// tryAcquireShared是Sync中的方法 protectedfinalinttryAcquireShared(int unused){ /* * Walkthrough: * 1. If write lock held by another thread, fail. * 2. Otherwise, this thread is eligible for * lock wrt state, so ask if it should block * because of queue policy. If not, try * to grant by CASing state and updating count. * Note that step does not check for reentrant * acquires, which is postponed to full version * to avoid having to check hold count in * the more typical non-reentrant case. * 3. If step 2 fails either because thread * apparently not eligible or CAS fails or count * saturated, chain to version with full retry loop. */ Thread current = Thread.currentThread(); int c = getState(); // 如果写锁线程数 != 0 ,且独占锁不是当前线程则返回失败(如果持有写锁的是当前线程,是可以继续获取读锁的) if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; // 总的读锁数量 int r = sharedCount(c); /* * readerShouldBlock():读锁是否需要等待(公平锁原则) * r < MAX_COUNT:总的读锁数量小于最大数(65535),防止溢出 * compareAndSetState(c, c + SHARED_UNIT):设置总的读锁数量+1 */ if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { // 总的读锁数量+1
protectedfinalbooleantryAcquire(int acquires){ /* * Walkthrough: * 1. If read count nonzero or write count nonzero * and owner is a different thread, fail. * 2. If count would saturate, fail. (This can only * happen if count is already nonzero.) * 3. Otherwise, this thread is eligible for lock if * it is either a reentrant acquire or * queue policy allows it. If so, update state * and set owner. */ Thread current = Thread.currentThread(); int c = getState(); int w = exclusiveCount(c); // 获取独占锁的重入数 // 当前同步状态state != 0,说明已经有其他线程获取了读锁或写锁 if (c != 0) { // (Note: if c != 0 and w == 0 then shared count != 0) if (w == 0 || current != getExclusiveOwnerThread()) // 1.如果没有线程持有写锁,但又线程持有读锁,那获取写锁失败,需要等读锁释放 // 2.如果有线程持有写锁,但持有写锁的线程不是自己,需要等写锁释放 returnfalse; if (w + exclusiveCount(acquires) > MAX_COUNT) thrownew Error("Maximum lock count exceeded"); // Reentrant acquire // 设置独占锁重入次数+1,因为这里acquires=1 setState(c + acquires); returntrue; } // 判断写锁是否应该阻塞 // CAS设置独占锁重入次数+1 if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) returnfalse; // 到这里说明CAS成功,将设置持有写锁的线程为当前线程 setExclusiveOwnerThread(current); returntrue; // 返回获取成功 }
writerShouldBlock方法
非公平锁实现
非公平锁不需要判断是否有人排队之类的,这里返回不需要阻塞,直接CAS尝试获取独占锁
1 2 3
finalbooleanwriterShouldBlock(){ returnfalse; // writers can always barge }
publicvoidunlock(){ sync.release(1); } // 父类AQS中的方法,释放成功锁后,如果当前节点的waitStatus != 0,则需要唤醒后继节点,忘了的话复习下AQS吧 publicfinalbooleanrelease(int arg){ if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); returntrue; } returnfalse; }
tryRelease方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/* * Note that tryRelease and tryAcquire can be called by * Conditions. So it is possible that their arguments contain * both read and write holds that are all released during a * condition wait and re-established in tryAcquire. */ // tryRelease是Sync中的方法 // 因为写锁是独占锁,具有排他性,直接state减1就是了 protectedfinalbooleantryRelease(int releases){ if (!isHeldExclusively()) thrownew IllegalMonitorStateException(); int nextc = getState() - releases; // state-1 boolean free = exclusiveCount(nextc) == 0; if (free) // 如果写锁持有的数量为0,则将当前持有写锁的线程设置为null setExclusiveOwnerThread(null); setState(nextc); return free; }
Thread current = Thread.currentThread(); int c = getState(); int w = exclusiveCount(c); if (c != 0) { if (w == 0 || current != getExclusiveOwnerThread()) // 1.如果没有线程持有写锁,但又线程持有读锁,那获取写锁失败,需要等读锁释放 // 2.如果有线程持有写锁,但持有写锁的线程不是自己,需要等写锁释放 returnfalse; ... } ... }
假设线程 A 先获取了读锁,然后获取写锁,那么上面的方法会返回false,线程A就到阻塞队列休眠了,自己把自己弄休眠了,而且可能之后就没人去唤醒它了。