CountDownLatch:它是一种同步工具,用于控制一个或多个线程等待其他线程完成操作后再继续执行。它的作用是让某个线程等待一组操作执行完成,再继续执行自己的任务。CountDownLatch 内部有一个计数器,当计数器的值为0时,等待的线程将会被唤醒。通过 CountDownLatch 的构造函数可以指定计数器的初始值,并通过 countDown() 方法递减计数器的值,通过 await() 方法使线程等待计数器达到0。
案例(模拟一个教室,里面有五个学生一个班长,当五个学生都离开教室后班长才能锁门):
public static void main(String[] args) { int numThreads = 5; CountDownLatch latch = new CountDownLatch(numThreads); // 创建并启动多个线程 for (int i = 0; i < numThreads; i++) { Thread thread = new Student(latch); //通过这样的方式将latch锁放到线程里 thread.start(); } try { // 主线程等待所有工作线程完成 latch.await(); System.out.println("班长锁门"); } catch (InterruptedException e) { e.printStackTrace(); } } static class Student extends Thread { private CountDownLatch latch; public Student(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+"同学离开教室"); } catch (InterruptedException e) { e.printStackTrace(); } finally { latch.countDown(); } } }
CyclicBarrier(循环栅栏):它也是一种同步工具,用于控制多个线程互相等待,直到所有线程都达到一个共同的屏障点,然后再一起继续执行后续操作。与 CountDownLatch 不同的是,CyclicBarrier 的计数器是可循环使用的,当计数器达到指定值时,所有等待的线程被释放,计数器会被重置。CyclicBarrier 的构造函数可以指定等待的线程数,并提供一个指定的动作(Runnable),该动作会在所有线程达到屏障点后执行。
其构造方法和使用案例类似于减少计数。
Semaphore(信号量):它是一种用来控制同时访问某个资源的线程数量的同步辅助类。Semaphore 内部维护了一组许可证(permit),线程在访问资源前需要先获取许可证,如果许可证数量为0,则需要等待其他线程释放许可证。当线程使用完资源后,需要释放许可证,以供其他等待线程使用。Semaphore 可以用来限制同时访问某个资源的线程数量,也可以作为一种计数器来统计通过某个点的线程数量。
案例:
private static final int MAX_CONCURRENT_THREADS = 5; private static Semaphore semaphore = new Semaphore(MAX_CONCURRENT_THREADS); public static void main(String[] args) { // 创建并启动多个访问线程 for (int i = 0; i < 10; i++) { Thread thread = new WorkerThread(i); thread.start(); } } static class WorkerThread extends Thread { private int threadIndex; public WorkerThread(int index) { this.threadIndex = index; } @Override public void run() { try { System.out.println("Thread " + threadIndex + " 正在等待许可证..."); semaphore.acquire(); System.out.println("Thread " + threadIndex + " 获取到许可证,开始访问资源"); // 模拟线程访问资源的耗时操作 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); System.out.println("Thread " + threadIndex + " 释放了许可证"); } } }
常用方法:
获取许可证:线程可以通过调用 acquire() 方法来请求一个许可证。如果有可用的许可证,则从计数器中减去一个许可证,并继续执行。如果没有可用的许可证,线程将被阻塞,直到有许可证可用或者线程被中断。
释放许可证:线程在使用完资源后,需要调用 release() 方法来释放许可证。该操作将会将计数器中的许可证数量加一,如果有其他线程在等待许可证,其中一个线程将会被唤醒并获取到许可证。
标签:JUC,Thread,许可证,计数器,线程,Semaphore,latch,CountDownLatch From: https://www.cnblogs.com/xialang/p/17743482.html