Semaphore
(信号量)是一种常用的并发控制技术,用于管理对一组资源的访问控制。信号量的核心是一个计数器,表示可用资源的数量。计数器的值可以初始化为任意值,如果初始化为1,则成为一个互斥锁(Mutex)。信号量提供了两个主要方法,acquire()
(获取)和release()
(释放),用于线程间的同步控制。
工作原理
-
acquire():
- 当线程尝试通过
acquire()
方法获取资源时,信号量的计数器会减1。 - 如果计数器的值大于等于0,说明资源可用,线程可以继续执行。
- 如果计数器的值小于0,则说明资源不足,线程会被阻塞,直到有其他线程释放资源。
- 当线程尝试通过
-
release():
- 线程通过调用
release()
方法来释放它持有的资源,这会使信号量的计数器加1。 - 如果有线程因为资源不足而被阻塞,释放资源后,这些线程中的一个或多个(取决于释放的资源数量和信号量的公平性策略)会被唤醒,尝试再次获取资源。
- 线程通过调用
公平性
Semaphore
支持两种公平性策略:公平模式和非公平模式。- 在公平模式下,线程获取资源的顺序与它们请求访问的顺序相同,能够防止线程饿死(即无限期等待)。
- 在非公平模式下,请求访问的顺序并不保证线程获取资源的顺序,这可能导致某些线程较快获取资源,而其他线程等待时间较长。
用途
- 控制资源的并发访问:信号量常用于限制对资源的并发访问数,确保系统的稳定性和性能。
- 实现生产者-消费者模式:通过两个信号量控制生产者和消费者的同步,一个信号量控制可用资源数,另一个控制可用空间数。
- 线程同步:虽然
Semaphore
主要用于资源的并发控制,但也可以用作线程间的同步机制。
示例代码
下面是一个简单的Semaphore
使用示例,演示如何控制对某个资源的并发访问:
import java.util.concurrent.Semaphore;public class SemaphoreExample {private static final int MAX_PERMITS = 3;private final Semaphore semaphore = new Semaphore(MAX_PERMITS, true); // 公平模式public void accessResource() {try {semaphore.acquire(); // 尝试获取一个许可// 模拟访问共享资源System.out.println(Thread.currentThread().getName() + " is accessing the shared resource.");Thread.sleep(1000); // 模拟操作耗时} catch (InterruptedException e) {Thread.currentThread().interrupt();} finally {semaphore.release(); // 释放一个许可System.out.println(Thread.currentThread().getName() + " is releasing the shared resource.");}}public static void main(String[] args) {SemaphoreExample example = new SemaphoreExample();for (int i = 0; i < 10; i++) {new Thread(example::accessResource).start();}}
}
在这个示例中,我们创建了一个具有3个许可的Semaphore
,确保最多只有3个线程可以同时访问某个共享资源。每个线程在访问资源前需要通过acquire()
方法获取许可,完成后通过release()
方法释放许可。这种方式保证了资源的安全访问和高效利用。