Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

CountDownLatch

countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。

是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

CountDownLatch中的方法

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };   
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  
//将count值减1
public void countDown() { };  

CountDownLatchDemo

条件改为i<20时,并不会输出“完结撒花”,因为latch还没有减到0

import java.util.concurrent.CountDownLatch;

public class CountDownLatchDemo {
    public static void main(String[] args)  {
        CountDownLatch latch = new CountDownLatch(20);
        //条件改为i<20时,并不会输出“完结撒花”,因为latch还没有减到0
        for (int i = 0; i < 20; i++) {
            int index=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    latch.countDown();
                    System.out.println(index);
                }
            }).start();
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("完结撒花");
    }
}

CyclicBarrier

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

  • CountDownLatch 是一次性的,CyclicBarrier 是可循环利用的

构造方法

public CyclicBarrier(int parties)
public CyclicBarrier(int parties, Runnable barrierAction)
  • parties 是参与线程的个数
  • 第二个构造方法有一个 Runnable 参数,这个参数的意思是最后一个到达线程要做的任务

方法

public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit) throws InterruptedException, BrokenBarrierException, TimeoutException
  • 线程调用 await() 表示自己已经到达栅栏
  • BrokenBarrierException 表示栅栏已经被破坏,破坏的原因可能是其中一个线程 await() 时被中断或者超时

Demo

  • 初始化线程1,线程1睡眠3秒
  • 剩余九个线程到达barrier,但是并不会又输出
  • 三秒后线程1到达,9个线程开始输出
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierDemo {
    public static void main(String[] args) {
        CyclicBarrier barrier = new CyclicBarrier(10);
        //初始化线程1,线程1睡眠3秒,等待剩余九个线程到达barrier
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.currentThread().sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                try {
                    barrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
            }
        }).start();
        //九个线程先到达barrier
        for (int i = 0; i < 9; i++) {
            int index=i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        barrier.await();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } catch (BrokenBarrierException e) {
                        e.printStackTrace();
                    }
                    System.out.println(index);
                }
            }).start();
        }
    }
}
//Output,输出是随机的
/*
        0
        6
        2
        1
        8
        7
        4
        3
        5*/

Semaphore

Semaphore也是一个线程同步的辅助类,可以维护当前访问自身的线程个数,并提供了同步机制。使用Semaphore可以控制同时访问资源的线程个数,例如,实现一个文件允许的并发访问数。

常用方法

  void acquire():从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。

  void release():释放一个许可,将其返回给信号量。

  int availablePermits():返回此信号量中当前可用的许可数。

  boolean hasQueuedThreads():查询是否有线程正在等待获取。

Demo

  • 六个人竞争三个办事窗口,每个办事窗口只能容纳三个人,输出如下
package ConcurrentApi;

import java.util.concurrent.Semaphore;
//Output
/*
    线程0等到了办事窗口空闲
            办事窗口剩余量2
    线程1等到了办事窗口空闲
            办事窗口剩余量1
    线程2等到了办事窗口空闲
            办事窗口剩余量0
    线程3等到了办事窗口空闲
            办事窗口剩余量0
    线程4等到了办事窗口空闲
            办事窗口剩余量0
    线程5等到了办事窗口空闲
            办事窗口剩余量0*/
public class SemaphoreDemo {
    public static void main(String[] args) {
        //初始化3 三个办事窗口
        Semaphore semaphore = new Semaphore(3);
        for (int i = 0; i < 6; i++) {
            int index = i;
            try {
                Thread.currentThread().sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        semaphore.acquire();
                        System.out.println("线程"+index+"等到了办事窗口空闲");
                        System.out.println("办事窗口剩余量"+semaphore.availablePermits());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    try {
                        Thread.currentThread().sleep(4000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    semaphore.release();
                }
            }).start();
        }
    }
}
posted @ 2021-08-27 17:14  aixueforever  阅读(518)  评论(0编辑  收藏  举报