Java 标准库 API 系列之 Semaphore
Semaphore是一种经典的同步工具,用于控制并发线程数,它可以保证在同一时间内只有一定数量的线程能够访问某个资源,从而避免线程间的竞争和冲突。
Semaphore有两个核心概念:
- 许可证(Permit):表示可用的访问权限数量,
Semaphore
内部维护了一个许可证池,初始时可以设置许可证的数量。 - 信号量(Semaphore):表示一个计数器,当线程想要访问某个资源时,必须先从
Semaphore
中获取一个许可证,然后才能访问资源;当线程使用完资源后,必须释放许可证,以便其他线程可以访问资源。
Semaphore
的使用方式如下:
- 创建
Semaphore
对象,指定许可证数量。 - 在需要访问共享资源的线程中,调用
acquire()
方法获取许可证。 - 线程使用共享资源。
- 在共享资源使用完毕后,调用
release()
方法释放许可证。
听起来有点像操作系统里面信号量的概念,其实本质是一样的,不过操作系统层面的信号量是作用于进程与进程之间的同步,java里面的信号量是线程与线程之间的同步。
下面是一个简单的示例代码,使用Semaphore
控制了同时执行的线程数目:
import java.util.concurrent.Semaphore;
public class SemaphoreExample {
public static void main(String[] args) throws InterruptedException {
Semaphore semaphore = new Semaphore(3); // 许可证数量为3
// 创建10个线程
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
semaphore.acquire(); // 获取许可证
System.out.println(Thread.currentThread().getName() + " acquire semaphore");
Thread.sleep(2000); // 模拟使用共享资源的时间
semaphore.release(); // 释放许可证
System.out.println(Thread.currentThread().getName() + " release semaphore");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
}
在上面的示例中,创建了10个线程,但是许可证数量只有3个,因此同时最多只能有3个线程获取许可证,其他线程需要等待。每个线程获取到许可证后,会打印一条日志,表示成功获取许可证,然后等待2秒,模拟使用共享资源的时间,使用完资源后,会打印一条日志,表示成功释放许可证。
总之,Semaphore是一种非常常用的同步工具,可以用于控制并发线程数,防止线程间的竞争和冲突,它的使用方式简单明了,非常适合于多线程编程。
它和锁的区别呢
Semaphore和锁(比如ReentrantLock
)的区别在于,锁通常只允许一个线程同时访问共享资源,而Semaphore可以控制同时访问共享资源的线程数量,即可以允许多个线程同时访问。
另外,Semaphore的许可证数量是可以动态调整的,而锁的访问数量是固定的。Semaphore可以用于实现资源池等场景,而锁则更适用于互斥访问共享资源的场景。
使用场景
Semaphore
的主要应用场景是控制并发访问某些共享资源的线程数量,通常用于限流和保护资源。
例如,假设有一个公共资源,比如数据库连接池、线程池等,由于该资源的数量是有限的,为了防止过多的线程同时访问该资源导致资源竞争和性能下降,可以使用Semaphore
来控制并发线程的数量。另外,Semaphore
也可以用于限制并发请求的数量,避免服务器过载。
另外,Semaphore
还可以用于实现生产者-消费者模型,其中生产者和消费者之间需要进行同步和协作,以避免出现数据竞争或者生产者和消费者之间的阻塞情况。Semaphore
可以用来控制生产者和消费者的访问数量,以保证生产者和消费者之间的同步和协作。
-
java
膜拜G佬每一天