AQS线程同步器-Semaphore(信号量同步器)

一、概念

        该同步器的作用是控制共享资源的最大可访问数量,或者定义最多允许多少个线程对共享资源同时进行访问。一个典型的运行就是实现池化机制,如对象池、连接池等。

二、代码示例

        代码示例由三个类组成,分别为连接池列、连接对象类、测试类

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值