目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

并发工具类

CountDownLatch

 创建 CountDownLatch 实例的时候需要传入线程数,await()操作进入等待状态,每个线程执行完毕调用 countDown(),计数器减一,当计数器为 0 的时候处于 WAITING 状态的线程会被唤醒。
 应用场景:启动三个线程计算,需要每个线程的计算结果进行累加。
CountDownLatch

 1import java.util.concurrent.CountDownLatch;
 2
 3public class CountDownLatchDemo {
 4    public static void main(String[] args) {
 5        CountDownLatch countDownLatch = new CountDownLatch(8);
 6
 7        for (int i = 0; i < 8; i++) {
 8            int finalI = i;
 9            new Thread(()->{
10                try {
11                    Thread.sleep(finalI * 1000L);
12                    System.out.println(Thread.currentThread().getName()+"到达终点");
13                } catch (InterruptedException e) {
14                    e.printStackTrace();
15                } finally {
16                    //无论是否发生异常,每个线程都会调用countDown(),计数器减1.
17                    countDownLatch.countDown();
18                }
19            }).start();
20        }
21
22        new Thread(()->{
23            try {
24                //计数器挂起
25                countDownLatch.await();
26            } catch (InterruptedException e) {
27                e.printStackTrace();
28            }
29            System.out.println("800米比赛结束,准备清空跑道并继续跨栏比赛");
30        }).start();
31        
32    }
33}

CyclicBarrier--栅栏

 允许一组线程相互等待达到一个公共的障碍点,之后再继续执行。

CyclicBarrier 跟 countDownLatch 的区别

  • CountDownLatch 一般用于某个线程等待若干个其他线程执行完任务之后,它才执行;不可重复使用 ​
  • CountDownLatch 一般用于某个线程等待若干个其他线程执行完任务之后,它才执行;不可重复使用 ​
    CyclicBarrier
 1import java.util.concurrent.BrokenBarrierException;
 2import java.util.concurrent.CyclicBarrier;
 3
 4public class CyclicBarrierDemo {
 5
 6    public static void main(String[] args) {
 7        CyclicBarrier cyclicBarrier = new CyclicBarrier(8);
 8
 9        for (int i = 0; i < 8; i++) {
10            int finalI = i;
11            new Thread(() -> {
12
13                try {
14                    Thread.sleep(finalI * 1000L);
15                    System.out.println(Thread.currentThread().getName() + "准备就绪");
16                    //相当于计数器加1,当所有线程await()数量累加到指定数量,则会被同时唤醒
17                    cyclicBarrier.await();
18                } catch (InterruptedException e) {
19                    e.printStackTrace();
20                } catch (BrokenBarrierException e) {
21                    e.printStackTrace();
22                }
23                System.out.println("开始比赛");
24            }).start();
25        }
26    }
27}

Semaphore--信号量

  • 控制并发数量
  • 使用场景:接口限流

Semaphore

 1import java.util.concurrent.Semaphore;
 2
 3public class SemaphoreDemo {
 4
 5    public static void main(String[] args) {
 6        Semaphore semaphore = new Semaphore(2);
 7
 8        for (int i = 0; i < 10; i++) {
 9            new Thread(()->{
10                try {
11		    //获取一个信号量,信号量池中减1
12                    semaphore.acquire();
13                    System.out.println(Thread.currentThread().getName() + "开始执行");
14                    Thread.sleep(5000L);
15                } catch (InterruptedException e) {
16                    e.printStackTrace();
17                } finally {
18		    //归还一个信号量,信号量池加1,防御信号量池中,以便后续的线程可以获取信号量
19                    semaphore.release();
20                }
21            }).start();
22        }
23    }
24}

Exchanger

 用于交换数据。
 它提供一个同步点,在这个同步点两个线程可以交换彼此的数据。这两个线程通过 exchange 方法交换数据, 如果第一个线程先执行 exchange 方法,它会一直等待第二个线程也执行 exchange,当两个线程都到达同步点时,这两个线程就可以交换数据,将本线程生产出来的数据传递给对方。因此使用 Exchanger 的重点是成对的线程使用 exchange()方法,当有一对线程达到了同步点,就会进行交换数据。因此该工具类的线程对象是【成对】的。
ExchangerDemo

 1import java.util.concurrent.Exchanger;
 2
 3public class ExchangerDemo {
 4
 5    public static void main(String[] args) {
 6        Exchanger<String> stringExchanger = new Exchanger<>();
 7
 8        String str1 = "test1";
 9        String str2 = "test2";
10        
11        //线程对象是成对出现的
12        new Thread(() -> {
13            System.out.println(Thread.currentThread().getName() + "初始值==========>" + str1);
14            try {
15                String exchange = stringExchanger.exchange(str1);
16                System.out.println(Thread.currentThread().getName() + "交換后的数据==========>" + exchange);
17            } catch (InterruptedException e) {
18                e.printStackTrace();
19            }
20        }, "线程1").start();
21
22        new Thread(() -> {
23            System.out.println(Thread.currentThread().getName() + "初始值==========>" + str2);
24            try {
25                String exchange = stringExchanger.exchange(str2);
26                System.out.println(Thread.currentThread().getName() + "交換后的数据==========>" + exchange);
27            } catch (InterruptedException e) {
28                e.printStackTrace();
29            }
30        }, "线程2").start();
31
32        //单个出现的线程是无法交换数据的
33        new Thread(() -> {
34            System.out.println(Thread.currentThread().getName() + "初始值==========>" + str2);
35            try {
36                String exchange = stringExchanger.exchange(str2);
37                System.out.println(Thread.currentThread().getName() + "交換后的数据==========>" + exchange);
38            } catch (InterruptedException e) {
39                e.printStackTrace();
40            }
41        }, "线程3").start();
42    }
43}

输出结果

1线程1初始值==========>test1
2线程2初始值==========>test2
3线程1交換后的数据==========>test2
4线程2交換后的数据==========>test1
5线程3初始值==========>test2

作者:Soulboy