从list安全到vector到CopyOnWriteArrayList再到ReentrantReadWriteLock

list的add, get操作都不加锁,多线程不安全

二。.vetor,
----》读写都加sync重量级锁–>保证了安全 和 强的实时一致性
但是结果:读锁 只能1个线程 同时读,不可写。写锁,只能一个线程写,同时不可读。
一句话读写都是只能支持一个线程访问当然也就安全却性能差了

三。.CopyOnWriteArrayList
为vetor后juc的改良,其思想是 读写分离模式(但是缺点很明显后面讲)
CopyOnWrite容器即写时复制的容器。
通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。

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

2.缺点:
即内存占用问题和数据一致性问题,具体如下:
1)内存占用问题:
因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存)。如果这些对象占用的内存比较大,比如说200M左右,那么再写入100M数据进去,内存就会占用300M,那么这个时候很有可能造成频繁的Yong GC和Full GC。之前我们系统中使用了一个服务由于每晚使用CopyOnWrite机制更新大对象,造成了每晚15秒的Full GC,应用响应时间也随之变长。
2)数据一致性问题
读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。
 CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
 所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

四。ReentrantReadWriteLock
1.0 可调用读锁的lock(),unlock()方法;
2.0 也可调用写锁的lock(),unlock()方法。
结果分析:读锁 可有多个线程 同时读,但不可写。写锁,只能一个线程写,同时不可读
支持多个线程同时读(此时不能写因为读也是有锁?但是它还能实现多个读线程同时访问?这就是他厉害的地方,原理下面介绍)相对用CopyOnWrite他是可以保证数据的实时一致性的

可以实现多个读线程(枷锁)同时读的原理:
  ReentrantReadWriteLock 也是基于AQS实现的,它的自定义同步器(继承AQS)需要在同步状态(一个整型变量state)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁将变量切分成了两个部分,高16位表示读,低16位表示写。
ReentrantReadWriteLock含有两把锁readerLock和writerLock,其中ReadLock和WriteLock都是内部类。
在这里插入图片描述

发布了29 篇原创文章 · 获赞 0 · 访问量 398

猜你喜欢

转载自blog.csdn.net/qq_39965727/article/details/103781175