线程的并发工具类(4)---Semaphore
Semaphore的用法
- 1 .Semaphore介绍
- 1.1 用法场景
- 1.2 原理
- 2 .Semaphore使用
1 .Semaphore介绍
Semaphore:主要是用于流量控制。
作用:控制同时访问某个特定资源的线程数量,用于流量控制。
1.1 用法场景
最熟悉的场景就是数据库链接池的实现。在链接池的链接都被占用时,就会一直在等待憋的线程释放数据库链接资源,直到池中有可用链接。
1.2 原理
在初始化Semaphore实例的时候,同时会初始化许可证的数量N new Semaphore(N)。使用acquire()方法调用,调用成功后数量减1。当数量减为0时,会一直在acquire()这里等待,直到有可用许可证。使用完成后调用release()方法归还。
2 .Semaphore使用
Semaphore功能的实现主要是有两个方法配合acquire()和release()。acquire()是获取许可,release()是归还许可。
Semaphore有两种模式,公平模式和非公平模式。公平模式就是调用acquire的顺序就是获取许可证的顺序,遵循先进先出(FIFO);而非公平模式是抢占式的,也就是有可能一个新的获取线程恰好在一个许可证释放时得到了这个许可证,而前面还有等待的线程,默认是非公平模式。
两个构造方法Semaphore(int permits)和Semaphore(int permits, boolean fair)。permits为许可证数量,fair设置是否是先进先出。
看下具体实现:
SimulateCollection模拟一个数据库链接的实现。
import java.util.Collection;
import java.util.Iterator;
public class SimulateCollection implements Collection {
@Override
public int size() {
return 0;
}
...
}
UseSemaphore模拟一个数据库链接池的实现。
import java.util.LinkedList;
import java.util.concurrent.Semaphore;
/** * UseSemaphore:模拟数据库链接池的实现 */
public class UseSemaphore {
LinkedList<SimulateCollection> pool = new LinkedList<>();
private Semaphore useful;
private Semaphore already;
// public UseSemaphore(Semaphore useful,Semaphore already){
// this.useful = useful;
// this.already = already;
// }
public UseSemaphore(int linkNum) {
if(linkNum<=0){
linkNum=6;
}
this.useful = new Semaphore(linkNum);
this.already = new Semaphore(0);
}
//获取数据库链接
public SimulateCollection getCollection() throws InterruptedException {
useful.acquire();
SimulateCollection collection = null;
synchronized (pool) {
if (pool.size() > 0) {
collection = pool.removeFirst();
}
}
already.release();
return collection;
}
//释放数据库链接资源
public SimulateCollection releaseCollection(SimulateCollection collection) throws InterruptedException {
already.acquire();
synchronized (pool) {
if (collection != null) {
pool.addLast(collection);
}
}
useful.release();
return collection;
}
}
TestSemaPhore测试类:
public class TestSemaPhore implements Runnable {
private UseSemaphore useSemaphore;
public TestSemaPhore(UseSemaphore useSemaphore){
this.useSemaphore = useSemaphore;
}
@Override
public void run() {
try {
System.out.println("线程"+Thread.currentThread().getName()+"开始获取数据库链接");
long start = System.currentTimeMillis();
SimulateCollection simulateCollection = useSemaphore.getCollection();
long end = System.currentTimeMillis();
System.out.println("线程"+Thread.currentThread().getName()+"数据库链接获取成功,耗时"+(end-start)+"ms");
System.out.println("线程"+Thread.currentThread().getName()+"开始工作。。。");
Thread.sleep(500);
System.out.println("线程"+Thread.currentThread().getName()+"工作完成释放链接");
useSemaphore.releaseCollection(simulateCollection);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
TestSemaPhore testSemaPhore = new TestSemaPhore(new UseSemaphore(2));
for (int i=0;i<6;i++){
new Thread(testSemaPhore).start();
}
}
}
运行结果:
线程Thread-0开始获取数据库链接
线程Thread-1开始获取数据库链接
线程Thread-0数据库链接获取成功,耗时0ms
线程Thread-1数据库链接获取成功,耗时0ms
线程Thread-0开始工作。。。
线程Thread-1开始工作。。。
线程Thread-2开始获取数据库链接
线程Thread-3开始获取数据库链接
线程Thread-4开始获取数据库链接
线程Thread-5开始获取数据库链接
线程Thread-1工作完成释放链接
线程Thread-0工作完成释放链接
线程Thread-2数据库链接获取成功,耗时504ms
线程Thread-2开始工作。。。
线程Thread-3数据库链接获取成功,耗时504ms
线程Thread-3开始工作。。。
线程Thread-2工作完成释放链接
线程Thread-3工作完成释放链接
线程Thread-4数据库链接获取成功,耗时1005ms
线程Thread-4开始工作。。。
线程Thread-5数据库链接获取成功,耗时1005ms
线程Thread-5开始工作。。。
线程Thread-4工作完成释放链接
线程Thread-5工作完成释放链接
还没有评论,来说两句吧...