一、Semaphore(信号量)
注解:信号量,其实就是定义一定的数量,只有释放一个才能进去下一个,其余都得进入等待状态。比如有2个洗手间,有5个人要上洗手间,这时候只能有2个人先使用(也就是acquire),其余人只能等着。等到其中一人使用完成(也就是release),下一个人才能使用。
//定义一个信号量有2个位置 Semaphore semaphore = new Semaphore(2); @RequestMapping("thread") public int test() { //多开几个线程 for (int i = 0; i < 5; i++) { //练习下信号量 new Thread(() -> { try { //判断有无当前信号量位置 if (semaphore.availablePermits() > 0) { System.out.println(Thread.currentThread().getName() + "有当前信号量位置"); } else { System.out.println(Thread.currentThread().getName() + "有当前信号量无位置,进入等待"); } semaphore.acquire(); System.out.println(Thread.currentThread().getName() + "已拿到当前信号量"); Thread.sleep(1000); semaphore.release(); System.out.println(Thread.currentThread().getName() + "已释放当前信号量"); } catch (Exception ex) { } }).start(); } return 0; }
二、CyclicBarrier(屏障器)
注解:这个屏障就是相当于挡住一部分线程,当达到屏障点后,被挡住的这部分线程被放行。比如你要坐轮船,一个轮船坐2个人,只有一个人的时候得等待另一个人的到来,当另一个人来的时候,你们2个就可以被放行了。接着继续进入下一批次的等待中。比较好奇线程安全问题,翻了下源码,多虑了,没事多翻翻源码还是很不错的。也可以看出来底层是通过Condition来实现线程等待和线程唤醒的。
//定义一个线程屏障 CyclicBarrier barrier = new CyclicBarrier(2); @RequestMapping("thread") public int test() { //多开几个线程 for (int i = 0; i < 5; i++) { //每个线程等一会再发起 try { Thread.sleep(3000); } catch (Exception ex) {} new Thread(() -> { try { System.out.println(Thread.currentThread().getName() + "已到达屏障"); barrier.await(); System.out.println(Thread.currentThread().getName() + "已穿过屏障"); } catch (Exception ex) {} }).start(); } return 0; }
三、Exchanger(交换器)
注解:交换器就是交换2个线程之间的数据,当只有一个线程发起,没有另一个就会进入循环状态,直到有一个线程也进行交换为止。比较简单调用下方法就知道了。可以添加超时时间。
String result = exchanger.exchange("我是A方法添加",3000, TimeUnit.MILLISECONDS);
//定义一个交换器 Exchanger<String> exchanger = new Exchanger(); //此方法往交换器内添加数据 @RequestMapping("/thread/a") public void a() throws Exception { String result = exchanger.exchange("我是A方法添加"); System.out.println("A方法添加交换器拿到的结果:" + result); } //此方法往交换器内添加数据 @RequestMapping("/thread/b") public void b() throws Exception { String result = exchanger.exchange("我是B方法添加"); System.out.println("B方法添加交换器拿到的结果:" + result); }
四、CountDownLatch(闭锁)
注解:这个东西和CyclicBarrier比较像,只是CyclicBarrier是循环的,每次放一定数的线程。CountDownLatch是等待到达指定数量线程然后放行,也就是使用await的线程可以继续执行。
CountDownLatch countDownLatch = new CountDownLatch(2); @RequestMapping("thread") public int test() { //多开几个线程 for (Integer i = 0; i < 5; i++) { int a = i + 1; new Thread(() -> { try { Thread.sleep(1000 * a); countDownLatch.countDown(); System.out.println(Thread.currentThread().getName() + "已执行完成"); } catch (Exception ex) { } }).start(); } try { countDownLatch.await(); System.out.println("主线程结束"); } catch (Exception ex) { } return 0; }