Java concurrency--inter-thread communication and synchronization technology

Source: Internet
Author: User

The traditional inter-thread communication and synchronization technology is the Wait (), notify (), Notifyall () method on object, and Java adds the condition object to the display lock, and the object can also realize the communication and synchronization between threads. This paper introduces the concept and implementation of bounded cache, and introduces the necessity of introducing inter-thread communication and synchronization technology in the process of implementing bounded cache in one step. First, the abstract base class for a bounded cache is introduced, and all implementations will inherit from this abstract base class:

Public abstract class Baseboundedbuffer<v> {private final v[] buf;private int tail;private int head;private int Coun t;protected baseboundedbuffer (int capacity) {This.buf = (v[]) new object[capacity];} Protected synchronized final void DoPut (v V) {Buf[tail] = v;if (++tail = = buf.length) tail = 0;++count;}  Protected synchronized Final V Dotake () {v v = buf[head];buf[head] = null;if (++head = = buf.length) head = 0;--count;return V;} Public Synchronized Final Boolean isfull () {return count = = buf.length;} Public Synchronized Final Boolean isEmpty () {return count = = 0;}}

One problem with inserting or extracting elements into the bounded cache is if the cache is full and you need to insert it? If the cache is empty, what is the extracted element? The following specific implementations will answer this question separately.

1. Passing an exception to the caller

The simplest way to do this is if the cache is full and an element is added to the cache, we throw an exception:

public class Grumpyboundedbuffer<v> extends baseboundedbuffer<v> {public Grumpyboundedbuffer () {This (100) ;} public grumpyboundedbuffer (int size) {super (size);} Public synchronized void put (V V) throws bufferfullexception {if (Isfull ()) throw new Bufferfullexception ();d oput (v);} Public synchronized V take () throws Bufferemptyexception {if (IsEmpty ()) throw new Bufferemptyexception (); return Dotake () ;}}

This method is simple to implement, but it is not easy to use, because each put () and take () must be ready to catch the exception, which may satisfy some requirements, but some people still want to be inserted when the detection is full, you can block there, and so on when the queue is not satisfied when the object is inserted.

2. Simple blocking through polling and hibernation

When the queue is full to insert data, we can leave the thread dormant for a period of time without throwing an exception, and then try again, at which point the queue may not already be full:

public class Sleepyboundedbuffer<v> extends baseboundedbuffer<v> {int sleep_granularity = 60;public Sleepyboundedbuffer () {this (100);} public sleepyboundedbuffer (int size) {super (size);} public void put (V-V) throws Interruptedexception {while (true) {synchronized (this) {if (!isfull ()) {doPut (v); return;}} Thread.Sleep (sleep_granularity);}} Public V take () throws Interruptedexception {and (true) {synchronized (this) {if (!isempty ()) return Dotake ();} Thread.Sleep (sleep_granularity);}}}

The biggest problem with this approach is that it is difficult to determine the appropriate sleep interval, and if the sleep interval is too long, then the responsiveness of the program becomes worse, and if the sleep interval is too short, a lot of CPU time is wasted.

3. Using conditional queue to implement bounded cache

There is a reactive problem with hibernation because we can't guarantee that the thread will end up asleep and detect it immediately when the queue is not full, so we want to have another way of implementing it, and when the cache is not full, it will actively wake up the thread instead of requiring the thread to poll the cache state. Wait () and Notifyall () on object objects can achieve this requirement. When the Wait () method is called, the thread automatically releases the lock and requests that the operating system suspend the current thread, and when the other thread detects that the condition is met, calls the Notifyall () method to wake up the suspended thread for inter-thread communication and synchronization:

public class Boundedbuffer<v> extends baseboundedbuffer<v> {public Boundedbuffer () {this (100);} public boundedbuffer (int size) {super (size);} Public synchronized void put (V V) throws interruptedexception {while (Isfull ()) wait ();d oput (v); Notifyall ();} Public synchronized V take () throws Interruptedexception {while (IsEmpty ()) wait (); V v = dotake (); Notifyall (); return v;} Public synchronized void Alternateput (v V) throws interruptedexception {while (Isfull ()) Wait (); Boolean wasempty = IsEmpty ();d oput (v); if (Wasempty) Notifyall ();}}

Note that in the above example we used the Notifyall () wake-up thread instead of the Notify () wake-up thread, and if we use Notify () to wake the thread instead, it will cause an error, and notify () will randomly select a thread wakeup in the wait queue, and Notifyall ( ) will wake up all waiting threads. For the above example, if the current is not full state, we use Notify () to wake up the thread, because only one thread can wake up, then we wake up may be waiting for a non-empty state of the thread, will cause signal loss. A single notify instead of a notifyall is required only if the following two conditions are met:

    1. All waiting threads have the same type. Only one conditional predicate is associated with a conditional queue, and each thread performs the same action after returning from wait.
    2. Single-input single-out. Every notification on a condition variable can only wake up one thread at a time to execute.

4. Using the displayed condition to implement a bounded cache

There are some flaws in the built-in condition queue, and each built-in lock can have only one associated conditional queue, so as in the last example, multiple threads are waiting for different conditional predicates on the same conditional queue, and if you want to write a concurrent object with multiple conditional predicates, you can use the displayed locks and condition. Unlike built-in locks, each display lock can have any number of condition objects. The following code gives another implementation of the bounded cache, even with two condition, notfull and Notempty, representing "non-full" and "non-null" two conditional predicates.

public class Conditionboundedbuffer<t> {protected final lock lock = new Reentrantlock ();p rivate final Condition NOTF ull = Lock.newcondition ();p rivate final Condition notempty = lock.newcondition ();p rivate static final int buffer_size = 10 0;private final t[] items = (t[]) new object[buffer_size];p rivate int tail, head, count;public void put (T x) throws Interr uptedexception {lock.lock (); try {while (count = = items.length) notfull.await (); Items[tail] = x;if (++tail = items.length ) tail = 0;++count;notempty.signal ();} finally {Lock.unlock ();}} Public T take () throws Interruptedexception {Lock.lock (), try {while (count = = 0) notempty.await (); T x = items[head];items[head] = null;if (++head = = items.length) head = 0;--count;notfull.signal (); return x;} finally {Lock.unlock ();}}}

Note that in the above example, because of the use of two condition objects, our wake-up method calls the signal () method instead of the Signalall () method.

When working with conditional queues, you need to pay special attention to the ternary relationship between locks, conditional predicates, and conditional variables: the variables contained in the conditional predicate must be protected by locks, and you must hold the lock object when checking conditional predicates and calling wait and notify (or await and signal).

Java concurrency--inter-thread communication and synchronization technology

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.