Java. util. concurrent package source code reading 16 special BlockingQueue: SynchronousQueue, java. util package

Source: Internet
Author: User

Java. util. concurrent package source code reading 16 special BlockingQueue: SynchronousQueue, java. util package

SynchronousQueue is a special BlockingQueue. Any operation to add an element must wait until another thread takes the element away. That is, SynchronousQueue itself does not store any elements, which is equivalent to direct transactions between producers and consumers.

SynchronousQueue has a fair option. If fair is true, it is called the fair mode. Otherwise, it is the unfair mode.

In fair mode, all the waiting producer threads or consumer threads queue in sequence according to the start wait time, and then perform matching transactions according to the waiting sequence. In this case, use the queue.

In the unfair mode, the opposite is true, and then the matching is performed first. In this case, the stack is used for implementation.

     */    public SynchronousQueue(boolean fair) {        transferer = fair ? new TransferQueue() : new TransferStack();    }

Because adding and removing elements are similar to hand-handed transactions, SynchronousQueue calls the same Transferer method for removing and adding elements.

If the object is null, it indicates that the element is taken away for the consumer thread. Otherwise, the element is added for the producer thread. Therefore, the transfer method is the focus of analysis.

abstract Object transfer(Object e, boolean timed, long nanos);

 

First, let's look at the TransferQueue's transfer method for fair mode:

Let's take a look at the logic before looking at the Code:

1. The start queue must be empty.

2. The thread enters the queue. If the queue is empty, add the thread to the queue and wait (either a matching thread appears or the request timed out and canceled)

3. The second thread enters. If the previous thread belongs to different types, that is, the two can be matched, the first thread is deleted from the queue.

For the same thread, refer to 2.

 

The basic logic is clarified, that is, there are two situations:

1. the queue is empty or the waiting threads in the queue are of the same type

2. The waiting threads in the queue are of the matching type.

Object transfer (Object e, boolean timed, long nanos) {QNode s = null; // If e is not null, it indicates that it is the producer thread, and e indicates the product, the opposite is the consumer thread boolean isData = (e! = Null); for (;) {QNode t = tail; QNode h = head; // tail and head are initialized to a virtual node when the queue is created. // No Initialization is found, recyclically wait until Initialization is complete if (t = null | h = null) continue; // The queue is empty or the waiting thread type is the same (different types can match) // Add the current thread to the waiting queue in both cases. if (h = t | t. isData = isData) {QNode tn = t. next; // The tail object has been updated, and inconsistency reading occurs. Re-loop if (t! = Tail) continue; // when a thread is added to the waiting queue, the next of the current tail is updated first, and then the tail itself is updated. Therefore, only next is updated, should be // updated, and then re-loop if (tn! = Null) {advanceTail (t, tn); continue ;}// set timeout. When the remaining waiting time is exhausted, no need to wait until if (timed & nanos <= 0) return null; // when s is used for the first time, create a new node to save the current thread and data to initialize s if (s = null) s = new QNode (e, isData); // try to update tail's next, add the new node to the end of tail. if the node fails, repeat if (! T. casNext (null, s) continue; // set the new node to tail advanceTail (t, s); // wait for the matching thread, if a successful match is successful, the matched value is returned. // otherwise, the current node is returned. If s and x are the same, the request is canceled. Object x = awaitFulfill (s, e, timed, nanos ); if (x = s) {clean (t, s); return null;} // The match is successful, s should be the first waiting thread. // If s is still in the queue, update the head. // The method for updating the head is to take the node s in the first place as the new head // so you need to reset some attributes to make it a virtual node if (! S. isOffList () {advanceHead (t, s); if (x! = Null) s. item = s; s. waiter = null;} // if the value of x is not null, the data of the matching thread is obtained (the consumer obtains the data of the producer). // Therefore, the data is returned, otherwise, the system returns its own data (the builder returns its own data) return (x! = Null )? X: e;} else {// The thread can match. // because it is a queue, the first node QNode m = h is matched. next; // check if (t! = Tail | m = null | h! = Head) continue; Object x = m. item; // if the matching fails, remove m from the queue and re-cycle if (isData = (x! = Null) | // m has been matched x = m | // m has been canceled! M. casItem (x, e) {// use CAS to set m's data to null advanceHead (h, m); continue ;}// match successful, update head advanceHead (h, m); // unlock m's thread Wait Status LockSupport. unpark (m. waiter); // return the matched data return (x! = Null )? X: e ;}}}

 

Next we will use the TransferStack transfer method for the Unfair mode.

The general logic should be the same. The difference is that the inbound and outbound operations of the queue correspond to the stack operations.

Object transfer (Object e, boolean timed, long nanos) {SNode s = null; int mode = (e = null )? REQUEST: DATA; for (;) {SNode h = head; // if the stack is empty or the node type is the same, if (h = null | h. mode = mode) {if (timed & nanos <= 0) {// check whether the top node of the stack has been canceled. if it has been canceled, the node is displayed // recyclically, then check the new stack top node if (h! = Null & h. isCancelled () casHead (h, h. next); else return null; // create a node and try to stack the new node} else if (casHead (h, s = snode (s, e, h, mode) {// wait for a match. If the node is canceled, the node is released and null SNode m = awaitFulfill (s, timed, nanos) is returned ); if (m = s) {clean (s); return null ;} // if the two nodes match successfully, they are the two nodes at the top of the stack. // if (h = head) is displayed for both nodes )! = Null & h. next = s) casHead (h, s. next); // help s's fulfiller return (mode = REQUEST )? M. item: s. item;} else if (! IsFulfilling (h. mode) {// The top node of the stack does not match other threads. It can match if (h. isCancelled () // The request for the top node of the stack has been canceled casHead (h, h. next); // remove the top element of the stack and recycle it. // try to add the node to the stack, this node is set to a matching status // isFulfilling returns true else if (casHead (h, s = snode (s, e, h, FULFILLING | mode ))) {for (;) {// The top node of the stack (the node of the current thread) matches with its next node. If m is null, it means that no other node exists in the stack, because the previous node is in the stack, the node needs to be popped up and recyclically SNode m = s. next; if (m = null) {casHead (s, null); s = null; break;} // At this time, a node can match Match the two nodes with SNode mn = m. next; // m and s match successfully. The two nodes are displayed and data is returned. if m (m. tryMatch (s) {casHead (s, mn); return (mode = REQUEST )? M. item: s. item;} else s. casNext (m, mn) ;}// the top of the stack is matching. For details, see the code: // else if (casHead (h, s = snode (s, e, h, FULFILLING | mode) {// The method is basically similar, but here it helps other threads match, whether it is successful or not, it must be recycled} else {SNode m = h. next; if (m = null) casHead (h, null); else {SNode mn = m. next; if (m. tryMatch (h) casHead (h, mn); else h. casNext (m, mn );}}}}

 

For more information about the Algorithm Implementation of TransferQueue and TransferStack, see




Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.