本文共 3677 字,大约阅读时间需要 12 分钟。
一、CountDownLatch(闭锁),
* 概念:同步辅助类,构造函数传入计数count,调用await可以阻塞被调用的 * 当前线程,而在其他线程中调用countDown次数达到count时,那么await就停止阻塞,从而 * 达到了一个线程等待另外1个或多个线程执行完成的效果。public class CountDownLatchDemo { /** * 案例1)想达到的效果是一个主线程等待,其他count个数的线程执行完成。 * 缺点:在其他线程启动到await之间会存在其他线程已经运行点时间了,我们想要的效果是 * 其他线程一起启动。 */ public static void main1(String[] args) throws InterruptedException { int count = 10; CountDownLatch countDown = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":ok"); countDown.countDown(); // 执行count次, 阻塞1放行。 }; },"thread"+i).start(); } System.out.println("all start"); countDown.await(); // 阻塞1 System.out.println("all ok"); } /** * 案例2)改造版本:通过另外一个闭锁startCountDown,在线程轮流启动时,进行await(), * 在全部启动完,就进行startCountDown的countDown。 */ public static void main(String[] args) throws InterruptedException { int count = 10; CountDownLatch startCountDown = new CountDownLatch(1); CountDownLatch countDown = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(new Runnable() { @Override public void run() { // 轮流启动时,其他线程全部等待 try { startCountDown.await(); } catch (InterruptedException e1) { e1.printStackTrace(); } try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+":ok"); countDown.countDown(); // 执行count次, 阻塞1放行。 }; },"thread"+i).start(); } System.out.println("all start"); startCountDown.countDown(); countDown.await(); // 阻塞1 System.out.println("all ok"); } }
二、 CyclicBarrier
* 概述:CyclicBarrier(屏障),通过计数器传入构造函数,当其他线程调用await次数达到 * 计数器数目,就会全部唤醒,继续执行。public class CyclicBarrierDemo { /** * 如果注释打开,就是全部线程先打印"执行前",然后等待,最后await数量达到 * CyclicBarrier构造函数传入的计数,这些等待的线程就会继续执行,然后打印执行完。 */ public static void main(String[] args) { int count = 10; CyclicBarrier cb = new CyclicBarrier(count,()->{ System.out.println("唤醒一次"); }); for (int i = 0; i < count; i++) { new Thread(new Runnable() { @Override public void run() { System.out.println("执行前");// try {// cb.await();// } catch (InterruptedException e1) {// e1.printStackTrace();// } catch (BrokenBarrierException e1) {// e1.printStackTrace();// } System.out.println("执行完"); }; },"thread"+i).start(); } }}
三、Semaphore(信号量):
* Semaphore是用来控制同时访问特定资源的线程数量,它有2个方法acquire()获得许可, * release()释放许可,它构造方法可以传入线程数量,比如10个,而创建了30个线程调用 * 了acquire想获得许可,那么只能有10个成功。即此信号量下线程的并发是10个public class SemaphoreDemo { private static final int THREAD_COUNT = 30; private static Semaphore semaphore = new Semaphore(10); /** * 案例一: * 线程数量30个,实际上一次只有10个打印,当这10个线程释放时(必须调用release),那么就会运行另外10个。 */ public static void main1(String[] args) { for(int i = 0; i < THREAD_COUNT; i++) { final int index = i; new Thread(() -> { try { semaphore.acquire(); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前并发运行编号为: "+index); semaphore.release(); }).start(); }; } /** * 采用线程池改写上面的案例 */ public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); for(int i = 0; i < THREAD_COUNT; i++) { final int index = i; executor.execute(()->{ try { semaphore.acquire(); Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("当前并发运行编号为: "+index); semaphore.release(); }); }; executor.shutdown(); }}
转载地址:http://weuni.baihongyu.com/