一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
1.5 集合中的线程不安全
1.5.1 什么叫做集合的线程不安全
问题根由:读和写操作同步执行
多个线程同时对同一个线程不安全的集合进行读和写操作导致出现ConcurrentModificationException
异常
1.5.2 如何解决ArrayList的线程不安全问题
不直接使用ArrayList而是使用一些代替类
-
Vector:
Vector
替代ArrayList
不使用
ArrayList
,而是使用Vector
。其实现的add
方法是加了synchronized
关键字List<String> list = new Vector<>();
-
Collections工具类:使用
Collections.synchronizedList(new ArrayList())
List<String> list= Collections.synchronizedList(new ArrayList<>());
-
CopyOnWriteArrayList:使用JUC中的
CopyOnWriteArrayList()
List<String> list=new CopyOnWriteArrayList<>();
写时复制技术:并发读,写入并不直接写入list,而是写入一个copyList然后将copyList覆盖原本的list
进行add操作的时候
- 将原本的list复制出来一份copyList
- 在复制中的copyList进行写
- 写完之后与原本的那个list进行覆盖
1.5.2 HashSet的线程不安全问题
问题原因与ArrayList一致
CopyOnWriteArraySet:与CopyOnWriteArrayList解决方案一致
1.5.3 HashMap线程不安全
与ArrayList的原因是一致的
解决:
ConcurrentHashMap:在进行元素添加的时候增加了synchronized
关键字
1.6 Callable接口
创建线程的一种方式
优点:可以在线程结束之后获取到返回值
Runnable接口和Callable接口区别
- 后者有返回值
- 如果出现异常会抛出
创建Callable的线程实现
使用FutureTask
未来任务(就是可以支持另一个线程执行完成之后应该怎么做,比如下单,我需要扣完库存、扣完款才能给这个人发货。这个时候需要等待“扣库存”和“扣款”结束之后“发货”)
1.7 辅助类
countdownLatch计数器
直到所有线程运行一定次数才执行await里面的方法
- 使用
- 每个线程调用countDown使计数器-1
- 调用await方法,使值减到0的时候执行其中的代码
cyclicBarrier循环栅栏
让所有线程都等待,直到所有线程都达到一个固定的点才执行barrierAction方法
相当于多段操作,每段操作使用await()方法阻塞等待在那。比如部队里士兵训练。当所有士兵都跑完步才开始去往食堂,当所有士兵都打完饭才开始吃饭,当所有士兵都吃完饭才去洗澡
需要注意的是,协调好ThreadSize、PartiesSize、TaskSize之间的关系,不然就会导致永远等待
semaphore信号灯
多个资源被相互竞争,只有一个线程释放占用的资源,才能会有一个线程能占用这个资源
汽车抢占车位