转载出处:https://www.cnblogs.com/XHJT/p/3910406.html
信号量Semaphore
Semaphore 类是一个计数信号量,必须由获取它的线程释放,通常用于限制可以访问某些资源(物理或逻辑的)线程数目。
一个信号量有且仅有3种操作,且它们全部是原子的:初始化,增加和减少
- 增加可以为一个线程解除阻塞
- 减少可以为一个线程进入阻塞
信号量维护一个许可集,若有必要,会在获得许可之前阻塞每一个线程:
// 从此信号量获取给定数目的许可,在提供这些许可前一直将线程阻塞
acquireUninterruptibly(int permits){}
每一个release() 添加一个许可,从而可能释放一个正在阻塞的获取者。
Semaphore 只对许可的号码进行计数,并采取相应的行动。
如何获得Semaphore 对象
public Semaphore(int permits,boolean fair)
permits:初始化可用的许可数目
fair:若该信号量保证在征用时按 FIFO 的顺序授予许可,则为true,否则为false
如何从信号量获得许可
public void acquire() throws InterruptedException
如何释放一个许可,并返回信号量
public void release()
实例代码
package com.zhihua.subject;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
/**
* Semaphore信号灯
* @author caizh
*
*/
public class SemaphoreTest {
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final Semaphore semaphore = new Semaphore(3);// 3个许可证
for(int i=0;i<10;i++) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
} catch (Exception e) {
e.printStackTrace();
}
/*System.out.println("线程" + Thread.currentThread().getName() +
"进入,当前已有" + (3-semaphore.availablePermits()) + "个并发");*/
System.out.println("线程" + Thread.currentThread().getName() +
"进入,还剩" +semaphore.availablePermits() + "个许可证");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程" + Thread.currentThread().getName() +
"即将离开");
// 释放许可证
semaphore.release();
//下面代码有时候执行不准确,因为其没有和上面的代码合成原子单元
System.out.println("线程" + Thread.currentThread().getName() +
"已离开,还剩" +semaphore.availablePermits() + "个许可证");
}
};
service.execute(runnable);
}
service.shutdown();
}
}
面试题思考
在很多情况下,可能有多个线程需要访问数据吗很少的资源。假想在服务器上运行着若干个回答客户端请求的线程,
这些线程需要连接到同一数据库,但任意时刻只能获得一定数目的数据库连接。
你要怎样才能够有效地将这些固定数目的数据库连接分配给大量的线程?
答:1.给方法加同步锁,保证同一时刻只能有一个人去调用此方法,其他所有线程排队等候,
但是此中情况下即使你的数据库连接有10个,也始终只有一个处于使用状态。这样将会大大的浪费系统资源,
而且系统的运行效率非常的低下。
2.另外以何种方法当然是使用信号量,通过信号量许可与数据库可用连接数目相同的数目,将大大的提高效率和性能。