CopyOnWriteArrayList是并发安全的ArrayList,采用写时复制的策略Object[]属性用来存放数组的元素ReentrantLock属性是一个独占锁,为了保证同时只能有一个线程操作数组,实现并发安全1、add(E e)方法 2、get(int index)方法 先获取数组通过下标访问数组元素
整个过程没有上锁,从而导致的问题?——数据的弱一致问题假设线程A在获取数组元素的过程中,另外一个线程B删除了这个元素,因为删除时时用写时复制的策略(先复制,再删除,再替换),导致A线程读取到的是B线程删除前的原数组的数据。3、remove(int index)方法
其实和新增元素的代码类似,首先获取独占锁以保证删除数据期间其他线程不能对 array 进行修改,然后获取数组中要被删除的元素,并把剩余的元素复制到新数组,之后使用新数组替换原来的数组,最后在返回前释放锁。 2、读写锁ReentrantReadWriteLock
解决线程安全 题使用 ReentrantLock 就可以 , 但是 Ree ntrantLock 是独占锁 某时只个线程可以获取该锁,而实际中会有写少读多的场景,显然 ee ntrantLock 满足不了这个需求,所以 Ree ntrantR ea dWrit eLock 应运而生 ReentrantReadWriteLock 采用 读写分 离的策略,允许多个线程可以同时获取读锁。 内部维护了读锁ReadLock()和写锁WriteLock()两个方法读写锁本质上也是通过AQS原理实现的,32位的state变量的低16位表示写锁的重入次数,高16位表示读锁的重入次数。
private ArrayList
在修改、添加、删除时要首先获取写锁,如果现在又其他线程持有写锁会被阻塞;如果没有线程持有写锁,则获取写锁,state的低16位+1,并把当前持有锁的线程设置为本线程。释放写锁的时候state的低16位-1读锁的获取和释放:
读取数据前先获取读锁,如果当前有其他线程持有写锁,就会被阻塞。否则直接获取读锁。可以允许多个线程同时持有读锁