JUC
Semaphore
信号量,用来限制能同时访问共享资源的线程上限(单机限流)。单位时间内,只允许 设定数量的线程执行,超过数量的线程进入阻塞。等到执行中线程调用release()释放了资源,阻塞线程竞争资源继续执行。
Semaphore可以设置公平与非公平两种模式(默认非公平的),非公平模式在竞争Sempahore资源的时候不会判断等待队列是否有线程阻塞,公平模式则在acquire()方法中先判断等待队列中是否有阻塞线程,存在则排队到队列中。
使用例子:
public class SemaphoreTest {
public static void main(String[] args) {
//创建Semaphore对象
Semaphore semaphore = new Semaphore(3);
for(int i=0;i<10;i++){
new Thread(()->{
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
log.info("running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("end...");
} finally {
semaphore.release();
}
}).start();
}
}
}
结果打印:
14:01:19.480 [Thread-1] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:19.480 [Thread-0] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:19.480 [Thread-2] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:20.498 [Thread-0] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:20.498 [Thread-1] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:20.498 [Thread-2] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:20.498 [Thread-4] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:20.498 [Thread-3] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:20.498 [Thread-5] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:21.509 [Thread-4] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:21.509 [Thread-3] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:21.509 [Thread-5] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:21.509 [Thread-6] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:21.509 [Thread-8] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:21.509 [Thread-7] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:22.521 [Thread-6] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:22.521 [Thread-7] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:22.521 [Thread-8] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
14:01:22.521 [Thread-9] INFO jl.com.jl.juc.semaphore.SemaphoreTest - running…
14:01:23.534 [Thread-9] INFO jl.com.jl.juc.semaphore.SemaphoreTest - end…
Semaphore的应用
1.使用Semaphore限流,在访问高峰期时,让请求线程阻塞,高峰期过去再释放许可,当然它只适合限制单机线程数量,兵器仅是限制线程数,而不是限制资源数(例如连接数,对比Tomcat LimitLatch的实现-这个我还没有看。。。后续要恶补了)
2.用Semaphore实现简单连接池,对比享元模式下的实现(用 wait notify实现),性能和可读性显然更好,
/**
* 通过sempahore 优化数据库连接池
* @author jiangl
* @version 1.0
* @date 2021/4/15 11:03
*/
public class SemaphorePoolTest {
public static void main(String[] args) {
MyPool myPool = new MyPool(2);
List<Thread> lists = new ArrayList<>();
for(int i=0;i<10;i++){
lists.add(new Thread(()->{
Connection borrow = myPool.borrow();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
myPool.release(borrow);
}));
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10;i++){
lists.get(i).start();
}
}
}
@Slf4j(topic = "my.MyPool")
class MyPool{
/**
* 连接池大小
*/
private final int poolSize;
/**
* 链接数组
*/
private Connection[] connections;
/**
* 链接状态数组
*/
private AtomicIntegerArray statesArray;
private Semaphore semaphore;
/**
* 连接池对象构造方法
* @param poolSize
*/
public MyPool(int poolSize) {
this.poolSize = poolSize;
this.semaphore = new Semaphore(poolSize);
this.connections = new Connection[poolSize];
this.statesArray = new AtomicIntegerArray(poolSize);
for(int i=0;i<poolSize;i++){
this.connections[i] = new MyConnection();
this.statesArray.set(i,0);
}
}
/**
*
* @return
*/
public Connection borrow(){
//获取许可
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<poolSize;i++){
if(statesArray.get(i) == 0){
if (statesArray.compareAndSet(i,0,1)) {
log.info("borrow {}",connections[i]);
return this.connections[i];
}
}
}
//不会执行到这里
return null;
}
/**
* 释放链接
* @param connection
*/
public void release(Connection connection){
for(int i=0;i<poolSize;i++){
if(connections[i] == connection){
statesArray.set(i,0);
log.info("free {}",connection);
semaphore.release();
break;
}
}
}
}
class MyConnection implements Connection{
//省略。。。 只是实现了Connection的空方法,没有实际逻辑
}
执行结果:
14:11:43.111 [Thread-0] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:43.111 [Thread-1] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:43.621 [Thread-1] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:43.621 [Thread-0] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:43.621 [Thread-2] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:43.621 [Thread-3] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:44.133 [Thread-3] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:44.133 [Thread-2] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:44.133 [Thread-4] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:44.133 [Thread-5] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:44.634 [Thread-5] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:44.634 [Thread-4] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:44.634 [Thread-7] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:44.634 [Thread-6] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:45.134 [Thread-7] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:45.134 [Thread-6] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:45.134 [Thread-9] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:45.134 [Thread-8] INFO my.MyPool - borrow com.jl.juc.semaphore.MyConnection@52a62ac5
14:11:45.648 [Thread-9] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@53df8f5b
14:11:45.648 [Thread-8] INFO my.MyPool - free com.jl.juc.semaphore.MyConnection@52a62ac5