一、概念
Semaphore是一个计数信号量,常用于限制可以访问某些资源(物理或逻辑的)线程数目。
一个信号量有且仅有3种操作,且它们全部是原子的:初始化、增加和减少
增加可以为一个进程解除阻塞;
减少可以让一个进程进入阻塞。
和线程池的区别:使用Seamphore,创建了多少线程,实际就会有多少线程进行执行,只是可同时执行的线程数量会受到限制。但使用线程池,不管你创建多少线程,实际可执行的线程数是一定的。
二、方法
1 构造方法:
Semaphore(int)、Semaphore(int,boolean)
int表示该信号量拥有的许可数量
boolean表示获取许可的时候是否是公平的。(公平指的是先来的先执行)
2 获取许可
acquire()、acquire(int)、tryAcquire()
int参数表示一次性要获取几个许可,默认为1个,acquire方法在没有许可的情况下,要获取许可的线程会阻塞。
tryAcquire()方法在没有许可的情况下会立即返回 false,要获取许可的线程不会阻塞。
3 释放许可
release()、release(int)
int参数表示一次性要释放几个许可,默认为1个,
注意一个线程调用release()之前并不要求一定要调用了acquire因此如果释放的比获取的信号量还多,例如获取了2个,释放了5次,那么当前信号量就动态的增加为5了(实现动态增加)
4 当前可用的许可数
int availablePermits()
三、测试
public void testSemaphore() { // 线程池 ExecutorService exec = Executors.newCachedThreadPool(); // 只能5个线程同时访问 final Semaphore semp = new Semaphore( 2 ); // 模拟20个客户端访问 for ( int index = 0 ; index < 5 ; index++) { final int NO = index; Runnable run = new Runnable() { @Override public void run() { try { if (semp.availablePermits() > 0 ) { System.out.println( NO + "线程启动" ); } else { System.out.println(NO + "线程启动,排队等待" ); } // 获取许可 semp.acquire(); System.out.println(NO + "线程执行" ); //模拟实际业务逻辑 Thread.sleep(( long ) (Math.random() * 10000 )); // 访问完后,释放 semp.release(); System.out.println(NO + "线程释放" ); } catch (InterruptedException e) { } } }; exec.execute(run); } try { Thread.sleep( 10 ); } catch (InterruptedException e) { e.printStackTrace(); } //System.out.println(semp.getQueueLength()); // 退出线程池 exec.shutdown(); } |
0线程启动
0线程执行
1线程启动
1线程执行
2线程启动,排队等待
3线程启动,排队等待
4线程启动,排队等待
2线程执行
0线程释放
1线程释放
3线程执行
2线程释放
4线程执行
3线程释放
4线程释放