集合类不安全
ArrayList
集合类不安全
- 故障现象
java.util.ConcurrentModificationException
- 导致原因 多线程对集合的并发操作导致并发修改异常的产生
- 解决方案
Vector(加synchronized)
Collections.synchronizedList(new ArrayList<>())
使用同步代码块CopyOnWriteArrayList
(写时复制ReentrantLock
)
- 优化建议
package com.zbiti.juc;
import lombok.extern.slf4j.Slf4j;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
//ArrayList集合类不安全
//故障现象 java.util.ConcurrentModificationException
//导致原因 多线程对集合的并发操作导致并发修改异常的产生
//解决方案 Vector(加synchronized)--->Collections.synchronizedList(new ArrayList<>())使用同步代码块--->CopyOnWriteArrayList(写时复制ReentrantLock)
//优化建议
@Slf4j
public class CopyOnWriteArrayListExample {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayListExample.testArrayList();
// CopyOnWriteArrayListExample.testVector();
// CopyOnWriteArrayListExample.testCollectionsSynchronizedList();
// CopyOnWriteArrayListExample.testCopyOnWriteArrayList();
TimeUnit.SECONDS.sleep(3);
}
static void testArrayList() {
List list = new ArrayList();
for (int i = 1; i <= 30; i ) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
static void testVector() {
List list = new Vector();
for (int i = 1; i <= 30; i ) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
static void testCollectionsSynchronizedList() {
List list = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <= 30; i ) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
static void testCopyOnWriteArrayList() {
List list = new CopyOnWriteArrayList();
for (int i = 1; i <= 30; i ) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
源码
Vector添加操作
使用了synchronized
,底层关键字,重量级锁,会阻塞其它线程
/**
* Appends the specified element to the end of this Vector.
*
* @param e element to be appended to this Vector
* @return {@code true} (as specified by {@link Collection#add})
* @since 1.2
*/
public synchronized boolean add(E e) {
modCount ;
ensureCapacityHelper(elementCount 1);
elementData[elementCount ] = e;
return true;
}
Collections.synchronizedList
添加操作
使用synchronized
同步代码块
public boolean add(E e) {
synchronized (mutex) {return c.add(e);}
}
CopyOnWriteArrayList
的添加操作
使用了ReentrantLock
锁,这是JavaAPI
层面的锁,属于轻量级的锁,会阻塞其它线程
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
ArrayList
剖析
底层数据结构
Object
类型的数组结构
数组的的默认值
既然底层数据结构是Object
类型的数组结构,那么数组是一段连续的内存空间
HashSet
剖析
底层数据结构
底层数据结构是HashMap
添加操作
HashSet
的添加操作使用的是HashMap
的put
操作,来保证数据的唯一性,因为HashMap
的键是不可重复的
举一反三
Collections
工具类
CopyOnWriteArrayList
写时复制
ConcurrentHashMap
底层并不是用写时复制的思想来控制多线程并发安全的,而是直接用Node
数组 链表 红黑树的数据结构来实现,并发控制使用Synchronized
和CAS
来操作,整个看起来就像是优化过且线程安全的HashMap
参考
探索 ConcurrentHashMap 高并发性的实现机制
本文由博客一文多发平台 OpenWrite 发布!