一、概念
该同步器的作用是控制共享资源的最大可访问数量,或者定义最多允许多少个线程对共享资源同时进行访问。一个典型的运行就是实现池化机制,如对象池、连接池等。
二、代码示例
代码示例由三个类组成,分别为连接池列、连接对象类、测试类
(1) 连接池代码
import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;
/**
* 连接池
*/
public class ConnectPool {
//最大连接数
private final int max_num ;
//最小连接数
private final int min_num ;
//信号量线程同步器
private final Semaphore semaphore;
//可重入锁
private final ReentrantLock lock = new ReentrantLock();
//空闲的连接
private static final ConcurrentLinkedQueue<Connection> items = new ConcurrentLinkedQueue<>();
//单例
private static ConnectPool pool;
public ConnectPool(int maxNum, int minNum, long timeBetweenEvictionRunsMillis){
this.max_num = maxNum;
this.min_num = minNum;
//设置允许访问资源的最大数
this.semaphore = new Semaphore(max_num,true);
//初始化连接,数量为最小连接数
for (int i = 0; i < minNum; i++) {
items.offer(new Connection(this,i));
}
//定期检测超过最小连接数量的空闲连接,并释放掉
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
if(items.size()>min_num){
int num = items.size()-min_num;
for (int i = 0; i < num; i++) {
items.poll().release();//释放连接
}
}
} catch (Exception e) {//捕获异常并处理,避免因异常未捕获而不再定时执行此任务
e.printStackTrace();
}
}
},1000,timeBetweenEvictionRunsMillis, TimeUnit.MILLISECONDS);
}
/**
* 归还连接
* @param connection
*/
protected void returnItem(Connection connection){
connection.setUsed(false);
boolean flag = items.offer(connection);
if(!flag){
throw new RuntimeException("归还连接失败-num:"+connection.getNum());
}
//归还许可证
semaphore.release();
}
/**
* 获取连接
* @return
*/
public Connection getConnection(){
Connection connection = null;
try {
//获得许可证
semaphore.acquire();
lock.lock();//获取连接应保证是互斥锁,共享资源每次只能被一个线程读写
if(items.isEmpty()){
System.out.println("最小连接数的连接已取完");
Connection conn = new Connection(this,999);
boolean flag = items.offer(conn);
if(!flag){
conn.release();
throw new RuntimeException("创建连接失败");
}
}
connection = items.poll();
connection.setUsed(true);
System.out.println("已获取连接,序号为:"+connection.getNum());
} catch (InterruptedException e) {
System.out.println("超过最大许可");
e.printStackTrace();
}finally {
lock.unlock();
}
return connection;
}
}
(2) 连接对象代码
public class Connection {
private boolean isUsed = false;//是否已被使用
private int num; //连接的序号
public boolean isUsed() {
return isUsed;
}
private ConnectPool connectPool; //用于调用归还连接的方法
protected Connection(ConnectPool connectPool,int num){
this.connectPool = connectPool;
this.num = num;
}
public void setUsed(boolean used) {
isUsed = used;
}
public void close(){
System.out.println("归还连接-num:"+num);
connectPool.returnItem(this);
}
protected void release(){
System.out.println("释放连接-num:"+num);
}
public int getNum() {
return num;
}
}
(3) 测试类
import com.zhangzz.thread.aqs.chi.ConnectPool;
import com.zhangzz.thread.aqs.chi.Connection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ConnectTest implements Runnable{
ConnectPool pool = null;
public ConnectTest(){
pool = new ConnectPool(20,10,5000L);
}
public void run(){
Connection connection = null;
try {
connection = pool.getConnection();
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
connection.close();
}
}
public static void main(String[] args) {
ConnectTest test = new ConnectTest();
ExecutorService service = Executors.newFixedThreadPool(10);
for (int i=0;i<100;i++){
service.execute(test);
}
}
}