juc包下四大并发工具
juc.CountDownLatch 闭锁
一个线程在等待一组线程后再恢复执行
await()等待其他线程执行完毕
被等待线程执行完毕后计数器-1
如何知道其他线程执行完了?
计数器,若一组线程为,CountDown为5,减到0代表等待线程被全部执行完毕
一次性工具:当Countdown的值减到0的时候再也无法恢复
juc内部的代码都是lock体系来实现的
import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; // 运动员线程 class CDLTask implements Runnable { private CountDownLatch countDownLatch; public CDLTask(CountDownLatch countDownLatch) { this.countDownLatch = countDownLatch; } @Override public void run() { System.out.println(Thread.currentThread().getName()+"开始跑步"); try { TimeUnit.SECONDS.sleep(1); System.out.println(Thread.currentThread().getName()+"到达终点"); countDownLatch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); } } } public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(4); CDLTask cdlTask = new CDLTask(countDownLatch); System.out.println("比赛开始..."); new Thread(cdlTask,"运动员A").start(); new Thread(cdlTask,"运动员B").start(); new Thread(cdlTask,"运动员C").start(); new Thread(cdlTask,"运动员D").start(); // 等待所有线程都到达终点后再输出此语句 countDownLatch.await(); System.out.println("比赛结束..."); } }
juc.CyclicBarrier 循环栅栏
一组线程同时到达临界点后再恢复执行(先到达临界点的线程会阻塞,直到所有线程都到达临界点)
public CyclicBarrier(int parties, Runnable barrierAction)
当多个线程同时到达临界点时,
随机挑选一个线程执行barrierAction后再同时恢复执行
计数器的值可以恢复
await
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; class CBTask implements Runnable { private CyclicBarrier cyclicBarrier; public CBTask(CyclicBarrier cyclicBarrier) { this.cyclicBarrier = cyclicBarrier; } @Override public void run() { System.out.println(Thread.currentThread().getName()+ "正在写入数据..."); try { TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread().getName()+ "写入数据完毕,等待其他线程写入完毕..."); cyclicBarrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println("所有线程均已写入完毕,继续恢复执行..."); } } class CyclicBarrierDemo { public static void main(String[] args) { CyclicBarrier cyclicBarrier = new CyclicBarrier(4 ,() -> { System.out.println("当前线程为:"+Thread.currentThread().getName()); }); CBTask cbTask = new CBTask(cyclicBarrier); for (int i = 0; i < 4; i++) { new Thread(cbTask,"写线程"+(i+1)).start(); } } }
juc.Exchanger 线程交换器
用于两个线程直线的数据交换,当Exchanger只有一个线程时,该线程会阻塞直到有别的线程
调用exchange进入缓冲区,当前线程与新线程交换数据后同时恢复执行。
import java.util.concurrent.Exchanger; import java.util.concurrent.TimeUnit; class ExchangerDemo { public static void main(String[] args) { Exchanger<String> exchanger = new Exchanger<>(); Thread girlThread = new Thread(() -> { try { String girl = exchanger.exchange("我喜欢你....."); System.out.println("女生说:"+girl); } catch (InterruptedException e) { e.printStackTrace(); } }); girlThread.start(); Thread boyThread = new Thread(() -> { System.out.println("女神缓缓步入眼帘..."); try { TimeUnit.SECONDS.sleep(1); String boy = exchanger.exchange("我喜欢你!"); System.out.println("男生说:"+boy); } catch (InterruptedException e) { e.printStackTrace(); } }); boyThread.start(); } }
juc.Semaphore 信号量
acquire() : 尝试占用一个信号量,失败的线程会阻塞直到有新的信号量
release() : 释放一个信号量
acquire(int n) : 尝试占用n个信号量,失败的线程会阻塞直到有新的信号量
release(int n) : 释放n个信号量
import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; class SemaphoreTask implements Runnable { private Semaphore semaphore; public SemaphoreTask(Semaphore semaphore) { this.semaphore = semaphore; } @Override public void run() { try { semaphore.acquire(2); System.out.println(Thread.currentThread() .getName()+"占用2台设备生产"); TimeUnit.SECONDS.sleep(2); System.out.println(Thread.currentThread() .getName()+"生产完毕,释放设备"); semaphore.release(2); } catch (InterruptedException e) { e.printStackTrace(); } } } class SemaphoreDemo { public static void main(String[] args) { Semaphore semaphore = new Semaphore(5); SemaphoreTask task = new SemaphoreTask(semaphore); for (int i = 0; i < 8; i++) { new Thread(task,"工人"+(i+1)).start(); } } }
这里有一篇比较好的博客关于cyclicbarrier和countdownlatch的区别: