【多线程】工具类

 Phase:https://cloud.tencent.com/developer/article/1350849


 CyclicBarrier

参考:https://blog.csdn.net/qq_38293564/java/article/details/80558157

 栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生。

CyclicBarrier可以使一定数量的线程反复地在栅栏位置处汇集。当线程到达栅栏位置时将调用await方法,这个方法将阻塞直到所有线程都到达栅栏位置。如果所有线程都到达栅栏位置,那么栅栏将打开,此时所有的线程都将被释放,而栅栏将被重置以便下次使用。

叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier 可以被重用。

CyclicBarrier构造方法

  CyclicBarrier(int parties):其参数表示屏障拦截的线程数量,每个线程使用await()方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

  CyclicBarrier(int parties, Runnable barrierAction):用于线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景

await方法:

     public int await():用来挂起当前线程,直至所有线程都到达 barrier 状态再同时执行后续任务;

  public int await(long timeout, TimeUnit unit):让这些线程等待至一定的时间,如果还有线程没有到达 barrier 状态就直接让到达 barrier 的线程执行后续任务。


 

public class CyclicBarrierTest {
    // 自定义工作线程
    private static class Worker extends Thread {
        private CyclicBarrier cyclicBarrier;
        
        public Worker(CyclicBarrier cyclicBarrier) {
            this.cyclicBarrier = cyclicBarrier;
        }
        
        @Override
        public void run() {
            super.run();
            
            try {
                System.out.println(Thread.currentThread().getName() + "开始等待其他线程");
                cyclicBarrier.await();
                System.out.println(Thread.currentThread().getName() + "开始执行");
                // 工作线程开始处理,这里用Thread.sleep()来模拟业务处理
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + "执行完毕");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
 
    public static void main(String[] args) {
        int threadCount = 3;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
        
        for (int i = 0; i < threadCount; i++) {
            System.out.println("创建工作线程" + i);
            Worker worker = new Worker(cyclicBarrier);
            worker.start();
        }
    }
}

执行结果:

创建工作线程0
创建工作线程1
Thread-0开始等待其他线程
创建工作线程2
Thread-1开始等待其他线程
Thread-2开始等待其他线程
Thread-2开始执行
Thread-0开始执行
Thread-1开始执行
Thread-1执行完毕
Thread-0执行完毕
Thread-2执行完毕

 

CyclicBarrier和CountDownLatch的区别
  CountDownLatch的计数器只能使用一次,而CyclicBarrier的计数器可以使用reset()方法重置,可以使用多次,所以CyclicBarrier能够处理更为复杂的场景;

  CyclicBarrier还提供了一些其他有用的方法,比如getNumberWaiting()方法可以获得CyclicBarrier阻塞的线程数量,isBroken()方法用来了解阻塞的线程是否被中断;

  CountDownLatch允许一个或多个线程等待一组事件的产生,而CyclicBarrier用于等待其他线程运行到栅栏位置。

        CyclicBarrier vs CountdownLatch:CyclicBarrier可以通过reset()实现重置门限值,CountDownLatch为一次性。


 

CountDownLatch

注意:new CountDownLatch(5)中数字必须严格跟期望等待数字保持一致,否则可能出现意外的结果(因为超出5的线程会不被进行等待)

1、代码使用样例

     通过CountDownLatch实现:"主线程"等待"5个子线程"全部都完成"指定的工作(休眠1000ms)"之后,再继续运行。

import java.util.concurrent.CountDownLatch;

public class CountDownLatchTest {

    private static CountDownLatch latch = new CountDownLatch(5);

    public static void main(String[] args) {

        System.out.println("Main Thread start....");
        System.out.println();

        for (int i = 0; i < 5; i++) {
            new InnerThread().start();
        }

        try {
            latch.await();
            System.out.println();
            System.out.println("Main Thread latch.getCount = " + latch.getCount());
        } catch (InterruptedException e) {
            System.out.println("Exception happened in latch await: " + e);
        }

        System.out.println("Main Thread end....");
    }

    static class InnerThread extends Thread {
        public void run() {
            synchronized (InnerThread.class) {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " sleep 1000 ms.");
                    // 将CountDownLatch的数值减1
                    latch.countDown();
                    System.out.println(Thread.currentThread().getName() + " count number: " + latch.getCount());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
View Code

执行结果:  主线程等待,直至 latch 通过 countDown 减为0后,主线程才继续执行。

Main Thread start....

Thread-1 sleep 1000 ms.
Thread-1 count number: 4
Thread-4 sleep 1000 ms.
Thread-4 count number: 3
Thread-0 sleep 1000 ms.
Thread-0 count number: 2
Thread-3 sleep 1000 ms.
Thread-3 count number: 1
Thread-2 sleep 1000 ms.
Thread-2 count number: 0

Main Thread latch.getCount = 0
Main Thread end....
View Code

 2、常用方法解读

CountDownLatch(int count) // 构造一个用给定计数初始化的 CountDownLatch。
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()      // 调用sync.acquireSharedInterruptibly(1)实现AQS中state=1
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。 
boolean await(long timeout, TimeUnit unit) 
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 
void countDown() // 调用sync.releaseShared(1) 实现AQS中state-1
long getCount() // 返回当前计数。 

 

posted @ 2020-05-05 23:42  飞翔在天  阅读(168)  评论(0编辑  收藏  举报