Read SynchronousQueue source code

// 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.
*/

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326300092&siteId=291194637