SAN_YUN 2009-04-09 13:28
浏览 607
已采纳

多线程操作导致list报NoSuchElementException

为什么我用两个线程操作一个list,一个不断的删除,一个不断的添加。
会导致
Exception in thread "Thread-0" java.util.NoSuchElementException
at java.util.LinkedList.remove(LinkedList.java:788)
at java.util.LinkedList.removeFirst(LinkedList.java:134)
at SynlistTest.remove(SynlistTest.java:10)
at SynlistTest$1.run(SynlistTest.java:27)
at java.lang.Thread.run(Thread.java:619)
[code="java"]
public class SynlistTest {

LinkedList<String> items = new LinkedList<String>();

public String remove() {

    if (!items.isEmpty()) {
         return items.removeFirst();
     }
    return null;
}

public void add(String item) {

    items.add(item);
}


public void test() {

    Runnable thread1 = new Runnable() {

        public void run() {
            while (true) {
                remove();
            }
        }
    };

    Runnable thread2 = new Runnable() {

        public void run() {
            while (true) {
                add("sanyun");
            }
        }
    };

    new Thread(thread1).start();
    new Thread(thread2).start();
}

public static void main(String[] args) {

    new SynlistTest().test();
}

}
[/code]

  • 写回答

3条回答 默认 最新

  • liwenzhengloveliuli 2009-04-13 17:12
    关注

    我给你的类稍微做了修改
    public class SynlistTest {

    List items = Collections.synchronizedList(new LinkedList());
    // LinkedList items = new LinkedList();

     public String remove() {  
    
         if (!items.isEmpty()) {  
             //使用索引代替removefirst();
              return   items.remove(0); 
          }  
         return null;  
     } 
    

    主要的问题是LinkedList是非线程安全的,如果多个线程同时访问列表,而其中至少一个线程从结构上修改了该列表,则它必须 保持外部同步。我帮你修改了是基于LIST的,如果也可以使用下面的方式基于linklist的线程安全的访问。

    public class SynlistTest {

     LinkedList<String> items = new LinkedList<String>(); 
    
     String flag="110";
     public  String remove() {  
         synchronized(flag){
         if (!items.isEmpty()) {  
             System.out.println("remove.......");
              return items.removeFirst();  
          }  
         return null;  
     }  }
    
     public void add(String item) {  
         synchronized(flag){
             System.out.println("add.......");
         items.add(item);  
         }
     } 
    

    两个线程共享这个判断标志flag,当第一个线程执行add操作的时候将flag的标志位修改此时如果第二个线程来访问标志位,发现不对正在被使用 就不会执行操作。所以就不会出现同时add和move的情况,确保了同步。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?