为什么我用两个线程操作一个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]
我给你的类稍微做了修改
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的情况,确保了同步。
唔,没看出来为什么……明明在修改了链表内容之后它的size才改变的,没看出来是在什么位置上的切换会出问题 T T
不过这个应用场景是很典型的生产者-消费者问题,在Java 5或以上可以用BlockingQueue接口嘛,要用链式容器的话可以用LinkedBlockingQueue。
把
[code="java"]
LinkedList items = new LinkedList();
[/code]
改成
[code="java"]
List items = java.util.Collections.synchronizedList(new LinkedList()) ;
[/code]
把
[code="java"]
items.removeFirst();
[/code]
改成
[code="java"]
return items.remove(0);
[/code]