Java8 CountDownLatch and resolve the source CyclicBarrier

  table of Contents

A, CountDownLatch 

1,

2, to achieve

3, using synchronized transformation

二、CyclicBarrier

1,

2, the definition of

 3, to achieve

4, using synchronized transformation


     CountDownLatch represents a counter child thread is finished calls countDown method to count by 1, the main thread calls await, wait until the count becomes 0 or wait for a timeout for the main thread must wait for completion of all sub-threads to perform a task situation; CyclicBarrier represents a reusable fence, called the fence refers to wait for all threads to reach a certain point before you begin a task, if this point before the child thread to perform the task, you can ensure that all child threads started tasks, such as high concurrency test scenario, if the point is in the child thread to complete the task execution can be used to implement functions CountDownLatch, this blog will explain these two classes of specific usage and implementation details.

A, CountDownLatch 

1,

     CountDownLatch not let the child thread to stay at a certain point, the method can only be notified by countDown main task execution thread number of days to complete, and CountDownLatch count is not reset, that can not be reused, which is a test case as follows:

@Test
    public void test() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        CountDownLatch end=new CountDownLatch(threadNum);

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    String name=Thread.currentThread().getName();
                    System.out.println(name + " 执行任务开始,时间:" + System.currentTimeMillis());;
                    Thread.sleep(random.nextInt(2000));
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    //只是将计数减1,无法让该线程在此处停留
                    end.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum; i++) {
            new Thread(test).start();
        }
        end.await();
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
        for (int i = 0; i < threadNum; i++) {
            new Thread(test).start();
        }
        //无法重复使用,此时计数已经是0,await方法直接返回,不会阻塞
        end.await();
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
    }

The output is as follows:

Thread-0 执行任务开始,时间:1585733772491
Thread-4 执行任务开始,时间:1585733772492
Thread-3 执行任务开始,时间:1585733772492
Thread-1 执行任务开始,时间:1585733772495
Thread-5 执行任务开始,时间:1585733772495
Thread-2 执行任务开始,时间:1585733772495
Thread-4 执行任务结束,时间:1585733773436
Thread-2 执行任务结束,时间:1585733773624
Thread-0 执行任务结束,时间:1585733773928
Thread-3 执行任务结束,时间:1585733774119
Thread-1 执行任务结束,时间:1585733774257
Thread-5 执行任务结束,时间:1585733774494
所有线程结束任务,时间: 1585733774494
Thread-6 执行任务开始,时间:1585733774494
Thread-7 执行任务开始,时间:1585733774494
Thread-8 执行任务开始,时间:1585733774495
Thread-10 执行任务开始,时间:1585733774495
//第二次调用await方法立即返回,子线程启动了但是还没有执行countDown方法
//就随着主线程的退出而退出了
所有线程结束任务,时间: 1585733774495
Thread-11 执行任务开始,时间:1585733774495
Thread-9 执行任务开始,时间:1585733774495

Timeout waiting for test case scenario is as follows:

@Test
    public void test2() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        CountDownLatch end=new CountDownLatch(threadNum);

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000+random.nextInt(1000));
                    String name=Thread.currentThread().getName();
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    end.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum; i++) {
            new Thread(test).start();
        }
        //如果等待超时则被唤醒,继续执行下面的逻辑,主线程退出了,子线程也跟着退出了
        end.await(1500, TimeUnit.MILLISECONDS);
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
    }

Its execution results are as follows:

Thread-1 执行任务结束,时间:1585734211126
Thread-4 执行任务结束,时间:1585734211421
//主线程并没有等待所有的子线程执行完成就直接退出了
//其他子线程因为主线程退出了也退出了
所有线程结束任务,时间: 1585734211594

2, to achieve

     CountDownLatch is easy to implement, the core is an inherited, core class method from inside AbstractQueuedSynchronizer implemented to achieve the following:

 public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
  }

Sync(int count) {
            setState(count);
    }

  
public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            //阻塞当前线程
            doAcquireSharedInterruptibly(arg);
    }

 protected int tryAcquireShared(int acquires) {
    //判断state是否为0,为0返回1,不为0返回-1
    return (getState() == 0) ? 1 : -1;
 }

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        //创建一个新的节点并插入到链表中,注意如果链表为空会插入一个空的Node到链表中,然后再
        //插入我们创建的Node
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                //返回node的前一个节点,实际就是head节点
                final Node p = node.predecessor();
                if (p == head) {
                    //node是第一个插入的节点
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        //被唤醒后for循环进入此逻辑
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                //head的初始状态为0,shouldParkAfterFailedAcquire将其改成SIGNAL然后返回false
                //第二遍for循环就返回true,
                //parkAndCheckInterrupt方法会park掉当前线程,如果被唤醒了返回是否被线程中断
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
            //如果tryAcquireShared小于0就会执行后面的doAcquireSharedNanos方法了
        return tryAcquireShared(arg) >= 0 ||
            doAcquireSharedNanos(arg, nanosTimeout);
    }

private boolean doAcquireSharedNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                //node的前一个节点就是head节点
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return true;
                    }
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                //同上p的初始状态是0,第一遍shouldParkAfterFailedAcquire将其改成SIGNAL然后返回false,第二遍for循环就返回true
                //执行后面的判断逻辑    
                //spinForTimeoutThreshold的值是1000,单位是纳秒,如果等待的时间小于该值则自旋
                //否则让线程阻塞    
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }


public void countDown() {
        sync.releaseShared(1);
    }

  public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            //唤醒等待的主线程
            doReleaseShared();
            return true;
        }
        return false;
    }

  protected boolean tryReleaseShared(int releases) {
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                //原子的修改state,如果nextc为0则返回true
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                //head节点在doAcquireSharedInterruptibly方法中状态被改成了SIGNAL
                if (ws == Node.SIGNAL) {
                    //如果设置失败就返回false,则继续下一次循环
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    //唤醒head的下一个节点,即上面doAcquireSharedInterruptibly插入的一个节点    
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }

  3, using synchronized transformation

       It may be used instead of the internal synchronized based Sync, as follows:

import java.util.concurrent.TimeUnit;

public class ObjectCountDownLatch {

    private Object lock = new Object();

    private int count;


    public ObjectCountDownLatch(int count) {
        if (count <= 0) throw new IllegalArgumentException();
        this.count = count;
    }

    public void await() throws InterruptedException {
        dowait(false, 0L);
    }


    public void await(long timeout, TimeUnit unit)
            throws InterruptedException {
        dowait(true, unit.toMillis(timeout));
    }

    private void dowait(boolean timed, long nanos)
            throws InterruptedException {
        synchronized (lock) {
            if (count > 0) {
                if (timed) {
                    lock.wait(nanos);
                } else {
                    lock.wait();
                }
            }
        }
    }

    public void countDown() {
        synchronized (lock) {
            count--;
            if (count == 0) {
                lock.notify();
            }
        }
    }

}

Test case as follows:

@Test
    public void test3() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        ObjectCountDownLatch end=new ObjectCountDownLatch(threadNum);

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    String name=Thread.currentThread().getName();
                    Thread.sleep(random.nextInt(2000));
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    //只是将计数减1,无法让该线程在此处停留
                    end.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum; i++) {
            new Thread(test).start();
        }
        System.out.println("main start await,时间: " + System.currentTimeMillis());
        end.await();
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
    }

    @Test
    public void test4() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        ObjectCountDownLatch end=new ObjectCountDownLatch(threadNum);

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000+random.nextInt(1000));
                    String name=Thread.currentThread().getName();
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    end.countDown();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum; i++) {
            new Thread(test).start();
        }
        System.out.println("main start await,时间: " + System.currentTimeMillis());
        end.await(1500, TimeUnit.MILLISECONDS);
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
    }

  CountDownLatch effect and basically the same idea and its realization CountDownLatch is concerned.

二、CyclicBarrier

1,

     CyclicBarrier can make all child threads simultaneously start the task can be achieved CountDownLatch function, that is the main thread waits for all child threads to complete the task execution, test case as follows:

     class TaskThread extends Thread {

        CyclicBarrier barrier;

        private static Random random=new Random();

        public TaskThread(CyclicBarrier barrier) {
            this.barrier = barrier;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(random.nextInt(1000));
                System.out.println(getName() + " 到达栅栏A,时间:"+System.currentTimeMillis());
                //await方法的返回值可用来确定各线程到达的顺序,0是最后一个到达的
                //已到达的线程会阻塞等待最后一个线程到达
                int num=barrier.await();
                System.out.println(getName()+" 执行任务开始,时间:"+System.currentTimeMillis()+",num->"+num);
                Thread.sleep(random.nextInt(2000));
                System.out.println(getName()+" 执行任务结束,时间:"+System.currentTimeMillis());
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test() throws Exception {
        int threadNum = 6;
        //回调函数是最后一个调用await,即最后一个到达栅栏的线程执行的
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务,时间:"+System.currentTimeMillis());
            }
        });

        for(int i = 0; i < threadNum-1; i++) {
            new TaskThread(barrier).start();
        }
        //await可以调用多次,一旦某个线程调用了await,要求其他的相关线程也要调用await,否则因为某个线程没有调用await,其他
        //已调用await的线程就会被阻塞
        //因此主线程中await的调用次数需要与子线程中的调用次数保持一致
        int num=barrier.await();
        //如果有一个或者多个线程因为中断或者等待超时了就返回true,否则返回false
        System.out.println("isBroken->"+barrier.isBroken());
        System.out.println("所有线程开始执行,时间: "+System.currentTimeMillis()+",num->"+num);
        num=barrier.await();
        System.out.println("所有线程结束任务,时间: "+System.currentTimeMillis()+",num->"+num);
    }

Example using the results are as follows:

Thread-2 到达栅栏A,时间:1585708426763
Thread-3 到达栅栏A,时间:1585708426975
Thread-0 到达栅栏A,时间:1585708427303
Thread-1 到达栅栏A,时间:1585708427377
Thread-4 到达栅栏A,时间:1585708427378
#最后一个到达的,负责执行回调函数
Thread-4 完成最后任务,时间:1585708427378
#任务开始时间是基本一致的
Thread-4 执行任务开始,时间:1585708427381,num->0
isBroken->false
所有线程开始执行,时间: 1585708427382,num->5
Thread-2 执行任务开始,时间:1585708427382,num->4
Thread-3 执行任务开始,时间:1585708427382,num->3
Thread-0 执行任务开始,时间:1585708427382,num->2
Thread-1 执行任务开始,时间:1585708427382,num->1
Thread-0 执行任务结束,时间:1585708427707
Thread-1 执行任务结束,时间:1585708428153
Thread-2 执行任务结束,时间:1585708428186
Thread-4 执行任务结束,时间:1585708428442
Thread-3 执行任务结束,时间:1585708428918
Thread-3 完成最后任务,时间:1585708428918
所有线程结束任务,时间: 1585708428918,num->5

 The above use case is an ideal situation, the actual use to avoid the block will be set to wait for time-out, if the wait timed out would be how do? CyclicBarrier multiple threads involved if there is one or more threads wait for a timeout or interrupted because the other threads will result in the blocking state wakes up and throws an exception, the method returns true isBroken, this time must call the reset method to reset to re-use CyclicBarrier, otherwise it will error BrokenBarrierException, test case as follows:

static class TimeThread extends Thread {

        CyclicBarrier barrier;

        long time;

        public TimeThread(CyclicBarrier barrier,long time) {
            this.barrier = barrier;
            this.time=time;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(time);
                System.out.println(getName()+" 执行任务结束,时间:"+System.currentTimeMillis());
                barrier.await();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Test
    public void test2() throws Exception {
        int threadNum = 6;
        CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务,时间:"+System.currentTimeMillis());
            }
        });

        for(int i = 0; i < threadNum-1; i++) {
            new TimeThread(barrier,i*1000).start();
        }
        try {
            barrier.await(3, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("isBroken->"+barrier.isBroken());
            //重置以后isBroken变成false,可以继续使用
            //必须重置,否则抛出异常BrokenBarrierException
            barrier.reset();
            System.out.println("after reset,isBroken->"+barrier.isBroken());
        }
        for(int i = 0; i < threadNum-1; i++) {
            new TimeThread(barrier,i*1000).start();
        }
        barrier.await(5, TimeUnit.SECONDS);
        System.out.println("所有线程结束任务,时间: "+System.currentTimeMillis());
        barrier.reset();
    }

  Example performed with the following results:

Thread-0 执行任务结束,时间:1585709228033
Thread-1 执行任务结束,时间:1585709229027
Thread-2 执行任务结束,时间:1585709230032
Thread-3 执行任务结束,时间:1585709231033
isBroken->true
after reset,isBroken->false
Thread-5 执行任务结束,时间:1585709231035
java.util.concurrent.BrokenBarrierException
	at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
	at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
	at synchronizedTest.CyclicBarrierDemo$TimeThread.run(CyclicBarrierDemo.java:80)
java.util.concurrent.TimeoutException
	at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:257)
	at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:435)
	at synchronizedTest.CyclicBarrierDemo.test2(CyclicBarrierDemo.java:102)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
java.util.concurrent.BrokenBarrierException
	at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:207)
	at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
	at synchronizedTest.CyclicBarrierDemo$TimeThread.run(CyclicBarrierDemo.java:80)
java.util.concurrent.BrokenBarrierException
	at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
	at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
	at synchronizedTest.CyclicBarrierDemo$TimeThread.run(CyclicBarrierDemo.java:80)
java.util.concurrent.BrokenBarrierException
	at java.util.concurrent.CyclicBarrier.dowait(CyclicBarrier.java:250)
	at java.util.concurrent.CyclicBarrier.await(CyclicBarrier.java:362)
	at synchronizedTest.CyclicBarrierDemo$TimeThread.run(CyclicBarrierDemo.java:80)
Thread-4 执行任务结束,时间:1585709232033
Thread-6 执行任务结束,时间:1585709232036
Thread-7 执行任务结束,时间:1585709233036
Thread-8 执行任务结束,时间:1585709234036
Thread-8 完成最后任务,时间:1585709234036
所有线程结束任务,时间: 1585709234036

2, the definition of

     CyclicBarrier contains the following attributes:

    //互斥锁
    private final ReentrantLock lock = new ReentrantLock();

    /**实现阻塞的Condition*/
    private final Condition trip = lock.newCondition();

    /**参与的线程数 */
    private final int parties;

    /* 最后一个到达的线程执行的回调函数 */
    private final Runnable barrierCommand;

    /**用来描述当前的栅栏的状态,如果其属性为true,表示栅栏已损坏,重新使用该栅栏前需调用reset方法重新创建一个新的Generation  */
    private Generation generation = new Generation();
    
    /** 尚未到达栅栏,即未调用await方法的线程数 */
    private int count;

Generation which is defined as follows:

getNumberWaiting method returns the call has reached the fence that is the number of threads await method by parties minus count attributes come; getParties method returns the parties attribute, isBroken method returns a generation of broken property. Why use a private static class to wrap the broken internal properties rather than directly to private property as a CyclicBarrier? This is to distinguish the current operation belongs to await "fence", each instance corresponding to a Generation "fence", methods such as reset and interrupt execution threads, thread to be awakened found CyclicBarrier corresponding Generation has been reset, then the current thread needs to be broken.

The method of construction to achieve the following:

public CyclicBarrier(int parties) {
        this(parties, null);
    }

public CyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

 3, to achieve

      Both versions await method ultimately calls dowait method, which is the core of CyclicBarrier, its implementation is as follows:

private int dowait(boolean timed, long nanos)
        throws InterruptedException, BrokenBarrierException,
               TimeoutException {
        final ReentrantLock lock = this.lock;
        //获取锁
        lock.lock();
        try {
            final Generation g = generation;
            
            //如果为true,说明上一次调用await方法时有线程抛出异常了而没有调用reset方法重置
            if (g.broken)
                throw new BrokenBarrierException();

            if (Thread.interrupted()) {
                //如果当前线程处于中断状态,则唤醒所有等待的线程
                breakBarrier();
                throw new InterruptedException();
            }
            //count表示未到达栅栏处的线程数,此处是先减1,则赋值给index
            int index = --count;
            if (index == 0) {  // tripped
                //index等于0,说明所有线程都到达了栅栏处,当前线程是最后一个到达的线程
                boolean ranAction = false;
                try {
                    final Runnable command = barrierCommand;
                    //执行回调函数
                    if (command != null)
                        command.run();
                    ranAction = true;
                    nextGeneration();
                    return 0;
                } finally {
                    //如果回调函数执行异常,就会进入此逻辑,唤醒所有等待的线程
                    if (!ranAction)
                        breakBarrier();
                }
            }
            //index不等于0
            //此处虽然是for循环,但是实际不会循环
            for (;;) {
                try {
                    if (!timed)
                        //如果是无限期等待
                        trip.await();
                    else if (nanos > 0L)
                        //等待指定时间
                        nanos = trip.awaitNanos(nanos);
                } catch (InterruptedException ie) {
                    //await和awaitNanos方法在线程被中断时才抛出InterruptedException异常,等待超时不会抛出异常而是返回一个负数
                    //被正常唤醒时返回一个正数,表示等待的时间
                    if (g == generation && ! g.broken) {
                        //因为线程中断被唤醒的,g.broken为false
                        breakBarrier();
                        throw ie;
                    } else {
                        //某个线程准备唤醒了(g.broken为true)但是被打断了,极端情况进入此分支
                        Thread.currentThread().interrupt();
                    }
                }
                
                //某个线程因被中断或者超时等待导致等待的线程被唤醒,此时g.broken为true
                if (g.broken)
                    throw new BrokenBarrierException();
                
                //正常被唤醒,返回index
                if (g != generation)
                    return index;

                if (timed && nanos <= 0L) {
                    //因为等待超时被唤醒,抛出异常
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        } finally {
            lock.unlock();
        }
    }

   private void breakBarrier() {
        generation.broken = true;
        count = parties;
        //唤醒所有等待的线程
        trip.signalAll();
    }

    private void nextGeneration() {
        //唤醒所有线程
        trip.signalAll();
        //重置
        count = parties;
        generation = new Generation();
    }

Reset method for resetting implemented as follows:

    public void reset() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //唤醒所有线程
            breakBarrier();   // break the current generation
            //将count和generation等重置
            nextGeneration(); // start a new generation
        } finally {
            lock.unlock();
        }
    }

4, using synchronized transformation

     Because the semantics and synchronized ReentrantLock like, can also be synchronized so CyclicBarrier achieved, as follows:

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class ObjectCyclicBarrier {

    private static class Generation {
        boolean broken = false;
    }

    private final Object lock = new Object();

    private final int parties;

    private final Runnable barrierCommand;

    private Generation generation = new Generation();

    private int count;


    private void nextGeneration() {
        lock.notifyAll();
        count = parties;
        generation = new Generation();
    }

    private void breakBarrier() {
        generation.broken = true;
        count = parties;
        lock.notifyAll();
    }

    private int dowait(boolean timed, long nanos)
            throws InterruptedException, BrokenBarrierException,
            TimeoutException {
        synchronized (lock) {
            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();
                }
            }

            boolean timeout=false;
            for (; ; ) {
                try {
                    if (!timed)
                        lock.wait();
                    else if (nanos > 0L) {
                        long start=System.currentTimeMillis();
                        lock.wait(nanos);
                        if(System.currentTimeMillis()-start==nanos){
                            timeout=true;
                        }
                    }
                } 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 && timeout) {
                    breakBarrier();
                    throw new TimeoutException();
                }
            }
        }
    }


    public ObjectCyclicBarrier(int parties, Runnable barrierAction) {
        if (parties <= 0) throw new IllegalArgumentException();
        this.parties = parties;
        this.count = parties;
        this.barrierCommand = barrierAction;
    }

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }


    public int await(long timeout, TimeUnit unit)
            throws InterruptedException,
            BrokenBarrierException,
            TimeoutException {
        return dowait(true, unit.toMillis(timeout));
    }


    public boolean isBroken() {
        synchronized (lock) {
            return generation.broken;
        }
    }


    public synchronized void reset() {
        synchronized (lock) {
            breakBarrier();   // break the current generation
            nextGeneration(); // start a new generation
        }
    }

}

 await two versions of the test are as follows:

@Test
    public void test3() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        //回调函数是最后一个调用await,即最后一个到达栅栏的线程执行的
        ObjectCyclicBarrier barrier = new ObjectCyclicBarrier(threadNum, new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务,时间:" + System.currentTimeMillis());
            }
        });

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    String name=Thread.currentThread().getName();
                    Thread.sleep(random.nextInt(1000));
                    System.out.println(name + " 到达栅栏A,时间:" + System.currentTimeMillis());
                    //await方法的返回值可用来确定各线程到达的顺序,0是最后一个到达的
                    int num = barrier.await();
                    System.out.println(name + " 执行任务开始,时间:" + System.currentTimeMillis() + ",num->" + num);
                    Thread.sleep(random.nextInt(2000));
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum - 1; i++) {
            new Thread(test).start();
        }
        int num = barrier.await();
        System.out.println("isBroken->" + barrier.isBroken());
        System.out.println("所有线程开始执行,时间: " + System.currentTimeMillis() + ",num->" + num);
        num = barrier.await();
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis() + ",num->" + num);
    }

    @Test
    public void test4() throws Exception {
        Random random = new Random();
        int threadNum = 6;
        //回调函数是最后一个调用await,即最后一个到达栅栏的线程执行的
        ObjectCyclicBarrier barrier = new ObjectCyclicBarrier(threadNum, new Runnable() {

            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " 完成最后任务,时间:" + System.currentTimeMillis());
            }
        });

        Runnable test=new Runnable() {
            @Override
            public void run() {
                try {
                    String name=Thread.currentThread().getName();
                    Thread.sleep(800+random.nextInt(1000));
                    System.out.println(name + " 执行任务结束,时间:" + System.currentTimeMillis());
                    barrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };

        for (int i = 0; i < threadNum - 1; i++) {
            new Thread(test).start();
        }
        try {
            barrier.await(1500,TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("isBroken->" + barrier.isBroken());
            barrier.reset();
        }
        for (int i = 0; i < threadNum - 1; i++) {
            new Thread(test).start();
        }
        barrier.await();
        System.out.println("所有线程结束任务,时间: " + System.currentTimeMillis());
    }

CyclicBarrier and its effects, as even the code more concise.

Published 137 original articles · won praise 15 · views 20000 +

Guess you like

Origin blog.csdn.net/qq_31865983/article/details/105228189