[Practical Java high concurrency Program Design 7] Let threads help each other-Implementation of SynchronousQueue and synchronousqueue

Source: Internet
Author: User

[Practical Java high concurrency Program Design 7] Let threads help each other-Implementation of SynchronousQueue and synchronousqueue

[Practice: Java high concurrency Program Design 1] pointer in Java: Unsafe class

[Java high concurrency program design 2] Lock-free Object Reference: AtomicReference

[Practical Java high concurrency Program Design 3] References to objects with timestamps: AtomicStampedReference

[Practical Java high concurrency Program Design 4] Arrays can also be unlocked: AtomicIntegerArray

[Practical Java high concurrency Program Design 5] allows common variables to also enjoy atomic operations

[Practical Java high concurrency Program Design 6] challenge lock-free algorithm: Lock-Free Vector implementation

In the introduction to thread pools, we mentioned a very special waiting queue SynchronousQueue. The SynchronousQueue capacity is 0. Any write to SynchronousQueue needs to wait for a read to SynchronousQueue, and vice versa. Therefore, SynchronousQueue is not so much a queue as a data exchange channel. How does the Merge function of SynchronousQueue be implemented?

Since I plan to introduce it in this section, SynchronousQueue, for example, cannot be separated from lockless operations. In fact, SynchronousQueue also uses a large number of lockless tools.

For SynchronousQueue, it abstracts put () and take () operations into a common method Transferer. transfer (). Literally, This is what data transmission means. Its complete signature is as follows:

 

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

If parameter e is not empty, it indicates that the current operation is passed to a consumer. If it is empty, it indicates that the current operation needs to request a data. The timed parameter determines whether the timeout time exists. nanos determines the timeout duration. If the returned value is not null, the data is accepted or provided normally. If the returned value is null, the Data fails (timeout or interruption ).

SynchronousQueue maintains a thread waiting queue. The waiting queue stores information about the waiting thread and related data. For example, when a producer puts data into SynchronousQueue, if no consumer accepts the data, both the data itself and the thread object will be packed in the queue for waiting (because the SynchronousQueue volume is 0, and no data can be normally put in ).

The implementation of the Transferer. transfer () function is the core of SynchronousQueue. It consists of three steps:

1. If the waiting queue is empty or the node type in the queue is the same as that in this operation, press the current operation into the queue for waiting. For example, the waiting queue is a read thread wait, and this operation is also a read, so the two reads need to wait. The threads entering the waiting queue may be suspended and they will wait for a "match" operation.

2. If the elements in the waiting queue are complementary to this operation (for example, the waiting operation is read and the operation is write), a node in the "finished" state is inserted, and let him "match" to a waiting node. The two nodes are displayed, and the corresponding two threads continue to run.

3. If the thread finds that the node waiting for the queue is a "complete" node. This helps the node complete the task. The process is consistent with Step 2.

The implementation of step 1 is as follows (for the code, refer to JDK 7u60 ):

SNode h = head; if (h = null | h. mode = mode) {// if the queue is empty, or the mode is the same if (timed & nanos <= 0) {// do not wait if (h! = Null & h. isCancelled () casHead (h, h. next); // processing the cancelling behavior else return null;} else if (casHead (h, s = snode (s, e, h, mode ))) {SNode m = awaitFulfill (s, timed, nanos); // wait until a matching operation appears if (m = s) {// wait for the canceled 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 ;}}

In the above Code, line 4 SNode indicates waiting for nodes in the queue. It encapsulates information such as the current thread, next node, matching node, and data content. Row 3 determines that the current waiting queue is empty, or that the element mode in the queue is the same as that in this operation (for example, if both are read operations, you must wait ). Line 3: generate a new node and place it in the queue header. This node represents the current thread. If the queue is successfully added, the awaitFulfill () function of Line 1 is executed. This function performs spin wait and finally suspends the current thread. Wait until a corresponding operation is generated and wake it up. After the thread is awakened (indicating that the data has been read or the data generated by itself has been read by another thread ~ Line 15 tries to help the corresponding thread to complete the queuing operation of the two header nodes (this is only a friendly help ). At the end, the data read or written (16th rows) is returned ).

The implementation of step 2 is as follows: 

} Else if (! IsFulfilling (h. mode) {// if (h. isCancelled () // If casHead (h, h. next); // pop up and retry else if (casHead (h, s = snode (s, e, h, FULFILLING | mode) {(;;) {// keep loop until match or no waiting person has SNode m = s. next; // m is the matching person of s (match) if (m = null) {// No waiting person has casHead (s, null ); // The fulfill node s = null is displayed; // use the new node break next time; // re-start the main loop} SNode mn = m. next; if (m. tryMatch (s) {casHead (s, mn); // pop-up S and m return (mode = REQUEST )? M. item: s. item;} else // match failed s. casNext (m, mn); // help delete node }}}

In the above Code, first determine whether the header node is in fulfill mode. If yes, go to step 3. Otherwise, you will try to use the corresponding fulfill thread. Line 3 generates a SNode element, sets it to fulfill mode, and pushes it to the queue header. Then, Set m (original queue header) to s's matching node (row 13th). This tryMatch () operation will activate a waiting thread and pass m to that thread. If the setting is successful, the data delivery is complete. You can bring up the s and m nodes (14th rows ). If tryMatch () fails, it indicates that other threads have completed the operation for me, so simply delete the m node (17th rows), because the data of this node has been shipped, you do not need to process it again, and then jump to the loop body of the 5th line again to perform the matching and data shipping of the next waiting thread until the queue does not have a waiting thread.

Step 3: If the thread finds that the Header element is in fulfill mode during execution, it will help the fulfill node to be executed as soon as possible: 

} Else {// help a fulfiller SNode m = h. next; // m is the match if (m = null) of h // No waiting person casHead (h, null); // The fulfill node else {SNode mn = m is displayed. next; if (m. tryMatch (h) // try to match casHead (h, mn); // pop up h and m else // match failed h. casNext (m, mn); // help delete node }}

The execution principle of the above Code is exactly the same as that of step 2. The only difference is that step 3 does not return data because the work in step 3 is to help other threads ship their data as soon as possible. However, the corresponding operations are not completed. Therefore, after the thread enters step 3, it enters the Large Loop body again (not given in the Code), and starts from step 1 to re-judge the condition and ship data.

From the entire data delivery process, we can see that in SynchronousQueue, all the threads involved in the work are not just the relationship between competing resources. More importantly, they will help each other. Within a thread, it may help other threads to complete their work. This mode can reduce the possibility of hunger to a greater extent and improve the overall degree of parallelism of the system.

 

 

 

From "Practical Java high concurrency Program Design"

Related Article

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.