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();
        }
    }
}

 

posted on 2021-12-08 11:04  无心睡眠A8  阅读(34)  评论(0)    收藏  举报