Version: Next
集合的线程安全性
List——CopyOnWriteArrayList
默认线程不安全
public class Demo01List {
public static void main(String[] args) {
List<String> list = Arrays.asList("1", "2", "3");
list.forEach(System.out::println);
}
}
1
2
3
写一个多线程的例子
public class Demo01List {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 1; i < 200; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + " | " + list);
}, "Thread" + i).start();
}
}
}
会出现报错ConcurrentModificationException
——并发修改异常
Exception in thread "Thread190" Exception in thread "Thread184" java.util.ConcurrentModificationException
解决方案
使用
Vector
,默认线程安全,基于synchronized实现,但是这东西效率不行,没人用
Vector
出现在JDK1.0ArrayList
出现在JDK1.2使用
Collections
工具类,Collections.synchronizedXXX
集合使用JUC的
CopyOnWriteArrayList
,基于Lock锁实现(1.8)、JDK11里又弄成synchronized实现了
- 底层使用了
transient
和volatile
- 写入时复制、COW(Copy On Write),一种效率优化策略 (引出新知识点,读写分离,Mycat等)
- 读取,是固定的
- 写入,可能发生后写的把前面的东西覆盖了,解决方法:
- 复制一份,让调用者写,写好了再放回去
- 关键源码
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();}}
- 使用Collections工具类,实现线程安全
@Test
public void Test2() {
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i < 200; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + " | " + list);
}, "Thread" + i).start();
}
}
- 使用CopyOnWriteArrayList
@Test
public void Test3() {
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i < 200; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + " | " + list);
}, "Thread" + i).start();
}
}
为什么用CopyOnWriteArrayList,而不用Vectoc?
- Vector基于synchronized;CopyOnWriteArrayList基于Lock锁
Set——CopyOnWriteSet
- HashSet
@Test
public void Test1() {
Set<String> set = new HashSet<>();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + set);
}, "Thread" + i).start();
}
}
报错
- Collections.synchronizedSet
@Test
public void Test2() {
Set<String> set = Collections.synchronizedSet(new HashSet<>());
for (int i = 0; i < 200; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + set);
}, "Thread" + i).start();
}
}
- CopyOnWriteSet
@Test
public void Test3() {
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 200; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(Thread.currentThread().getName() + set);
}, "Thread" + i).start();
}
}
Map——ConcurrentHashMap
- HashMap
@Test
public void test1() {
Map<String, String> map = new HashMap();
for (int i = 0; i < 150; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(),
UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, "Thread" + i).start();
}
}
- Collections.synchronizedMap
@Test
public void test2() {
Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
for (int i = 0; i < 150; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, "Thread" + i).start();
}
}
- ConcurrentHashMap
@Test
public void test3() {
Map<String, String> map = new ConcurrentHashMap<>();
for (int i = 0; i < 150; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, "Thread" + i).start();
}
}
实现原理——分段锁