美文网首页java高级开发
【java】并发-同步器

【java】并发-同步器

作者: 老鼠AI大米_Java全栈 | 来源:发表于2021-03-19 10:02 被阅读0次

    多线程处理中,有时需要等待一些线程到达后才继续执行,这就需要线程同步器。

    CountDownLatch 闭锁

    java.util.concurrent.CountDownLatch 是一个并发构造,它允许一个或多个线程等待一系列指定操作的完成。
    CountDownLatch 以一个给定的数量初始化。countDown() 每被调用一次,这一数量就减一。通过调用 await() 方法之一,线程可以阻塞等待这一数量到达零。
    以下是一个简单示例。Decrementer 三次调用 countDown() 之后,等待中的 Waiter 才会从 await() 调用中释放出来。

    CountDownLatch latch = new CountDownLatch(3);
     
    Waiter      waiter      = new Waiter(latch);
    Decrementer decrementer = new Decrementer(latch);
     
    new Thread(waiter)     .start();
    new Thread(decrementer).start();
     
    Thread.sleep(4000);
     
    public class Waiter implements Runnable{
     
        CountDownLatch latch = null;
     
        public Waiter(CountDownLatch latch) {
            this.latch = latch;
        }
     
        public void run() {
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
     
            System.out.println("Waiter Released");
        }
    }
     
    public class Decrementer implements Runnable {
     
        CountDownLatch latch = null;
     
        public Decrementer(CountDownLatch latch) {
            this.latch = latch;
        }
     
        public void run() {
     
            try {
                Thread.sleep(1000);
                this.latch.countDown();
     
                Thread.sleep(1000);
                this.latch.countDown();
     
                Thread.sleep(1000);
                this.latch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    

    栅栏 CyclicBarrier

    java.util.concurrent.CyclicBarrier 类是一种同步机制,它能够对处理一些算法的线程实现同步。换句话讲,它就是一个所有线程必须等待的一个栅栏,直到所有线程都到达这里,然后所有线程才可以继续做其他事情。图示如下:

    image.png
    两个线程在栅栏旁等待对方。
    通过调用 CyclicBarrier 对象的 await() 方法,两个线程可以实现互相等待。一旦 N 个线程在等待 CyclicBarrier 达成,所有线程将被释放掉去继续运行。

    创建一个 CyclicBarrier

    在创建一个 CyclicBarrier 的时候你需要定义有多少线程在被释放之前等待栅栏。创建 CyclicBarrier 示例:

    CyclicBarrier barrier = new CyclicBarrier(2);
    

    等待一个 CyclicBarrier

    以下演示了如何让一个线程等待一个 CyclicBarrier:

    barrier.await();
    

    当然,你也可以为等待线程设定一个超时时间。等待超过了超时时间之后,即便还没有达成 N 个线程等待 CyclicBarrier 的条件,该线程也会被释放出来。以下是定义超时时间示例:

    barrier.await(10, TimeUnit.SECONDS);
    

    满足以下任何条件都可以让等待 CyclicBarrier 的线程释放:

    • 最后一个线程也到达 CyclicBarrier(调用 await())
    • 当前线程被其他线程打断(其他线程调用了这个线程的 interrupt() 方法)
    • 其他等待栅栏的线程被打断
    • 其他等待栅栏的线程因超时而被释放
    • 外部线程调用了栅栏的 CyclicBarrier.reset() 方法

    CyclicBarrier 行动

    CyclicBarrier 支持一个栅栏行动,栅栏行动是一个 Runnable 实例,一旦最后等待栅栏的线程抵达,该实例将被执行。你可以在 CyclicBarrier 的构造方法中将 Runnable 栅栏行动传给它:

    Runnable      barrierAction = ... ;
    CyclicBarrier barrier       = new CyclicBarrier(2, barrierAction);
    

    CyclicBarrier 示例

    以下代码演示了如何使用 CyclicBarrier:

    Runnable barrier1Action = new Runnable() {
        public void run() {
            System.out.println("BarrierAction 1 executed ");
        }
    };
    Runnable barrier2Action = new Runnable() {
        public void run() {
            System.out.println("BarrierAction 2 executed ");
        }
    };
     
    CyclicBarrier barrier1 = new CyclicBarrier(2, barrier1Action);
    CyclicBarrier barrier2 = new CyclicBarrier(2, barrier2Action);
     
    CyclicBarrierRunnable barrierRunnable1 =
            new CyclicBarrierRunnable(barrier1, barrier2);
     
    CyclicBarrierRunnable barrierRunnable2 =
            new CyclicBarrierRunnable(barrier1, barrier2);
     
    new Thread(barrierRunnable1).start();
    new Thread(barrierRunnable2).start();
    

    CyclicBarrierRunnable 类:

    public class CyclicBarrierRunnable implements Runnable{
     
        CyclicBarrier barrier1 = null;
        CyclicBarrier barrier2 = null;
     
        public CyclicBarrierRunnable(
                CyclicBarrier barrier1,
                CyclicBarrier barrier2) {
     
            this.barrier1 = barrier1;
            this.barrier2 = barrier2;
        }
     
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() +
                                    " waiting at barrier 1");
                this.barrier1.await();
     
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() +
                                    " waiting at barrier 2");
                this.barrier2.await();
     
                System.out.println(Thread.currentThread().getName() +
                                    " done!");
     
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
    

    以上代码控制台输出如下。注意每个线程写入控制台的时序可能会跟你实际执行不一样。比如有时 Thread-0 先打印,有时

    Thread-1 先打印。
    Thread-0 waiting at barrier 1
    Thread-1 waiting at barrier 1
    BarrierAction 1 executed
    Thread-1 waiting at barrier 2
    Thread-0 waiting at barrier 2
    BarrierAction 2 executed
    Thread-0 done!
    Thread-1 done!
    

    相关文章

      网友评论

        本文标题:【java】并发-同步器

        本文链接:https://www.haomeiwen.com/subject/wjqvcltx.html