集合类-线程安全问题
集合类不安全的问题
List<String> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
new Thread(()->{
//多个线程修改同一个资源list
list.add(UUID.randomUUID().toString());
System.out.println(list);
}).start();
}
出现 java.util.ConcurrentModificationException 并发修改异常
解决方案
- Vector 线程安全的, 加了重锁(不推荐)
- List
list = Collections.synchronizedList(new ArrayList<>()); // Collections工具类 - CopyOnWriteArrayList list = new CopyOnWriteArrayList(); // JUC (推荐)
CopyOnWriteArrayList为什么能解决线程安全问题
//array用volatile修饰保证可见性
private transient volatile Object[] array;
public boolean add(E e) {
// 加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//复制到一个新的数组,数组长度加1
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
//设置新的数组为当前集合
setArray(newElements);
return true;
} finally {
//释放锁
lock.unlock();
}
}
HashSet 线程不安全问题
- Set
set = Collections.synchronizedSet(new HashSet<>()); - CopyOnWriteArraySet set = new CopyOnWriteArraySet();
//内部构造的还是CopyOnWriteArrayList
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
HashSet 底层数据结构就是HashMap
public HashSet() {
map = new HashMap<>();
}
//key是值,value是Object对象常量
private static final Object PRESENT = new Object();
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
HashMap 线程安全问题 解决方案
Map<String, String> map = new ConcurrentHashMap();