List 多线程问题
1
2
3
4
5
6
7
8
9
10
11
12
ArrayList<String> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
int finalI = i;
new Thread(() -> data.add(Thread.currentThread().getName() + finalI)).start();
}
for (int i = 0; i < 100; i++) {
new Thread(() -> {
for (String item : data) {
Log.e(Thread.currentThread().getName(), "item:"+item);
}
}).start();
}
上述代码目前已知会产生两个多线程问题
1. ArrayIndexOutOfBoundsException
1
2
java.lang.ArrayIndexOutOfBoundsException: length=33; index=33
at java.util.ArrayList.add(ArrayList.java:468)
查看 add 源码
1
2
3
4
5
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
假如同时多个线程执行到 ensureCapacityInternal(size + 1); 但是没有执行 elementData[size++] = e; 就会导致 size+1 这个数据并不是最终个数,导致上述问题。
解决方案
- 使用线程安全的 List
- 手动添加锁
2. ConcurrentModificationException
这是因为在遍历过程中有其他线程对数据进行了修改
解决方案
- 使用线程安全的 List
- 手动添加锁
ArrayList
1
2
3
4
5
6
7
java.util.ConcurrentModificationException
at java.util.AbstractList$SimpleListIterator.next(AbstractList.java:62)
at java.util.AbstractList$SubAbstractList$SubAbstractListIterator.next(AbstractList.java:201)
at java.util.AbstractList$SubAbstractList$SubAbstractListIterator.next(AbstractList.java:201)
at java.util.AbstractCollection.toArrayList(AbstractCollection.java:349)
at java.util.AbstractCollection.toArray(AbstractCollection.java:339)
at java.util.ArrayList.<init>(ArrayList.java:97)
Collections.synchronizedList 并不能解决 ConcurrentModificationException 问题
查看 Collections.synchronizedList 源码可知底层返回的是 SynchronizedCollection 持有传入的list,只不过在 add、remove、get 等基础操作加了一个锁,但是 iterator 方法没有加锁,而且官方注释了 Must be manually synched by user! 需要使用者自己加锁处理。
1
2
3
public Iterator<E> iterator() {
return c.iterator(); // Must be manually synched by user!
}
多线程读取同一个磁盘数据修改后复写到磁盘中。
在多线程场景下有可能