/** * Creates a new {@code ReentrantReadWriteLock} with * default (nonfair) ordering properties. */ publicReentrantReadWriteLock(){ // 默认构造器使用的是非公平模式 this(false); }
/** * Creates a new {@code ReentrantReadWriteLock} with * the given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ publicReentrantReadWriteLock(boolean fair){ sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); // new时就已经实例化一个readerLock 对象和 writerLock 对象 writerLock = new WriteLock(this); }
/** * Constructor for use by subclasses * * @param lock the outer lock object * @throws NullPointerException if the lock is null */ // WriteLock的调用点是在ReentrantReadWriteLock的构造器中: /* public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } */ protectedWriteLock(ReentrantReadWriteLock lock){ sync = lock.sync; }
/** * Acquires the write lock. * * <p>Acquires the write lock if neither the read nor write lock * are held by another thread * and returns immediately, setting the write lock hold count to * one. * * <p>If the current thread already holds the write lock then the * hold count is incremented by one and the method returns * immediately. * * <p>If the lock is held by another thread then the current * thread becomes disabled for thread scheduling purposes and * lies dormant until the write lock has been acquired, at which * time the write lock hold count is set to one. */ // 从这里可以看出:类似的用户程序使用rwl.writeLock().lock()时,其实就是调用AQS的独占锁的获取锁逻辑:acquire(1),显然既然是独占锁,那么获取逻辑自然跟ReentrantLock的lock()是类似的,也即AQS的acquire方法. publicvoidlock(){ sync.acquire(1); } ...//WriteLock类其他省略部分
protectedfinalbooleantryAcquire(int acquires){ /* Walkthrough:攻略或玩法,也即tryAcquire的成功与否的策略 * 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); // 当前写锁计数(需要利用移位来计算出) // 由于同步状态可以表征读锁计数和写锁计数,因为当前线程想获取写锁,因此它需要判断:同步状态值不为0到底是指有其他线程获取到了写锁还是获取了读锁还是都被获取? if (c != 0) { // 1、c != 0且写锁计数为0,说明当前线程持有读锁,不允许请求写锁(否则就是持有读锁情况下拿到写锁,那么这个读锁就不是共享模式读锁,而是变相的独占锁,显然违背了ReentrantReadWriteLock的功能设计初衷);或者说“当前线程持有读锁且不释放读锁的情况下,不允许升级为写锁,否则读锁就变相的成为了独占锁” // 2、写锁计数不为了0,说明是当前线程正在重入独占锁,如果不是同一线程请求,写锁当然请求失败,返回false // (Note: if c != 0 and w == 0 then shared count != 0) if (w == 0 || current != getExclusiveOwnerThread()) returnfalse; // 3、是当前线程重入的写锁请求,但重入次数超过最大值,直接抛出异常提示 if (w + exclusiveCount(acquires) > MAX_COUNT) thrownew Error("Maximum lock count exceeded"); // Reentrant acquire // 4、说明是同一线程的写锁重入,累加计数后,允许通过请求锁。 setState(c + acquires); returntrue; } // 5、执行流来到这里说明c等于0,说明此刻暂时还没其他线程在竞争读、写锁,那么当前线程可以去CAS抢锁 /* writerShouldBlock() 是用于是否使用公平模式抢锁策略,对于写锁获取策略来说,显然是false,如下所示 static final class NonfairSync extends Sync { private static final long serialVersionUID = -8159625535654395037L; final boolean writerShouldBlock() { return false; // writers can always barge ,写锁获取只能直接争抢 } 因此这里的if第一个writerShouldBlock()返回false然后第二个条件就是去跟其他写线程CAS抢锁了,失败那么只能返回false */ if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) returnfalse; // 6、对于c != 0,说明此写线程重入成功,对于c=0,说明此线程是第一个获得独占锁的线程 setExclusiveOwnerThread(current); returntrue; }
/** * Attempts to release this lock. * * <p>If the current thread is the holder of this lock then * the hold count is decremented. If the hold count is now * zero then the lock is released. If the current thread is * not the holder of this lock then {@link * IllegalMonitorStateException} is thrown. * * @throws IllegalMonitorStateException if the current thread does not * hold this lock */ //按照注释提示: // 1、如果当前线程是重入的,那么每次unlock就是对重入次数减1,也即此线程内部写锁计数hold count 减1 (注意,如果hold count减1后不为0,此写线程是不会释放独占锁的) // 2、如果当前线程的不是重入,仅是获取独占锁一次,那么当它调用unlock时,显然state变为0,意味着是释放独占锁,其他线程可以争抢此独占锁了。 publicvoidunlock(){ sync.release(1); }
/* * 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. */ // 释放锁的逻辑 protectedfinalbooleantryRelease(int releases){ if (!isHeldExclusively()) thrownew IllegalMonitorStateException(); int nextc = getState() - releases; // 扣减释放量 boolean free = exclusiveCount(nextc) == 0; // 这里的free是指写锁释放完全释放,如果等于0,说写锁完全被释放。 // 如果为0,说明写锁完全被释放,其他线程(含读、写线程)可以争抢了 if (free) setExclusiveOwnerThread(null); // free不为0,说明是同一线程重入写锁后,现在是释放自己重入的写锁,也即“重入-退出”操作,将state设为扣减后的值 setState(nextc); return free; }
/** * The lock returned by method {@link ReentrantReadWriteLock#readLock}. */ publicstaticclassReadLockimplementsLock, java.io.Serializable{ privatestaticfinallong serialVersionUID = -5992448646407690164L; privatefinal Sync sync;
/** * Constructor for use by subclasses * * @param lock the outer lock object * @throws NullPointerException if the lock is null */ protectedReadLock(ReentrantReadWriteLock lock){ sync = lock.sync; }
/** * Acquires the read lock. * * <p>Acquires the read lock if the write lock is not held by * another thread and returns immediately. * * <p>If the write lock is held by another thread then * the current thread becomes disabled for thread scheduling * purposes and lies dormant until the read lock has been acquired. */ publicvoidlock(){ sync.acquireShared(1); // 具体获取读锁的逻辑在tryAcquireShared实现 } // 响应中断的获取读锁方式 publicvoidlockInterruptibly()throws InterruptedException { sync.acquireSharedInterruptibly(1); }
/** * Throws {@code UnsupportedOperationException} because * {@code ReadLocks} do not support conditions. * * @throws UnsupportedOperationException always */ public Condition newCondition(){ thrownew UnsupportedOperationException(); }
/** * Returns a string identifying this lock, as well as its lock state. * The state, in brackets, includes the String {@code "Read locks ="} * followed by the number of held read locks. * * @return a string identifying this lock, as well as its lock state */ public String toString(){ int r = sync.getReadLockCount(); returnsuper.toString() + "[Read locks = " + r + "]"; } }
/** * Acquires the read lock. * * <p>Acquires the read lock if the write lock is not held by * another thread and returns immediately. * * <p>If the write lock is held by another thread then * the current thread becomes disabled for thread scheduling * purposes and lies dormant until the read lock has been acquired. */ publicvoidlock(){ sync.acquireShared(1); }
acquireShared当然是AQS的模板方法:
1 2 3 4
publicfinalvoidacquireShared(int arg){ if (tryAcquireShared(arg) < 0) // 只要ReentrantReadWriteLock的tryAcquireShared获取读锁方法返回-1,就说明当前线程没能马上获得读锁,得去CLH排队等待 doAcquireShared(arg); }
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(); //1、 当前state存在写锁计数但不是当前线程持有,那么不容许获取读锁,因为两者被设计为是互斥的,换句话说:在有写锁存在的条件下,只能是已经持有写锁的当前线程才能获取当前读锁,当然这种情况被称为“锁降级”。想想为何? // 因为如果存在写锁的条件下但不是当前线程持有,还去允许当前线程获取读锁的话,这不就等价于将别人占有的写锁“抢了过来”,这显然是不符合ReentrantReadWriteLock的读写互斥设计的。 if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; //2、当前state拥有的读锁数量 int r = sharedCount(c); //3、如果此时读线程是非公平模式且读锁计数小于最大值且CAS更新读锁计数加1成功,那么就执行此if里面的条件 if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) { // 在state的高16位累加1,也即使得所有线程总的读锁计数加1,执行流来到这里,说明当前线程已经成功获得读锁,下面就是要完成当前线程持有读锁的计数管理相关逻辑。 //4、在2读取的r值如果为0,说明当前线程是第一个进来请求读锁的线程,记为firstReader if (r == 0) { firstReader = current; firstReaderHoldCount = 1; // 记录第一个读线程的重入数量,首次当然是1 // 5、 如果在第2点读取的读锁数量不为0且当前线程就是之前的第一个读线程,说明是重入,对第一个读线程的重入进行计数加1 } elseif (firstReader == current) { firstReaderHoldCount++; // 6、以下的读锁设计比较难理解,参考后面的内容分析。 } else { // 读取“全局缓存计数器”,注意到此“全局缓存计数器”只缓存“最新成功获取读锁的那个线程”:The hold count of the last thread to successfully acquire readLock,目的是This saves ThreadLocal lookup,避免回到ThreadLocalHoldCounter的readHolds去查找。 HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != getThreadId(current)) /* 6.1 情况1 如果此“全局缓存计数器”变量为空,说明在此刻之前没有“最新成功获取读锁的那个线程””出现,那么当前线程自然可以将自己设为“最新成功获取读锁的那个线程”这个角色 情况2 如果此“全局缓存计数器”变量不为空但已经缓存“最新成功获取读锁的那个线程”,而这个缓存线程又不是当前线程,说明当前线程从此刻起将成为“最新成功获取读锁的线程”角色。 针对情况1和情况2,既然当前线程在此刻已经成为“最新成功获取读锁的线程”角色,那么当前线程取出自己的计数器并放入“全局缓存计数器”:cachedHoldCounter = rh = readHolds.get()。这样就保证了cachedHoldCounter会一直指向“最新成功获取读锁的线程” */ cachedHoldCounter = rh = readHolds.get(); /*6.2 说明6.1两个条件都不成立,说明“全局缓存计数器”缓存的恰好是当前线程,如果缓存的读锁计数为0,那么说明这个线程是在上一刻释放了自己持有的最后一个读锁且将“全局缓存计数器”计数减至0(并且它会调用readHolds.remove()移除了rh计数器对象,这一操作可以发生在tryReleaseShared中),现在这一刻此线程又再次进来作为“最新成功获取读锁的线程”,而此刻当前线程自己readHolds并没有放置计时器,于是作为“最新成功获取读锁的线程”,当前线程再将计数器放入到自己的“ThreadLocalHoldCounter的readHolds中”。 */ elseif (rh.count == 0) readHolds.set(rh); // rh.count++; } return1; } return fullTryAcquireShared(current); }
// 也即每个线程,只要请求读锁成功,那么读锁总数对应加1(state的高16位加1) if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
其次,还需要记录每个线程自己请求读锁的数量(或者重入读锁的次数),也即“当前线程自己持有的读锁计数进行相关管理”。这里解释为何每个线程需要记录自己读锁的数量,这是因为ReentrantReadWriteLock设计的读锁是可重入的,那么每个线程管理自己的读锁数量后,可以方便进行且准确的加锁、释放锁操作(自己重入多少次,就需要释放多少次)以及是否需要进入排队操作。而compareAndSetState(c, c + SHARED_UNIT)是记录所有线程的总读锁数量的设计,显然无法实现“当前线程自己持有的读锁计数进行相关管理”的功能。
// 理解本节内容的前提是掌握ThreadLocal的底层设计原理及其源代码实现,否则无法掌握其设计内涵。 /** * A counter for per-thread read hold counts. * Maintained as a ThreadLocal; cached in cachedHoldCounter */ // 1、此辅助对象就是为了记录当前线程请求读锁的次数,目的是为了知道此线程第一有没有持有读锁,第二持有读锁情况下重入多少次。交由ThreadLocal来维护。 staticfinalclassHoldCounter{ int count = 0; // 记录当前线程的读锁请求次数 // Use id, not reference, to avoid garbage retention // 当前线程的内存地址ID号,用于一些特别场景例如下面的cachedHoldCounter // 使用线程ID号而不是对象可以有效优化GC finallong tid = getThreadId(Thread.currentThread()); } // 2、通过ThreadLocal维护HoldCounter的更新,实现每个线程能线程安全的方式去管理持有读锁的计数。 // 这里是设定HoldCounter的初始化值 staticfinalclassThreadLocalHoldCounter extendsThreadLocal<HoldCounter> { public HoldCounter initialValue(){ returnnew HoldCounter(); } }
/** * The number of reentrant read locks held by current thread. * Initialized only in constructor and readObject. * Removed whenever a thread's read hold count drops to 0. */ /* 3、当前线程持有读锁的重入次数,如果不为0,说明当前线程肯定持有读锁,需要注意它的灵活用法: 总体上一定要遵守“当前线程不再持有读锁时,当前线程的ThreadLocal对象一定不能还存放着HoldCounter对象,否则HoldCounter是强引用,会造成当前线程的ThreadLocal出现内存泄露的风险” 3.1 一旦当前线程释放自己持有的最后一个读锁,说明当前线程不再需要持有“读锁计时器”引用来给自己计算读锁数量,那么当前线程还需要做多一个操作: readHolds.remove(),保证当前线程不再引用此“ThreadLocal变量”的读锁计数器,从而避免当前线程的ThreadLocal内存泄露,对应的代码逻辑(此逻辑一般在释放锁的操作中实施): if (count <= 1) { readHolds.remove(); readHolds = new ThreadLocalHoldCounter() ,当然此初始化已经被上面initialValue取代了。 每个线程持有的readHolds初始值:count=0,tid=此线程内存地址ID 3.2 如果当前线程查询自己readHolds的rh.count=0,说明当前线程是第一次成功获取读锁,考虑当前线程以后可能有重入读锁,那么此时可以将自己“读锁计数器” rh放到readHolds里面,对应的代码逻辑(此逻辑一般在请求读锁的操作中实施): else if (rh.count == 0) readHolds.set(rh); */ privatetransient ThreadLocalHoldCounter readHolds;
/** * The hold count of the last thread to successfully acquire * readLock. This saves ThreadLocal lookup in the common case * where the next thread to release is the last one to * acquire. This is non-volatile since it is just used * as a heuristic, and would be great for threads to cache. * * <p>Can outlive the Thread for which it is caching the read * hold count, but avoids garbage retention by not retaining a * reference to the Thread. * * <p>Accessed via a benign data race; relies on the memory * model's final field and out-of-thin-air guarantees. */
// 注意此cachedHoldCounter从名字可以直到它是一个缓存的读锁计数器,那么它是缓存哪个线程的读锁计时器呢? // 缓存的是“最近(最新)获得读锁的那个线程的读锁计数器”,例如Thread-0、Thread-1、Thread-2三个线程并发竞争读锁,如果Thread-1是最后一个成功获取读锁的线程,那么cachedHoldCounter就会缓存Thread-1的读锁计数count=1和Thread-1对应的内存地址ID号。当然如果后面还有最新的来的Thread-xx,那么cachedHoldCounter就会马上更新缓存Thread-xx的信息。 /* 这个缓存cachedHoldCounter有何作用呢? (1)在前面ThreadLocalHoldCounter中,每个线程HoldCounter由ThreadLocal维护,如果此线程需要查询自己的读锁计数,需要使用ThreadLocal里面的get方法,而此get方法会调用ThreadLocal里面ThreadLocalMap的getEntry方法,了解ThreadLocal的底层设计都知道这一get操作还可能引起ThreadLocalMap的额外清理操作,这无疑降低查询效率,因此干脆设计用于“具有缓存功能、快速查询”的cachedHoldCounter,如果当前线程恰好就是设置cachedHoldCounter的线程,那么它直接在cachedHoldCounter就可以拿到自己的读锁数,完全不需要调用ThreadLocal里面get方法来查询(避免了在ThreadLocalMap内部的一系列操作)通过这种方式,当前线程在读锁重入时能提高加锁效率。 (2)当前如果读锁竞争激烈,那么假设线程加锁后缓存了Thread-1,在Thread-1释放锁前,又有其他线程Thread-2、Thread-3请求了读锁,那么cachedHoldCounter就会一直更新,这种情况导致Thread-1需要调用ThreadLocal查询自己的读锁计数。可以说Thread-1在请求读锁重入锁期间没有“享受到缓存带来的性能提升” 正如源码注释里面的说的:This is non-volatile since it is just used as a heuristic, and would be great for threads to cache. 因为这是被设计为一个试探性的缓存,因此不需要设为volatile类型,如果当前线程试探性去查询发现此缓存是自己加锁后设置的缓存,那么就可以提高此线程的本次加锁和释放读锁的性能,如果不是自己设置缓存,那就稍微牺牲一点性能ThreadLocal(在内部的ThreadLocalMap)去查询。 */ privatetransient HoldCounter cachedHoldCounter;
/** * firstReader is the first thread to have acquired the read lock. * firstReaderHoldCount is firstReader's hold count. * * <p>More precisely, firstReader is the unique thread that last * changed the shared count from 0 to 1, and has not released the * read lock since then; null if there is no such thread. * * <p>Cannot cause garbage retention unless the thread terminated * without relinquishing its read locks, since tryReleaseShared * sets it to null. * * <p>Accessed via a benign data race; relies on the memory * model's out-of-thin-air guarantees for references. * * <p>This allows tracking of read holds for uncontended read * locks to be very cheap. */ /* 以下两个成员也是为了提升读锁加速的性能。认真看其源码注释说:更准确地说,firstReader是指向一个线程———这个线程是让总读锁计数从0变为1的线程。注意需要用动态的思维看待这样的解释。简单来说就是第一个获得读锁的线程,firstReaderHoldCount显然就是第一个获得读锁线程的重入计数 那么在什么场景下firstReader和firstReaderHoldCount起到提升性能的作用呢? 对于这种有序获取读锁的场景,优化效果明显,例如, Thread-0加锁-释放锁后,接着Thread-1才开始请求读锁,Thread-1释放读锁,然后Thread-2才开始请求读锁.... 可以这么理解: 当Thraed-0作为第一个请求读锁的线程,它从加锁到释放锁的代码执行期间,此时Thread-1还没开始启动请求读锁。那么当Thread-0再次重入锁时(而且此刻还没其他线程来请求读锁),显然只需查询firstReaderHoldCount自己的读锁计数即可,无需进入自己的ThreadLocal里面去查询读锁计数,因为进入ThreadLocal去查询意味着要去ThreadLocalMap查询(get操作还可能引起清理stale entry)意味着降低查询效率。 这就是注释所说的:This allows tracking of read holds for uncontended read locks to be very cheap. 能够使用最小代价去追踪那种非竞争线程获取的读锁计数 uncontended read locks:一个线程拥有读锁的时候,没有其他线程企图获得读锁(也就是非并发竞争的) */ privatetransient Thread firstReader = null; privatetransientint firstReaderHoldCount;
/** * Nonfair version of Sync */ staticfinalclassNonfairSyncextendsSync{ privatestaticfinallong serialVersionUID = -8159625535654395037L; finalbooleanwriterShouldBlock(){ returnfalse; // writers can always barge } finalbooleanreaderShouldBlock(){ /* As a heuristic to avoid indefinite writer starvation, * block if the thread that momentarily appears to be head * of queue, if one exists, is a waiting writer. This is * only a probabilistic effect since a new reader will not * block if there is a waiting writer behind other enabled * readers that have not yet drained from the queue. */ return apparentlyFirstQueuedIsExclusive(); } }
/** * Returns {@code true} if the apparent first queued thread, if one * exists, is waiting in exclusive mode. If this method returns * {@code true}, and the current thread is attempting to acquire in * shared mode (that is, this method is invoked from {@link * #tryAcquireShared}) then it is guaranteed that the current thread * is not the first queued thread. Used only as a heuristic in * ReentrantReadWriteLock. */ finalbooleanapparentlyFirstQueuedIsExclusive(){ Node h, s; // 1、存在阻塞队列 // 2、阻塞队列至少有1个线程节点在排队 // 3、且第一个线程节点是独占模式节点 // 4、且第一个线程节点线程未取消 // 如果以上4个条件同时成立,那么就会返回true,也即readerShouldBlock返回true return (h = head) != null && (s = h.next) != null && !s.isShared() && s.thread != null; }
/** * Attempts to release this lock. * * <p>If the number of readers is now zero then the lock * is made available for write lock attempts. */ publicvoidunlock(){ sync.releaseShared(1); }
/** * Nonfair version of Sync */ staticfinalclassNonfairSyncextendsSync{ privatestaticfinallong serialVersionUID = -8159625535654395037L; finalbooleanwriterShouldBlock(){ returnfalse; // writers can always barge } finalbooleanreaderShouldBlock(){ /* As a heuristic to avoid indefinite writer starvation, * block if the thread that momentarily appears to be head * of queue, if one exists, is a waiting writer. This is * only a probabilistic effect since a new reader will not * block if there is a waiting writer behind other enabled * readers that have not yet drained from the queue. */ return apparentlyFirstQueuedIsExclusive(); } }
/** * Queries whether any threads have been waiting to acquire longer * than the current thread. * * <p>An invocation of this method is equivalent to (but may be * more efficient than): * <pre> {@code * getFirstQueuedThread() != Thread.currentThread() && * hasQueuedThreads()}</pre> * * <p>Note that because cancellations due to interrupts and * timeouts may occur at any time, a {@code true} return does not * guarantee that some other thread will acquire before the current * thread. Likewise, it is possible for another thread to win a * race to enqueue after this method has returned {@code false}, * due to the queue being empty. * * <p>This method is designed to be used by a fair synchronizer to * avoid <a href="AbstractQueuedSynchronizer#barging">barging</a>. * Such a synchronizer's {@link #tryAcquire} method should return * {@code false}, and its {@link #tryAcquireShared} method should * return a negative value, if this method returns {@code true} * (unless this is a reentrant acquire). For example, the {@code * tryAcquire} method for a fair, reentrant, exclusive mode * synchronizer might look like this: * * <pre> {@code // 这里给出当前线程请求独占锁前需要询问阻塞队列的是否有线程正在排队情况 * protected boolean tryAcquire(int arg) { * if (isHeldExclusively()) { * // A reentrant acquire; increment hold count * return true; * } else if (hasQueuedPredecessors()) { * return false; * } else { * // try to acquire normally * } * }}</pre> * * @return {@code true} if there is a queued thread preceding the * current thread, and {@code false} if the current thread * is at the head of the queue or the queue is empty * @since 1.7 */
// 1. 如果当前准备请求读写锁的线程调用hasQueuedPredecessors()返回false,说明当前线程要么已经在队列且作为第一个排队节点,要么就是没有CLH阻塞队列,也即没有其他线程在排队,这两种情况都可以说明当前线程不需要排队可以直接去竞争锁。 // 2. s = h.next且s.thread = Thread.currentThread(),就是说明CLH阻塞队列里面第一个排队线程就是当前线程本身。 publicfinalbooleanhasQueuedPredecessors(){ // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }