问题再现:并发下对ArrayList进行add和遍历输出,出现java.util.ConcurrentModificationException异常
public class ListTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
原因:ArrayList在并发下线程不安全
解决方式一:
使用Vector创建list
List list = new Vector();
public class ListTest {
public static void main(String[] args) {
List<String> list = new Vector<String>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
说明:
查看Vector源码,发现Vector的方法基本上都被synchronized修饰,如图:
Vector的add方法
ArrayList的add方法
解决方式二:
使用Collections.synchronizedList()
List list = Collections.synchronizedList(new ArrayList());
public class ListTest {
public static void main(String[] args) {
List<String> list = Collections.synchronizedList(new ArrayList<String>());
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
说明:
查看Collections.synchronizedList()方法源码,发现synchronizedList()返回SynchronizedList<>(list)
解决方式三:
使用CopyOnWriteArrayList创建list
List list = new CopyOnWriteArrayList();
public class ListTest {
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<String>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(list);
},String.valueOf(i)).start();
}
}
}
说明:
查看CopyOnWriteArrayList的源码,它ReentrantLock锁住,底层的array被transient volatile修饰
其中的add方法,代码被ReentrantLock锁住,从而保证线程安全。
CopyOnWriteArrayList相对于Vector优点在于lock比synchronized的优势
https://blog.csdn.net/qq_43576814/article/details/119685810?spm=1001.2014.3001.5501
以及CopyOnWrite写入时复制,见上图CopyOnWriteArrayList的add方法