Semaphore、CountDownLatch和CyclicBarrier在Java中都是用于控制多线程执行的工具类,但它们各自有不同的使用场景和特性。
Semaphore(信号量)主要用于控制同时访问特定资源的线程数量。它允许一定数量的线程同时访问某个资源或资源池,通过获取和释放许可来协调各个线程的执行。Semaphore常用于实现如停车场提示牌功能等场景,确保资源得到合理的使用。
CountDownLatch是一个倒计时锁存器,它允许一个或多个线程等待其他线程完成操作。构造函数接收一个整数参数,表示计数的初始值。每当一个线程完成其任务后,计数减1,直到计数达到0,此时等待的线程会被唤醒并继续执行。CountDownLatch通常用于确保一组线程中的某些操作在所有线程都准备好之后再进行。
CyclicBarrier(循环屏障)则用于让一组线程互相等待,直到所有线程都到达某个公共屏障点。与CountDownLatch不同的是,CyclicBarrier的屏障可以在最后一次使用之后重置,因此它可以被循环使用。当所有线程都到达屏障点时,可以选择执行一个特定的操作,然后再继续执行。CyclicBarrier常用于需要所有线程都完成某个阶段的任务后才能进行下一阶段任务的场景。
总结来说,Semaphore、CountDownLatch和CyclicBarrier在控制多线程执行方面各有侧重。Semaphore关注资源的访问控制,CountDownLatch关注一组线程中某些操作的先后顺序,而CyclicBarrier则关注一组线程之间的相互等待和同步。根据具体需求,可以选择合适的工具类来实现多线程的协调和控制。
当然,下面我将用Java代码来展示Semaphore
、CountDownLatch
和CyclicBarrier
之间的区别。
首先是Semaphore
的示例,它用于限制同时访问某个资源的线程数:
java">import java.util.concurrent.Semaphore; public class SemaphoreExample { private static final int MAX_PERMITS = 3; // 允许同时访问的最大线程数 private static Semaphore semaphore = new Semaphore(MAX_PERMITS); public static void main(String[] args) { for (int i = 0; i < 5; i++) { new Thread(() -> { try { semaphore.acquire(); // 获取许可 System.out.println(Thread.currentThread().getName() + " 进入资源区"); // 模拟线程使用资源 Thread.sleep((long) (Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } finally { semaphore.release(); // 释放许可 System.out.println(Thread.currentThread().getName() + " 离开资源区"); } }).start(); } }
}
执行结果:
接下来是CountDownLatch
的示例,它用于等待一组线程完成某项操作:
java">import java.util.concurrent.CountDownLatch; public class CountDownLatchExample { private static final int THREAD_COUNT = 5; private static CountDownLatch countDownLatch = new CountDownLatch(THREAD_COUNT); public static void main(String[] args) throws InterruptedException { for (int i = 0; i < THREAD_COUNT; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 正在执行任务"); // 模拟任务执行 try { Thread.sleep((long) (Math.random() * 1000)); } catch (InterruptedException e) { e.printStackTrace(); } countDownLatch.countDown(); // 任务完成,计数器减一 }).start(); } countDownLatch.await(); // 等待所有线程完成任务 System.out.println("所有线程任务完成"); }
}
执行结果:
最后是CyclicBarrier
的示例,它用于一组线程互相等待,直到所有线程都到达某个屏障点:
java">import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier; public class CyclicBarrierExample { private static final int THREAD_COUNT = 5; private static CyclicBarrier cyclicBarrier = new CyclicBarrier(THREAD_COUNT, () -> { System.out.println("所有线程都到达了屏障点,可以执行额外的任务"); }); public static void main(String[] args) { for (int i = 0; i < THREAD_COUNT; i++) { new Thread(() -> { System.out.println(Thread.currentThread().getName() + " 准备到达屏障点"); try { cyclicBarrier.await(); // 等待所有线程到达屏障点 } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " 已经通过屏障点"); }).start(); } }
}
执行结果:
在这三个示例中,你可以看到它们各自的使用场景和特性:
Semaphore
用于限制同时访问资源的线程数,通过获取和释放许可来协调线程的执行。CountDownLatch
用于等待一组线程完成某项操作,通过计数器来确保所有线程都完成后再继续执行后续任务。CyclicBarrier
用于一组线程相互等待,直到所有线程都到达某个屏障点,之后可以一起执行某个任务或者进入下一阶段。
这些工具类在并发编程中非常有用,它们提供了不同的同步机制来协调和控制多线程的执行顺序。选择哪个工具类取决于具体的业务需求和应用场景。