1.CountDownLatch

让一些线程阻塞直到另一些线程完成一系列操作后才被唤醒。
CountDownLatch主要有两个方法,当一个或多个线程调用await()方法时,调用线程会被阻塞。其它线程调用countDown()方法会将计数器减1(调用countDown方法的线程不会阻塞),当计数器的值变为零时,因调用await方法被阻塞的线程会被唤醒,继续执行。
示例代码:

public class CountDownLatchDemo {

    public static void main(String[] args) {
        int size = 10;
        CountDownLatch countDownLatch = new CountDownLatch(size);
        for (int i = 1; i <= size; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 离开教室");
                //做减法
                countDownLatch.countDown();
            }, i + "").start();
        }
        try {
            //阻塞等到countDownLatch为0
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println(Thread.currentThread().getName() + "\t 班长锁门");
    }
}

运行结果:

1	 离开教室
4	 离开教室
3	 离开教室
2	 离开教室
6	 离开教室
5	 离开教室
7	 离开教室
8	 离开教室
9	 离开教室
10	 离开教室
main	 班长锁门

2.CyclicBarrier

CyclicBarrier的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活,线程进入屏障通过CyclicBarrier的await()方法。
示例代码:

public class CyclicBarrierDemo {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(7, () -> {
            System.out.println("集齐7颗龙珠 开始召唤神龙");
        });

        for (int i = 1; i <= 7; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + "\t 号龙珠准备好了");
                try {
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 号龙珠启动");
            }, i + "").start();
        }
    }
}

运行结果:

1	 号龙珠准备好了
5	 号龙珠准备好了
4	 号龙珠准备好了
3	 号龙珠准备好了
2	 号龙珠准备好了
7	 号龙珠准备好了
6	 号龙珠准备好了
集齐7颗龙珠 开始召唤神龙
6	 号龙珠启动
4	 号龙珠启动
7	 号龙珠启动
2	 号龙珠启动
3	 号龙珠启动
5	 号龙珠启动
1	 号龙珠启动

3.Semaphore

信号量主要用于两个目的,一个是用于多个共享资源的互斥作用,另外一个用于并发线程数的控制。
示例代码:

public class SemaphoreDemo {

    public static void main(String[] args) {

        //模拟三个车位
        Semaphore semaphore = new Semaphore(3);

        //控制6辆车同时抢车位
        CountDownLatch countDownLatch = new CountDownLatch(6);

        //模拟6辆车抢车位
        for (int i = 1; i <= 6; i++) {
            new Thread(() -> {
                countDownLatch.countDown();
                try {
                    countDownLatch.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t 开始抢车位");
                try {
                    semaphore.acquire();
                    System.out.println(Thread.currentThread().getName() + "\t 抢到车位");
                    TimeUnit.SECONDS.sleep(3);
                    System.out.println(Thread.currentThread().getName() + "\t 停车3秒离开");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphore.release();
                }
            }, i + "").start();
        }
    }
}

运行结果:

1	 开始抢车位
3	 开始抢车位
5	 开始抢车位
4	 开始抢车位
6	 开始抢车位
2	 开始抢车位
5	 抢到车位
3	 抢到车位
1	 抢到车位
3	 停车3秒离开
1	 停车3秒离开
4	 抢到车位
5	 停车3秒离开
6	 抢到车位
2	 抢到车位
4	 停车3秒离开
6	 停车3秒离开
2	 停车3秒离开
posted on 2021-03-18 10:50  whn051799  阅读(60)  评论(0编辑  收藏  举报