Semaphore 并发工具类
Java 中的 Semaphore 是一种新的同步类,它是一个计数信号。从概念上讲,信号量维护了一个许可集合。
如有必要,在许可可用前会阻塞每一个acquire(),然后再获取该许可。
每个 release()添加一个许可,从而可能释放一个正在阻塞的获取者。但是,
不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应行动。
信号量常常用于多线程的代码中,比如数据库连接池。
应用场景:流量控制 、数据库连接
特别是公用资源有限的应用场景,比如数据库连接。假如有一个需求,
要读取几万个文件的数据,因为都是 IO 密集型任务,我们可以启动几十个线程
并发地读取,但是如果读到内存后,还需要存储到数据库中,而数据库的连接数
只有 10 个,这时我们必须控制只有 10 个线程同时获取数据库连接保存数据,否
则会报错无法获取数据库连接。这个时候,就可以使用 Semaphore 来做流量控
制。
方法:
acquire()方法获取一个许可证:减少一个凭证,凭证数做--减减操作
使用完之后调用 release()方法归还许可证。: 添加一个凭证,凭证数做++操作
•availablePermits():返回此信号量中当前可用的许可证数。
•getQueueLength():返回正在等待获取许可证的线程数。
hasQueuedThreads():是否有线程正在等待获取许可证。
•void reducePermits (int reduction):减少 reduction 个许可证,是个 protected
方法。
•Collection getQueuedThreads():返回所有等待获取许可证的线程集合,是
个 protected 方法。
//1.这个类是数据库的连接类 实现 java.sql.Connection; public class MySqlConnection implements Connection { //创建一个方法 用来获取这个类的连接对象 public static Connection getMysqlConn(){ return new MySqlConnection(); } //下面的不用管 @Override public Statement createStatement() throws SQLException { return null; } }
/** * @Author zh * @Description 这个类是数据库的连接池 * @Date 2021/12/8 */ public class MysqlPool { //1.连接数量 private static final int POOL_MAX=10; //2. 集合存储多个连接 private static LinkedList<Connection> pool =new LinkedList<>(); //3.需要提前把10个连接放入集合 static { for (int i = 0; i < POOL_MAX; i++) { pool.add(MySqlConnection.getMysqlConn()); } } //4.创建两个信号量 一个信号量 用来控制可用连接数 一个用来控制已用连接数 //可用连接 private Semaphore usable; //已用连接 private Semaphore usedable; //5.在初始化的时候,请把两个信号量初始化 public MysqlPool(){ this.usable =new Semaphore(10);//可用的10个 this.usedable =new Semaphore(0);//已用的0个 } //6.提供一个获取连接的方法 public Connection getConn(){ Connection conn =null; try { //可用的做--操作 usable.acquire(); //用加锁的方式获取连接 synchronized (pool){ //从集合中获取连接 conn = pool.getFirst(); } //已用的做++操作 usedable.release(); } catch (Exception e) { e.printStackTrace(); } return conn; } //7.提供一个还连接的方法 public void backConn(Connection connection){ // 可以打印 当前可用连接数 已用连接数 和 等待线程数 System.out.println("可用连接数:"+usable.availablePermits() +"已用连接数:"+usedable.availablePermits() +"等待线程数:"+usable.getQueueLength()); try { //可用连接+1 usable.release();//++ //用加锁的方式返还连接 synchronized (pool){ pool.add(connection); } //已用连接-1 usedable.acquire();//-- } catch (InterruptedException e) { e.printStackTrace(); } } }
* @Author zh * @Description 用来做数据增删改查 * @Date 2021/12/8 */ public class MysqlThread extends Thread { private static MysqlPool pool = new MysqlPool(); @Override public void run() { try { Random random = new Random(); //1.获取连接 Connection conn = pool.getConn(); //2.做crud操作 Thread.sleep(100+random.nextInt(100)); //3.关闭连接 pool.backConn(conn); } catch (Exception e) { e.printStackTrace(); } } }
public class TMain { public static void main(String[] args) { for (int i = 0; i < 100; i++) { new MysqlThread().start(); } } }
浙公网安备 33010602011771号