http://xxgblog.com/2016/04/02/traverse-list-thread-safe/
http://www.2cto.com/kf/201403/286536.html
线程安全的Vector其实线程也不安全。使用CopyOnWriteArrayList可以线程安全地遍历。
为什么线程安全的Vector也不能线程安全地遍历呢?其实道理也很简单,看Vector源码可以发现它的很多方法都加上了synchronized来进行线程同步,例如add()、remove()、set()、get(),但是Vector内部的synchronized方法无法控制到遍历操作,所以即使是线程安全的Vector也无法做到线程安全地遍历。
如果想要线程安全地遍历Vector,需要我们去手动在遍历时给Vector加上synchronized锁,防止遍历的同时进行remove操作。
CopyOnWrite的意思是在写时拷贝,也就是如果需要对CopyOnWriteArrayList的内容进行改变,首先会拷贝一份新的List并且在新的List上进行修改,最后将原List的引用指向新的List。
使用CopyOnWriteArrayList可以线程安全地遍历,因为如果另外一个线程在遍历的时候修改List的话,实际上会拷贝出一个新的List上修改,而不影响当前正在被遍历的List。
package t;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
///http://www.2cto.com/kf/201403/286536.html
public class ConcurrentModificationException {
/**
* @param args
*/
public static void main(String[] args) {
final List<String> myList = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 100; i++) {
myList.add( "obj "+i);
}
new Thread(new Runnable() {
@Override
public void run() {
for (int i=100;i<200;i++) {
synchronized(myList){
myList.add( "obj add "+i);
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (String string : myList) {
System.out.println("遍历集合 value = " + string);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < myList.size(); i++) {
String value = myList.get(i);
System.out.println("删除元素 value = " + value);
if (value.equals( "3")) {
myList.remove(value);
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}