Semaphore 计数信号量限制资源访问的线程数目
目录
Semaphore 概述
public class java.util.concurrent.Semaphore implements java.io.Serializable {
1、JDK1.5 提供的 Semaphone 计数信号量维护了一个许可证集,线程中调用 acquire() 方法从 Semaphone 中获取许可证,得到了许可证,Semaphone 的许可证数减1,线程继续向后运行,未得到许可证时,线程一直阻塞在 acquire()。
2、线程中获得许可执行完毕后,使用 release() 方法归还许可证到 Semaphone,Semaphone 的许可证数加1,此时其余阻塞在 acquire() 的线程便可以获取其它线程归还的许可证后继续执行。
3、Semaphore 只对可用许可的号码进行计数,并采取相应的行动,信号量常常用于多线程的代码中,限制访问某些资源(物理或逻辑的)的线程数目,比如数据库连接池。
4、因为 Semaphone 的许可证数量是固定的,所以同一时刻最多只能有 Semaphone 许可证同等数量的线程访问,其余线程访问时必须等待已经拿到许可证的线程执行完毕(执行完毕的线程要归还许可证)。
常用方法
构造方法摘要 | ||
---|---|---|
Semaphore(int permits) |
创建具有给定的许可数和非公平的公平设置的 Semaphore 。 |
|
Semaphore(int permits, boolean fair) |
创建具有给定的许可数和给定的公平设置的 Semaphore 。 |
方法摘要 | |
---|---|
acquire() |
从此信号量获取一个许可,在提供一个许可前一直将线程阻塞,否则线程被中断。 获取一个许可(如果提供了一个)并立即返回,将可用的许可数减 1。 |
acquire(int permits) |
从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞,或者线程已被中断。 |
availablePermits() |
返回此信号量中当前可用的许可数。 |
drainPermits() |
获取并返回立即可用的所有许可。 |
release() |
释放一个许可,将其返回给信号量。 |
release(int permits) |
释放给定数目的许可,将其返回到信号量。 |
toString() |
返回标识此信号量的字符串,以及信号量的状态。 |
tryAcquire(long timeout, TimeUnit unit) |
如果在给定的等待时间内,此信号量有可用的许可并且当前线程未被中断,则从此信号量获取一个许可。 |
使用示例
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
public class Test {
public static void main(String[] args) throws InterruptedException {
//创建具有给定的许可数和非公平的公平设置的 Semaphore(计数信号量)
Semaphore semaphore = new Semaphore(3);
//使用线程池创建多个线程执行
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 6; i++) {
executorService.execute(new MyThread(semaphore));//计数信号量作为参数传入
}
}
}
class MyThread extends Thread {
private static Logger logger = Logger.getAnonymousLogger();//日志记录器
private Semaphore semaphore;//计数信号量作为参数传入
public MyThread(Semaphore semaphore) {
this.semaphore = semaphore;
}
@Override
public void run() {
try {
logger.info("线程 " + currentThread().getName() + " 准备获取许可证数,当前共有:" + semaphore.availablePermits());
/**
* acquire:从此计数信号量中获取一个许可证,在获得许可之前,此线程将一直阻塞,或者线程被中断。
* 获取许可证后,semaphore 中可用的许可数减会 1
*/
semaphore.acquire();
logger.info("线程 " + currentThread().getName() + " 获得许可证,剩余许可证数:" + semaphore.availablePermits());
Thread.sleep(2000 + new Random().nextInt(3000));//模拟线程在执行任务
/**
* release:当前线程释放许可证,将其返回给计数信号量
* 释放许可证后,semaphore 中可用的许可数增加 1。如果任意线程试图获取许可,则选中一个线程并将刚刚释放的许可给予它。然后针对线程安排目的启用(或再启用)该线程。
* 线程执行完成后一定要记得归还许可证,否则 Semaphore 的许可证用完之后,其它线程会一直阻塞在 acquire()
*/
semaphore.release();
logger.info("线程 " + currentThread().getName() + " 执行完毕,归还许可证,剩余许可证数:" + semaphore.availablePermits());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
完整输出内容如下:
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 获得许可证,剩余许可证数:2
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 准备获取许可证数,当前共有:3
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:47 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 获得许可证,剩余许可证数:1
三月 11, 2019 4:34:51 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-3 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:51 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-1 执行完毕,归还许可证,剩余许可证数:0
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-2 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:52 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 获得许可证,剩余许可证数:0
三月 11, 2019 4:34:53 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-4 执行完毕,归还许可证,剩余许可证数:1
三月 11, 2019 4:34:56 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-5 执行完毕,归还许可证,剩余许可证数:2
三月 11, 2019 4:34:57 下午 com.xyjt.test.MyThread run
信息: 线程 pool-1-thread-6 执行完毕,归还许可证,剩余许可证数:3