一、概念
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线程释放