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

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

List

示例代码

/**
 * 集合类不安全的问题 
 * ArrayList
 */
public class ContainerNotSafeDemo {
	public static void main(String[] args) {
		List<String> list = new ArrayList<>();
		
		//多线程同时访问
		for (int i = 0; i < 30; i++) {
			new Thread(()->{
				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<String> list = new Vector<>();
		
		//多线程同时访问
		for (int i = 0; i < 30; i++) {
			new Thread(()->{
				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<String> list = Collections.synchronizedList(new ArrayList<>());;
		
		//多线程同时访问
		for (int i = 0; i < 30; i++) {
			new Thread(()->{
				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<String> list = new CopyOnWriteArrayList<>();
		
		//多线程同时访问
		for (int i = 0; i < 30; i++) {
			new Thread(()->{
				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,使用方法类似。

发布了42 篇原创文章 · 获赞 22 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/cong____cong/article/details/104393758