Java 聊聊集合类不安全及读写分离技术

Noella ·
更新时间:2024-09-20
· 802 次阅读

Collection 应该是大家在编程中使用的最多的,在单线程编程中一般不会出现问题,但是到了多线程的时代,可就不一定了。

List 示例代码 /** * 集合类不安全的问题 * ArrayList */ public class ContainerNotSafeDemo { public static void main(String[] args) { List list = new ArrayList(); //多线程同时访问 for (int i = 0; i { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }).start(); } } }

运行结果:并发修改异常

导致原因

并发争抢修改导致,多线程访问 List 导致数据冲突

解决方案 方案 1

不使用 ArrayList,换成 Vector

public class ContainerNotSafeDemo { public static void main(String[] args) { // 更换为 Vector List list = new Vector(); //多线程同时访问 for (int i = 0; i { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }).start(); } } }

虽然更换为 Vector 可以解决问题,但是 Vector 的源码是使用 synchronized 关键字解决问题的,所以并发量大大下降,不推荐使用。

方案 2

换成 Collections.synchronizedList(new ArrayList());

public class ContainerNotSafeDemo { public static void main(String[] args) { List list = Collections.synchronizedList(new ArrayList());; //多线程同时访问 for (int i = 0; i { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }).start(); } } }

Collections 工具类提供接口,可以将不安全的集合转换为安全的,其实用的技术就是 synchronized。

方案 3

使用 JUC 包下的 new CopyOnWriteArrayList();

public class ContainerNotSafeDemo { public static void main(String[] args) { List list = new CopyOnWriteArrayList(); //多线程同时访问 for (int i = 0; i { list.add(UUID.randomUUID().toString().substring(0, 8)); System.out.println(list); }).start(); } } } 写时复制

写时复制 copyOnWrite 容器即写时复制的容器 往容器添加元素的时候,不直接往当前容器object[]添加,而是先将当前容器object[]进行,copy 复制出一个新的 object[] newElements 然后向新容器 object[] newElements 里面添加元素添加元素后,再将原容器的引用指向新的容器 setArray(newElements);

这样的好处是可以对 copyOnWrite 容器进行并发的读,而不需要加锁因为当前容器不会添加任何容器。所以 copyOnwrite 容器也是一种读写分离的思想,读和写不同的容器。

Set、Map

Set 的底层使用的 HashMap,所以将上面 List 的代码部分换成 Set、Map,将会报同样错,可以使用上面的三种方法去解决这个问题,我就不在这里赘述。JUC 包中提供 CopyOnWriteHashSet 和 ConcurrentHashMap,使用方法类似。


作者:楚瑞涛



读写分离 JAVA

需要 登录 后方可回复, 如果你还没有账号请 注册新账号