文章目录
- 一、概述
- 二、使用方法
- 三、测试示例
一、概述
-
Semaphore(信号量)是一种并发控制机制,用于控制对共享资源的访问。它维护了一个计数器,可以限制同时访问某个资源的线程数量。常用于限制同时访问某个资源的线程数量,例如控制数据库连接池的并发访问、控制线程池的并发任务数、生产者-消费者问题、读者-写者问题等。
-
使用 Semaphore ,就像银行取钱一样。假如银行有3个柜台,那么同一时刻最多就只能有3个人取钱,其他人需在等待区等待。当其中某个柜台的人走了以后,等待区的人才能有一个人到柜台办理取钱业务。从而实现限流,保证了柜台业务的正常运作,否则都挤过去就乱了。
-
Semaphore 有两个主要操作:acquire() 和 release()。
- acquire(): 当一个线程需要访问共享资源时,它可以调用 acquire() 方法。如果计数器大于0,那么线程将获得访问权限,并将计数器减1。如果计数器为0,那么线程将被阻塞,直到有其他线程释放资源并增加计数器。
- release(): 当一个线程完成对共享资源的访问时,它应该调用 release() 方法来释放资源并增加计数器的值。这将允许其他线程获取访问权限。
- tryAcquire():尝试获取一个许可证,如果获取成功返回 true,否则返回 false,不会阻塞线程。
-
注意:Semaphore 通常用来限流,即限制访问某个资源的线程数。而不是用于斥锁资源的访问,如果要用于斥锁资源的问题,则需把初始计数器设置为1。这时它变成了一个二元信号量,通常被称为互斥锁。只允许一个线程同时访问共享资源。
二、使用方法
-
使用 Semaphore 的方法如下:
- 声明一个 Semaphore 对象,初始化时指定 同时访问资源 的线程个数。
- 在业务开始部分使用 semaphore.acquire(); 领取许可证。
- 完成业务后使用 semaphore.release(); 还回许可证。
public class SemaphoreExample {private Semaphore semaphore = new Semaphore(5); // 允许同时访问资源的线程数量,这里设置为5,表示可以有5个线程同时访问public void accessResource() {try {semaphore.acquire(); // 获取许可证,如果有许可证,则计数器减1;如果没有可用许可证,则阻塞// 访问共享资源的代码} catch (InterruptedException e) {// 处理中断异常} finally {semaphore.release(); // 释放资源,计数器加1}} }
三、测试示例
-
在下面示例中,创建了一个 BankSemaphoreExample 类,模拟银行有5个柜台可以进行取钱业务。在主线程中创建100个线程,模拟100个富豪,然后一起去银行取钱。由于银行使用 Semaphore 限流,同一时刻只能有5个人取钱,其他人会排队等候。
package top.yiqifu.study.p004_thread;import java.util.ArrayList; import java.util.List; import java.util.concurrent.Semaphore;public class Test086_Semaphore {public static void main(String[] args) {BankSemaphoreExample bank = new BankSemaphoreExample();List<Thread> threads = new ArrayList();for(int i = 1; i<= 100; i++){Thread t = new Thread(()->{try {bank.getMoney(Thread.currentThread().getName());Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}});t.setName("富豪"+i);threads.add(t);}for(Thread t : threads){t.start();}for(Thread t : threads){try {t.join();} catch (InterruptedException e) {e.printStackTrace();}}}public static class BankSemaphoreExample {private volatile float Money = 1000 * 10000;private Semaphore semaphore = new Semaphore(5); // 假高银行有5个柜台synchronized void get(float m) {this.Money -= m;}public void getMoney(String people){try {semaphore.acquire();float m = (float) Math.random()* 10000;this.get(m);System.out.println(people+ " 取钱"+m+"元,还有排队富豪="+semaphore.getQueueLength());Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();} finally {semaphore.release();}}} }