java的各种集合为什么不安全(List、Set、Map)?
我们已经知道多线程下会有各种不安全的问题 , 都知道并发的基本解决方案 , 这里对出现错误的情况进行一个实际模拟 , 因此能够联想到具体的生产环境中 。
1|0一、List 的不安全1|11.1 问题看一段代码:
public static void main(String[] args) {ArrayList list = new ArrayList<>();for (int i = 0; i < 3; i++){new Thread(()->{list.add(UUID.randomUUID().toString().substring(0,8));System.out.println(list);},String.valueOf(i)).start();}}
过程很简单 , 只有 3 个线程而已 , 对同一个 list 进行 add 的写操作 , 并随后进行输出的读操作 。
输出结果 , 多执行几次 , 惊喜多多 。
文章插图
那么 , 情况不严重的时候 , 这里显然还正常运行结束了 , 只是导致了还没来得及写的时候 , 就已经读出了数据 。
如果把线程数增加试试 , 可能还会看到这样的奇观:
文章插图
报错了:重点异常:java.util.ConcurrentModificationException , 翻译过来就是并发修改异常 。
1|21.2 产生原因普通的 ArrayList 集合里面没有任何特殊处理 , 在多线程情况下 , 他们可以共同进行访问 。
那么在多线程同时操作的时候 , 按照操作的情况就有这几种:
- 各个线程都读 。 不影响 , 前提是只有读;
- 各个线程都写 。 会出现问题 , 这里的点有两种情况:值覆盖问题 , 因为 ArrayList 的底层数组 , 写入值的时候要先计算到一个下标位置 , 然后给对应的位置去赋值 , 多线程就会出现值覆盖的问题;空指针异常 , 因为 ArrayList 的底层数组 , 写入值在数组满的时候需要扩容 , 在扩容还没完成的时候 , 新的下标却已经计算出来并且要去插入 , 那么就会出现空指针异常 。
- 有的读有的写 。 那么显然对于多个线程来说 , 2 里面各个线程写的情况对应的问题就会出现 。 除此之外:如果多线程有的读有的写 , 对于 ArrayList 底层 , 某些情况下 , 对象是不允许进行修改的 , 如果修改了 , 后面调用某些方法时 , 就会检测到 , 然后就直接抛出ConcurrentModificationException 。 具体一下 , 因为源码里 , 写操作对集合修改是写 , 而next、remove等 Itr 的遍历读操作的时候会通过当前集合的修改次数与 Itr 对象创建时记录的次数校验集合是否被修改 , 如果修改了 , 不一致就说明正读的时候还有别的线程在改 , 就会抛出异常 。 JDK作者说了 , 会抛这个异常的都叫fail-fast iterator 。
1|31.3 解决方法注意:当然不能自己加锁 , 因为集合类已经在演变过程有线程安全的替代品 , 自己的代码加锁的粒度已经在集合的外层再加一层了 , 粒度太大 。
- 同样能够完成 ArrayList 功能的 , 可以使用 Vector , 查看源码就会发现 , Vector 的基本结构是一个叫 elementData 的 Object 类型的数组 , 和 ArrayList 类似 , 但是对应的操作方法 , 基本都加上了 synchronized 关键字 , 因此它是线程安全的集合 。
- 数据量小的时候 , 使用 Collections.synchronizedList(new ArrayList())这种方式 , 来包裹这个集合 , 跟 Collections 里面 synchronizedMap包裹hashmap 是一样的 , 更多的 , 还有:
文章插图
显然能传入参数的这些基本集合类都是线程不安全的 。
- 第三种就是 , 直接使用 juc 包里面的 , CopyOnWriteArrayList() 类 , 这个类就是并发包给我们提供的线程安全的列表类 。 1.4里介绍了这个集合 。
首先 , 按照前面的我们的分析 , 只要涉及了写的操作 , 和读或者写搭配的多线程情况 , 就会出现问题 , 那么多线程同时读却不会出现问题 , 因此相比较于直接都加上 synchronized 的方式 , 他的思想就是:读写分离 。 这个思想在数据库对于高并发的架构层面也有一样的设计 。
这样一来 , 对于这个 List 集合来说 , 分为不同操作的保证线程安全的策略 , 就能够保证更好的性能 。
写的方法 , 我们首先可以看 add 方法源码:
文章插图
- 小米科技|性价比拉满!TCL T8E-PRO QLED智屏当属潮玩世代的必备单品
- 华为鸿蒙系统|华为汽车战略布局,进入汽车行业的底气来自哪里?(车车佳)
- 浙江省|浙江的五大富豪,四位做过中国首富,仅马云的阿里就1年纳税366亿
- iOS|恒创科技:Linux日本云服务器安全设置的基本步骤
- javascript|手机移动端的PyTorch来了,还支持JavaScript
- 中关村|柳传志在这里被骗、掘金,书写半部科技史的中关村经历了什么?
- 手机维修|手机维修的猫腻‖你是不是上当了?
- 智能化|感知局限下,车路协同的“子弹”还得再飞会儿
- 华为鸿蒙系统|都2021年底了,为何Mate40Pro还是目前公认最好用的“安卓”手机
- saas|上半年的Redmi K40 Pro,现在入手2500元不到,还等?