Semaphore(信号量)
是用来控制同时访问特定资源的线程数量,它通过协 调各个线程,以保证合理的使用公共资源。应用场景 Semaphore 可以用于做流 量控制,特别是公用资源有限的应用场景,比如数据库连接。假如有一个需求, 要读取几万个文件的数据,因为都是 IO 密集型任务,我们可以启动几十个线程 并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数 只有 10 个,这时我们必须控制只有 10 个线程同时获取数据库连接保存数据,否 则会报错无法获取数据库连接。这个时候,就可以使用 Semaphore 来做流量控制。
Semaphore 的构造方法 Semaphore(intpermits)接受一个整型的数字, 表示可用的许可证数量。Semaphore 的用法也很简单,首先线程使用 Semaphore的 acquire()方法获取一个许可证,使用完之后调用 release()方法归还许可证。还 可以用 tryAcquire()方法尝试获取许可证。
Semaphore 还提供一些其他方法,具体如下
•intavailablePermits():返回此信号量中当前可用的许可证数。
•intgetQueueLength():返回正在等待获取许可证的线程数。
•booleanhasQueuedThreads():是否有线程正在等待获取许可证。
•voidreducePermits(intreduction):减少 reduction 个许可证,是个 protected 方法。
•CollectiongetQueuedThreads():返回所有等待获取许可证的线程集合,是 个 protected 方法。

用Semaphore实现数据库连接池
/**
*类说明:演示Semaphore用法,一个数据库连接池的实现
*/
public class DBPoolSemaphore {
private final static int POOL_SIZE =10;
//两个指示器,分别表示池子还有可用连接和已用连接
private final Semaphoreuseful,useless;
//存放数据库连接的容器
private static LinkedListpool =new LinkedList();
//初始化池
static {
for (int i =0; i
pool.addLast(SqlConnectImpl.fetchConnection());
}
}
public DBPoolSemaphore() {
this.useful =new Semaphore(10);
this.useless =new Semaphore(0);
}
/*归还连接*/
public void returnConnect(Connection connection)throws InterruptedException {
if(connection!=null) {
System.out.println("当前有"+useful.getQueueLength()+"个线程等待数据库连接!!"
+"可用连接数:"+useful.availablePermits());
useless.acquire();
synchronized (pool) {
pool.addLast(connection);
}
useful.release();
}
}
/*从池子拿连接*/
public Connection takeConnect()throws InterruptedException {
useful.acquire();
Connection connection;
synchronized (pool) {
connection =pool.removeFirst();
}
useless.release();
return connection;
}
}
网友评论