ReentrantReadWriteLock源码分析
代码在后面
读锁 = 共享锁
读锁写锁,公用一个Sync AQS state。
写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁,别人也不会进来获取锁。
写锁的获取跟ReentarntLock一样,每次加1,是一个独占锁,只要有人获取了锁,自己就去排队,排队时候节点是EXCLUSIVE的节点,入队方法acquireQueued和ReentarntLock一样,会设置OwnerThread。
读锁先获取锁,后面有读锁进来,多个读线程共存时候,第一个读线程设置firstReader,其余读线程设置threadLocals属性,然后获取锁,读锁每次增加65536,
写锁再进来,就去排队。
读锁再又进来,读锁还是去排队,
读锁不会设置OwnerThread,只是会state增加65536,写锁会忽略大于65536的部分。
state!=0,state去掉前16位=0,说明有读锁进去,写锁不进去。
State高位存储读锁获取次数,低位存储写锁获取次数。
设置threadLocals属性的读线程unlock时候清除threadLocalMap的标记,设置firstReader的读线程unlock时候设置firstReader=null,并且state减65536,
//读锁进来,首先判断state后16位,有写锁就去排队,没有写锁就设置firstReader或者firstReaderHoldCount++或者当前线程的threadLocals并且state增加65536
//写锁进来时候,首先判断state,有读锁写锁就去排队,
1.读锁进来,不看owenerThread,看的是state,去掉前面16位=0,说明没有写线程获取锁,就设置firstReader或者threadLocalMap,state增加65536。state去掉前面16位!=0说明有写线程获得了锁,就去排队。如果队列第一个是写线程,就去排队。 如果后面还有读线程进来,照样。
2.写锁进来,state!=0,state去掉前面16位=0,说明state已经加了几个65536了,说明有线程在读,写锁要去排队。state=0说明没有写线程获取锁,没有读线程在读,就去获取锁。state!=0,state去掉前面16位!=0,说明state有写线程获取锁,就去排队。
读锁每次加65536,不设置owenerThread。写锁每次加1,设置owenerThread。
读:去掉前面16!=0就去排队,队列空设置firstReader或者threadLocalMap,第一个节点是写线程排队,第一个节点是读线程设置firstReader或者threadLocalMap。
写:state!=0,去掉前面16位=0去排队,state=0获取锁。
if (exclusiveCount(c) != 0 /*去掉前面16位,*/ && getExclusiveOwnerThread() != current)
获取读锁时候,去掉前面16位!=0,OwnerThread() = current,说明里面有写锁了,并且是自己。说明一个线程先获取写锁在获取读锁,那么这个线程占据了owenerThread和firstReader或者threadLocalMap。
public class ReadWriteLockTest<E> { private final Map<String, String> map = new TreeMap<>(); private final ReentrantReadWriteLock1 lock = new ReentrantReadWriteLock1(); //写的时候,不能读不能写。 读的时候,不能写可以读。 //读线程获取锁,其他读线程可以获取锁,写线程不能获取锁 //写线程获取锁,读线程写线程不能获取锁 private final ReentrantReadWriteLock1.ReadLock readLock = lock.readLock(); private final ReentrantReadWriteLock1.WriteLock writeLock = lock.writeLock(); public ReadWriteLockTest() { } public String write(String key, String value) throws InterruptedException { writeLock.lock();//写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁别人也不会进来获取锁。 readLock.lock(); // writeLock.lockInterruptibly(); // writeLock.tryLock(); try { return map.put(key, value); } finally { writeLock.unlock();//写锁释放,就唤醒AQS } } public String read(String key) throws InterruptedException { readLock.lock();//获取的是共享锁 // writeLock.lock(); // readLock.lockInterruptibly(); // readLock.tryLock(); try { return map.get(key); } finally { readLock.unlock();//读锁全部释放完了,才会去唤醒AQS } } private static ReadWriteLockTest<Integer> tt = new ReadWriteLockTest<Integer>(); public static void main(String[] args) { new Thread(() -> { int i = 0; while (true) { Write w = new Write("写--" + (i++)); w.start(); } }).start(); new Thread(() -> { int j = 0; while (true) { Read s1 = new Read("读--" + (j++)); s1.start(); // Read s2 = new Read("读--" + (j++)); // s2.start(); // Read s3 = new Read("读--" + (j++)); // s3.start(); // s1.interrupt(); // s2.interrupt(); // s3.interrupt(); } }).start(); } static int i =0;static int j = 0; static class Write extends Thread { Write(String name) { super(name); } @Override public void run() { try { tt.write((i++)+"",(j++)+""); } catch (InterruptedException e) { e.printStackTrace(); } } } static class Read extends Thread { Read(String name) { super(name); } @Override public void run() { try { tt.read((i--)+""); } catch (InterruptedException e) { e.printStackTrace(); } } } }