// first look at the constructor public SynchronousQueue() { this(false); } //Fair mode or unfair mode public SynchronousQueue(boolean fair) { transferer = fair ? new TransferQueue() : new TransferStack(); } //All production and consumption go to this method Object transfer(Object e, boolean timed, long nanos) { SNode s = null; // constructed/reused as needed //e==null is the consumer, otherwise it is the producer. int mode = (e == null) ? REQUEST : DATA; for (;;) { SNode h = head; //If the header is empty or has the same pattern there are no other threads if (h == null || h.mode == mode) { //Indicate that you can't wait if (timed && nanos <= 0) { // Judge again whether there is a head if (h != null && h.isCancelled()) casHead(h, h.next); // pop cancelled node else return null; //If you can wait, CAS sets the current node to head. } else if (casHead(h, s = snode(s, e, h, mode))) { // keep spinning and wait until match SNode m = awaitFulfill(s, timed, nanos); if (m == s) { // wait was cancelled clean(s); return null; } if ((h = head) != null && h.next == s) casHead(h, s.next); // help s's fulfiller return (mode == REQUEST) ? m.item : s.item; } } else if (!isFulfilling(h.mode)) { // try to fulfill if (h.isCancelled()) // already cancelled casHead(h, h.next); // pop and retry else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) { for (;;) { // loop until matched or waiters disappear SNode m = s.next; // m is s's match if (m == null) { // all waiters are gone casHead(s, null); // pop fulfill node s = null; // use new node next time break; // restart main loop } SNode mn = m.next; // try to match if (m.tryMatch(s)) { casHead(s, mn); // pop both s and m return (mode == REQUEST) ? m.item : s.item; } else // lost match s.casNext(m, mn); // help unlink } } } else { // help a fulfiller SNode m = h.next; // m is h's match if (m == null) // waiter is gone casHead(h, null); // pop fulfilling node else { SNode mn = m.next; if (m.tryMatch(h)) // help match casHead(h, mn); // pop both h and m else // lost match h.casNext(m, mn); // help unlink } } } } boolean casHead(SNode h, SNode nh) { return h == head && UNSAFE.compareAndSwapObject(this, headOffset, h, nh); } SNode awaitFulfill(SNode s, boolean timed, long nanos) { // blocking version timed is false so here is 0 long lastTime = timed? System.nanoTime (): 0; Thread w = Thread.currentThread(); SNode h = head; //Whether it needs to be rotated. If the spin is required, judge how many times to spin according to timed. // Here's a question why you want to spin without directly suspending. I think it's because of efficiency issues. //Spin waiting can reduce thread scheduling. int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0); for (;;) { if (w.isInterrupted()) s.tryCancel (); SNode m = s.match; if (m != null) return m; if (timed) { long now = System.nanoTime(); nanos -= now - lastTime; lastTime = now; if (nanos <= 0) { s.tryCancel (); continue; } } if (spins > 0) spins = shouldSpin(s) ? (spins-1) : 0; else if (s.waiter == null) s.waiter = w; // establish waiter so can park next iter // hang up after spinning else if (!timed) LockSupport.park(this); else if (nanos > spinForTimeoutThreshold) LockSupport.parkNanos(this, nanos); } } boolean shouldSpin(SNode s) { SNode h = head; //If it is the head node or the head node is null return (h == s || h == null || isFulfilling(h.mode)); } boolean tryMatch(SNode s) { if (match == null && UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) { Thread w = waiter; if (w != null) { // waiters need at most one unpark waiter = null; LockSupport.unpark(w); } return true; } return match == s; } /** Summary: This class is equivalent to a producer corresponding to a consumer. When a person produces, there must be another to consume. Equivalent to one-to-one. A thread comes in and is set as the head node, then spins and waits. Another thread came in and found that there was a head node, There is a thread. Then set yourself as the head node, and point next to the head node just now. Then try to match. The match was successful. To judge the mode of the current thread, the producer takes the value of the first node, and the consumer takes the value of the second node. */
Read SynchronousQueue source code
Guess you like
Origin http://43.154.161.224:23101/article/api/json?id=326300092&siteId=291194637
Recommended
Ranking