In layman's Java Concurrency (11): Lock mechanism Part 6 Cyclicbarrier

Source: Internet
Author: User

If Countdownlatch is a one-off, then cyclicbarrier just can be recycled. It allows a group of threads to wait for each other until a common barrier point (common barrier points) is reached. The so-called barrier point is the time when a set of tasks is completed.

Listing 11 examples of using Cyclicbarrier

Package xylz.study.concurrency.lock;

Import java.util.concurrent.BrokenBarrierException;
Import Java.util.concurrent.CyclicBarrier;

public class Cyclicbarrierdemo {

Final Cyclicbarrier barrier;

final int max_task;

Public Cyclicbarrierdemo (int cnt) {
Barrier = new Cyclicbarrier (cnt + 1);
Max_task = CNT;
}

public void DoWork (final Runnable work) {
New Thread () {

public void Run () {
Work.run ();
try {
int index = barrier.await ();
Dowithindex (index);
} catch (Interruptedexception e) {
Return
} catch (Brokenbarrierexception e) {
Return
}
}
}.start ();
}

    private void Dowithindex (int index) {
         if (index = = MAX_TASK/3) {
             System.out.println ("left 30%.");
       } else if (index = = MAX_TASK/2) {
            System.out.println ( "Left 50%");
       } else if (index = = 0) {
            System.out.println (" Run Over ");
       }
    }

    public void Waitfornext () {
         try {
            Dowithindex (Barrier.await ());
       } catch (Interruptedexception e) {
            return;
       } catch (Brokenbarrierexception e) {
            return;
       }
    }

public static void Main (string[] args) {
Final int count = 10;
Cyclicbarrierdemo demo = new Cyclicbarrierdemo (count);
for (int i = 0; i <; i++) {
Demo.dowork (New Runnable () {

public void Run () {
Do something
try {
Thread.Sleep (1000L);
} catch (Exception e) {
Return
}
}
});
if ((i + 1)% count = = 0) {
Demo.waitfornext ();
}
}
}

}

Listing 1 Describes an example of a recurring task, in which a pair of tasks (100) is expected to be processed for each of the 10 groups, and the next group is currently only available when the previous set of tasks has been completed, and in each set of tasks, when the task remains 50%,30% and notifies the observer when all tasks are completed.

In this example, Cyclicbarrierdemo constructs a count+1 task group (one of the tasks to hang the main thread for the convenience of the outside world). In each sub-task, the character itself will need to wait for the other tasks in the same group to complete before continuing. At the same time the remaining tasks 50%, 30% already 0 o'clock perform special other tasks (notifications).

It is clear that Cyclicbarrier has the following characteristics:

    • The await () method suspends the thread until another thread in the same group finishes execution to continue
    • The await () method returns the index at which the thread has finished executing, noting that the index starts with the number of tasks-1, that is, the first task to complete is indexed as PARTIES-1, the last is 0, the parties is total task, and the list is cnt+1
    • The Cyclicbarrier is recyclable, and the name clearly illustrates this. In Listing 1, each set of tasks is completed to perform the next set of tasks.

In addition to Cyclicbarrier in addition to the above characteristics, there are several features:

    • If the barrier operation does not depend on the suspended thread, then any thread can perform a barrier operation. As you can see in Listing 1, you do not specify that the thread performs 50%, 30%, 0% operations, but rather a set of threads (cnt+1) Any one of the threads can perform the action as soon as it reaches the barrier point.
    • The Cyclicbarrier constructor allows you to carry a task that will be executed at the 0% barrier point, which will be executed after the await () ==0.
    • Cyclicbarrier other tasks in the task group are immediately interrupted to interruptedexception an exception from the thread if the barrier is left early because of an outage, failure, timeout, and so on.
    • All operations before the await () will run before the barrier point, which is the memory consistency effect of the Cyclicbarrier

All APIs for Cyclicbarrier are as follows:

  • Public cyclicbarrier(int parties) creates a new Cyclicbarrierthat starts when a given number of participants (threads) are waiting, but it does not start Performs a pre-defined operation when barrier.
  • Public cyclicbarrier(int parties, Runnable barrieraction) creates a new cyclicbarrier, It will start when a given number of participants (threads) are waiting and perform a given barrier operation when the barrier is started, which is executed by the last thread that enters barrier.
  • public int await() throws Interruptedexception, Brokenbarrierexception has been raised on this barrier in all participants await< Wait until the/c2> method is used.
  • public int await(long timeout,timeunit unit) throws Interruptedexception, Brokenbarrierexception, TimeoutException waits before all participants have invoked the await method on this barrier, or exceeds the specified wait time.
  • public int getnumberwaiting() Returns the number of participants currently waiting at the barrier. This method is primarily used for debugging and assertions.
  • public int getparties() Returns the number of participants that are required to start this barrier.
  • The public boolean isbroken() queries whether this barrier is in a corrupt state.
  • The public Void Reset () resets the barrier to its initial state.

For the above API, the following is a discussion of the implementation of the Cyclicbarrier, and why there is such an API.

Listing 2 Implementation fragments of cyclicbarrier.await* ()

private int Dowait (Boolean timed, Long Nanos)
Throws Interruptedexception, Brokenbarrierexception,
timeoutexception {
Final Reentrantlock lock = This.lock;
Lock.lock ();
try {
Final Generation g = Generation;
if (G.broken)
throw new Brokenbarrierexception ();

if (thread.interrupted ()) {
Breakbarrier ();
throw new Interruptedexception ();
}

int index =--count;
if (index = = 0) {//tripped
Boolean ranaction = false;
try {
Final Runnable command = Barriercommand;
if (command! = NULL)
Command.run ();
Ranaction = true;
Nextgeneration ();
return 0;
} finally {
if (!ranaction)
Breakbarrier ();
}
}

Loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
Trip.await ();
else if (Nanos > 0L)
Nanos = Trip.awaitnanos (Nanos);
} catch (Interruptedexception IE) {
if (g = = Generation &&! G.broken) {
Breakbarrier ();
throw ie;
} else {
Thread.CurrentThread (). interrupt ();
}
}

if (G.broken)
throw new Brokenbarrierexception ();

if (g! = Generation)
return index;

If (timed && Nanos <= 0L) {
Breakbarrier ();
throw new TimeoutException ();
}
}
} finally {
Lock.unlock ();
}
}

Listing 2 is a bit complicated, and here's a 1.1-point anatomy, and revert to the original state.

Using the knowledge learned above, we know that to allow threads to wait for other threads to finish, the thread that has already been executed (entering the await* () method) requires park () until it expires or is interrupted, or is woken by another thread.

Previously said that the characteristics of cyclicbarrier is either the normal execution of everyone, or everyone is abnormally interrupted, not one of them is interrupted and other normal execution of the phenomenon exists. This feature is called All-or-none. A similar concept is that in atomic operations either everyone executes or none of the operations are finished. Now this is actually two concepts. To accomplish this, you have to have a state to describe whether or not a thread has been interrupted (broken), so that the thread that executes after it knows if it needs to wait. And in the Cyclicbarrier generation is to accomplish this thing. The definition of generation is very simple, and the entire structure has only one variable, boolean broken = False, to define whether the broken operation has occurred.

Due to the existence of competitive resources (BROKEN/INDEX), there is no doubt that a locking lock is required. After getting the lock the whole process is this:

    1. Checks if there is a break bit (broken) and returns immediately with a Brokenbarrierexception exception if it exists. This exception describes the waiting state where the thread entry barrier is compromised. Otherwise proceed to 2.
    2. Check if the current thread is interrupted, if so set the interrupt bit (so that other threads that are going to wait), wake up the waiting thread, and return with the interruptedexception exception, indicating that the thread is processing the interrupt. Otherwise proceed to 3.
    3. Reduce the number of remaining tasks by 1, if the remaining number of tasks at this time is 0, that is, to reach the public barrier point, then perform the barrier task (if any), and create a new generation (in this process will wake all other threads, so the current thread is a barrier point thread, Then all other threads should be in the waiting state). Otherwise proceed to 4.
    4. This means that the thread should park () when the barrier point has not been reached. It is obvious that the park thread is to be in the following for loop. Here the park thread is using the Condition.await () method. namely trip.await* (). Why do I need condition? Because all the await* () is actually waiting for a condition, once the condition satisfies should all be awakened, so the condition is good to satisfy this characteristic. So here you'll see why it's important to wake up other threads when you create a new generation when you reach the barrier point in step 3.

The above 4 steps are just a description of the main structure, in fact there is a lot of logic in the process to deal with the problem caused by the exception, such as the execution of the barrier point task thrown by the exception, park line blocks until those caused by the interrupt exception and timeout exception and so on. So for await (), exception handling is more complex than business logic, which explains why an await () may cause interruptedexception,brokenbarrierexception, TimeoutException three kinds of anomalies.

Listing 3 generating the next cycle cycle and waking other threads

private void Nextgeneration () {
Trip.signalall ();
Count = parties;
Generation = new Generation ();
}

Listing 3 describes how to generate the next cycle cycle, which of course requires the use of Condition.signalall () to wake up all the threads that have completed and are waiting. In addition, here count describes how many threads still need to be executed in order for the thread to finish executing the index count.

The IsBroken () method describes the Generation.broken, which is whether the thread group has an exception. Here again, explain why this state exists.

If an exception occurs for a thread that is going to be at a barrier point or that is already at the barrier point and performs the barrier task, even if the other waiting threads are awakened, the other waiting Threads "die" because there is no thread that wakes up the second time the park threads. Another idea is that if the barrier points are damaged, then other threads that will wait for the barrier to hang are meaningless.

Writing here is very unfortunate, used for more than 4 years, the lamp finally "died."

In fact, Cyclicbarrier also has a reset method that describes the manual immediately interrupts all threads, restores the barrier points, and performs the next set of tasks. That is, the cost of maintenance may be less costly than recreating a new barrier point (less synchronization, less management of the previous cyclicbarrier, and so on).

Originally want to and semaphore together, finally found out after a bit long, but also not conducive to understanding and absorption, so put to the next article.

Resources:

      1. Synchronize between threads using Cyclicbarrier

      2. Cyclicbarrier and Countdownlatch Tutorial

      3. Thread-cyclicbarrier

      4. Java Threading Learning Notes (10) Countdownlatch and Cyclicbarrier

      5. A preliminary tutorial on multithreading synchronization design and use of--barrier

      6. Thread coordination with Countdownlatch and Cyclicbarrier

      7. How to make full use of multi-core CPUs, calculate the number of all integers in a large list and

In layman's Java Concurrency (11): Lock mechanism Part 6 Cyclicbarrier

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.