semaphore信号量
控制同时访问某个特定资源的线程数量,用在流量控制
这像是一种锁的机制,acquire()像是获取锁的机制,这里我们叫他许可证,如果获取不到则阻塞,但是一般锁只允许一个线程同时访问,而semaphore可以同时多个(只要有许可证的存在),当业务执行完毕,你需要增加许可证的个数,当然了,你也可以不增加,但是这样的业务需求似乎不存在,release()可新增一个许可证。
下面模拟数据库链接的代码演示:
package semaphore;
import java.sql.Connection;
import java.util.LinkedList;
import java.util.concurrent.Semaphore;
public class DBPoolSemaphore {
private final static int POOL_SIZE = 10;
private final Semaphore useful,useless;//useful表示可用的数据库连接,useless表示已用的数据库连接
public DBPoolSemaphore() {
this. useful = new Semaphore(POOL_SIZE);//10个可用的许可证
this.useless = new Semaphore(0);//0个不可用的许可证
}
//存放数据库连接的容器
private static LinkedList<Connection> pool = new LinkedList<Connection>();
//初始化池
static {
for (int i = 0; i < POOL_SIZE; i++) {//初始化存放10个连接器
pool.addLast(SqlConnectImpl.fetchConnection());
}
}
/*归还连接*/
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 conn;
synchronized (pool) {
conn = pool.removeFirst();
}
useless.release();//新增一个许可(不可用数量增加)
return conn;
}
}
package semaphore;
import java.sql.Connection;
import java.util.Random;
public class AppTest {
private static DBPoolSemaphore dbPool = new DBPoolSemaphore();
//业务线程
private static class BusiThread extends Thread{
@Override
public void run() {
Random r = new Random();//让每个线程持有连接的时间不一样
long start = System.currentTimeMillis();
try {
Connection connect = dbPool.takeConnect();//获取链接
System.out.println("Thread_"+Thread.currentThread().getId()
+"_获取数据库连接共耗时【"+(System.currentTimeMillis()-start)+"】ms.");
Thread.sleep(100+r.nextInt(100));//模拟业务操作,线程持有连接查询数据
System.out.println("查询数据完成,归还连接!");
dbPool.returnConnect(connect);//归还获得的链接
} catch (InterruptedException e) {
}
}
}
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
Thread thread = new BusiThread();
thread.start();//开启50个线程去获得链接,然后模拟业务,然后归还链接
}
}
}
结果:
Thread_12_获取数据库连接共耗时【0】ms.
Thread_16_获取数据库连接共耗时【0】ms.
Thread_17_获取数据库连接共耗时【0】ms.
Thread_18_获取数据库连接共耗时【0】ms.
Thread_15_获取数据库连接共耗时【0】ms.
Thread_14_获取数据库连接共耗时【0】ms.
Thread_13_获取数据库连接共耗时【0】ms.
Thread_9_获取数据库连接共耗时【0】ms.
Thread_11_获取数据库连接共耗时【0】ms.
Thread_10_获取数据库连接共耗时【0】ms.
查询数据完成,归还连接!
当前有40个线程等待数据库连接!!可用连接数:0
Thread_19_获取数据库连接共耗时【116】ms.
查询数据完成,归还连接!
当前有39个线程等待数据库连接!!可用连接数:0
Thread_20_获取数据库连接共耗时【124】ms.
查询数据完成,归还连接!
当前有38个线程等待数据库连接!!可用连接数:0
Thread_21_获取数据库连接共耗时【140】ms.
查询数据完成,归还连接!
当前有37个线程等待数据库连接!!可用连接数:0
Thread_22_获取数据库连接共耗时【159】ms.
查询数据完成,归还连接!
当前有36个线程等待数据库连接!!可用连接数:0
Thread_23_获取数据库连接共耗时【161】ms.
查询数据完成,归还连接!
当前有35个线程等待数据库连接!!可用连接数:0
Thread_24_获取数据库连接共耗时【173】ms.
查询数据完成,归还连接!
当前有34个线程等待数据库连接!!可用连接数:0
Thread_25_获取数据库连接共耗时【174】ms.
查询数据完成,归还连接!
当前有33个线程等待数据库连接!!可用连接数:0
Thread_26_获取数据库连接共耗时【175】ms.
查询数据完成,归还连接!
当前有32个线程等待数据库连接!!可用连接数:0
Thread_27_获取数据库连接共耗时【177】ms.
查询数据完成,归还连接!
当前有31个线程等待数据库连接!!可用连接数:0
Thread_29_获取数据库连接共耗时【191】ms.
查询数据完成,归还连接!
当前有30个线程等待数据库连接!!可用连接数:0
Thread_28_获取数据库连接共耗时【256】ms.
查询数据完成,归还连接!
当前有29个线程等待数据库连接!!可用连接数:0
Thread_30_获取数据库连接共耗时【266】ms.
查询数据完成,归还连接!
当前有28个线程等待数据库连接!!可用连接数:0
Thread_31_获取数据库连接共耗时【278】ms.
查询数据完成,归还连接!
当前有27个线程等待数据库连接!!可用连接数:0
Thread_33_获取数据库连接共耗时【284】ms.
查询数据完成,归还连接!
当前有26个线程等待数据库连接!!可用连接数:0
Thread_32_获取数据库连接共耗时【303】ms.
查询数据完成,归还连接!
当前有25个线程等待数据库连接!!可用连接数:0
Thread_34_获取数据库连接共耗时【308】ms.
查询数据完成,归还连接!
当前有24个线程等待数据库连接!!可用连接数:0
Thread_35_获取数据库连接共耗时【337】ms.
查询数据完成,归还连接!
当前有23个线程等待数据库连接!!可用连接数:0
Thread_36_获取数据库连接共耗时【352】ms.
查询数据完成,归还连接!
当前有22个线程等待数据库连接!!可用连接数:0
Thread_37_获取数据库连接共耗时【366】ms.
查询数据完成,归还连接!
当前有21个线程等待数据库连接!!可用连接数:0
Thread_38_获取数据库连接共耗时【371】ms.
查询数据完成,归还连接!
当前有20个线程等待数据库连接!!可用连接数:0
Thread_39_获取数据库连接共耗时【397】ms.
查询数据完成,归还连接!
当前有19个线程等待数据库连接!!可用连接数:0
Thread_40_获取数据库连接共耗时【409】ms.
查询数据完成,归还连接!
当前有18个线程等待数据库连接!!可用连接数:0
Thread_41_获取数据库连接共耗时【422】ms.
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有17个线程等待数据库连接!!可用连接数:0
当前有17个线程等待数据库连接!!可用连接数:0
Thread_42_获取数据库连接共耗时【439】ms.
Thread_43_获取数据库连接共耗时【439】ms.
查询数据完成,归还连接!
当前有15个线程等待数据库连接!!可用连接数:0
Thread_44_获取数据库连接共耗时【453】ms.
查询数据完成,归还连接!
当前有14个线程等待数据库连接!!可用连接数:0
Thread_45_获取数据库连接共耗时【475】ms.
查询数据完成,归还连接!
当前有13个线程等待数据库连接!!可用连接数:0
Thread_46_获取数据库连接共耗时【479】ms.
查询数据完成,归还连接!
当前有12个线程等待数据库连接!!可用连接数:0
Thread_48_获取数据库连接共耗时【499】ms.
查询数据完成,归还连接!
当前有11个线程等待数据库连接!!可用连接数:0
Thread_47_获取数据库连接共耗时【525】ms.
查询数据完成,归还连接!
当前有10个线程等待数据库连接!!可用连接数:0
Thread_49_获取数据库连接共耗时【559】ms.
查询数据完成,归还连接!
当前有9个线程等待数据库连接!!可用连接数:0
Thread_50_获取数据库连接共耗时【560】ms.
查询数据完成,归还连接!
当前有8个线程等待数据库连接!!可用连接数:0
Thread_51_获取数据库连接共耗时【564】ms.
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有7个线程等待数据库连接!!可用连接数:0
当前有7个线程等待数据库连接!!可用连接数:0
Thread_52_获取数据库连接共耗时【566】ms.
Thread_53_获取数据库连接共耗时【566】ms.
查询数据完成,归还连接!
当前有5个线程等待数据库连接!!可用连接数:0
Thread_54_获取数据库连接共耗时【571】ms.
查询数据完成,归还连接!
当前有4个线程等待数据库连接!!可用连接数:0
Thread_55_获取数据库连接共耗时【633】ms.
查询数据完成,归还连接!
当前有3个线程等待数据库连接!!可用连接数:0
Thread_56_获取数据库连接共耗时【634】ms.
查询数据完成,归还连接!
当前有2个线程等待数据库连接!!可用连接数:0
Thread_57_获取数据库连接共耗时【679】ms.
查询数据完成,归还连接!
当前有1个线程等待数据库连接!!可用连接数:0
Thread_58_获取数据库连接共耗时【681】ms.
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:0
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:1
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:2
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:3
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:4
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:5
查询数据完成,归还连接!
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:6
当前有0个线程等待数据库连接!!可用连接数:6
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:8
查询数据完成,归还连接!
当前有0个线程等待数据库连接!!可用连接数:9
SqlConnectImpl.fetchConnection()是一个实现Connection接口的类,没有太大的操作。
注意:acquire();默认使用了一个,即还剩下9个,所以你看到的不是10.(这是百度告诉我的,我也惊呆了)
availablePermits():获取许可证的个数,也就是流量的个数。
来源:CSDN
作者:yan_xiao_liu
链接:https://blog.csdn.net/qq_44132400/article/details/104145436