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写锁的获取lock()和释放unlock():array = new ArrayL st (); 独占锁 private final ReentrantReadWr teLock lock =口ew ReentrantReadWriteLock() ; private final Lock readLock = lock.readLock () ; private final Lock writeLock = lock . writeLock (); //添加元素 public void add (String e) { writeLock . lock (); try { array. add (e ) ; } finally { writeLock.unlock() ; //删除元素 public void remove (String e) { writeLock.lock () ; try { array . remove(e) ; } finally { writeLock. unlock() ; //获取数据 public Stri ng get (int index ) { readLock . lock() ; try { retur array get(index) } finally { readLock.unlock() ;
在修改、添加、删除时要首先获取写锁,如果现在又其他线程持有写锁会被阻塞;如果没有线程持有写锁,则获取写锁,state的低16位+1,并把当前持有锁的线程设置为本线程。释放写锁的时候state的低16位-1 读锁的获取和释放:
读取数据前先获取读锁,如果当前有其他线程持有写锁,就会被阻塞。否则直接获取读锁。可以允许多个线程同时持有读锁



