模拟数据库连接池超时连接

* 我们在平时开发的时候可能会遇到超时连接的场景:就是调用某个方法的时候,如何该方法在指定的时间里得到了相应的结果,那么将结果返回,如未得到结果,直接返回默认值。现在我们来模拟一下连接数据库连接池可能遇到的超时连接*

  • 首先我们自定义一个数据库连接类
public class ConnectionDriver {
    static class ConnectionHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if(method.getName().equals("commit")){
                //TimeUnit用于通知基于时间的方法用什么方式计数
                TimeUnit.MICROSECONDS.sleep(100);
            }
            return null;
        }

    }
    public static  final Connection createConnection(){
        //使用动态代理返回Connection,其中ConectionDriver相当于实现类(但不是),Connection被代理的接口,ConnectionHandler代理类
        return (Connection)Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),new Class[]{Connection.class},new ConnectionHandler());
    }

}
  • 在定义一个连接池
public class ConnectionPool {
    private LinkedList<Connection> pool=new LinkedList<Connection>();

    /**
     * 初始化线程数量
     * @param initialSize
     */
    public ConnectionPool(int initialSize){
        if(initialSize>0){
            for(int i=0;i<initialSize;i++){
                pool.addLast(ConnectionDriver.createConnection());
            }
        }
    }

    /**
     * 释放连接
     * @param connection
     */
    public  void releaseConnection(Connection connection){
        if(connection!=null){
            synchronized(pool){
                pool.addLast(connection);
                pool.notifyAll();
            }
        }
    }

    /**
     * 在抓取连接的时候,检验是否超时连接
     * @param mills
     * @return
     * @throws InterruptedException
     */
    public Connection fetchConnection(int mills) throws InterruptedException{
        synchronized (pool){
            //完全超时
            if(mills<=0){
                while (pool.isEmpty()){
                    pool.wait();
                }
                //removeFirst()移除并返回第一元素
                return pool.removeFirst();
            }else{
                long future=System.currentTimeMillis()+mills;
                long remaining=mills;
                while(pool.isEmpty()&&remaining>0){
                    pool.wait(remaining);
                    remaining=future-System.currentTimeMillis();
                }
                Connection connection=null;
                if(!pool.isEmpty()){
                    connection=pool.removeFirst();
                }

                return connection;
            }
        }
    }
}

  • 进行连接测试
/**
 *数据库线程连接测试类,
 */
public class ConnectionPoolTest {
    static ConnectionPool pool = new ConnectionPool(10);

    static CountDownLatch start = new CountDownLatch(1);
    //保证与初始化的线程数一直,若比线程数小,main线程则会被提前唤醒
    static CountDownLatch end = new CountDownLatch(100);

    public static void main(String[] args) throws InterruptedException{
        int threadCount=100;
        //使用Atomic前缀的类型保证线程安全
        //获取等待了连接的数量
        AtomicInteger got=new AtomicInteger();
        //超时未得到连接的数量
        AtomicInteger nogot=new AtomicInteger();
        for(int i=0;i<threadCount;i++){
            new Thread(new ConnectionRunner(20,got,nogot),"Thread"+i).start();
        }
        start.countDown();
        //等线程都完成了才继续main后续的动作
        end.await();
        System.out.println("got:"+got.get()+"_"+"nogot:"+nogot.get());
    }
    public static class ConnectionRunner implements Runnable{
        private int count;
        private AtomicInteger got;
        private AtomicInteger nogot;

        public ConnectionRunner(int count, AtomicInteger got, AtomicInteger nogot) {
            this.count = count;
            this.got = got;
            this.nogot = nogot;
        }

        public void run() {
            //保证线程同时初始化完成后才开始一起获取资源
            try {
                start.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            while (count>0){
                try {
                    Connection connection=pool.fetchConnection(100);
                    if(connection!=null){
                        try {
                            connection.commit();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        } finally {
                            pool.releaseConnection(connection);
                            got.incrementAndGet();
                        }
                    }else {
                        nogot.incrementAndGet();
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    count--;
                }
            }
            end.countDown();
        }
    }
}

这里里面使用了一下concurrent包下面的一下类,不了解的可以自己百度一下。

结果比较:

线程数连接次数显示结果
10200got:200_nogot:0
20400got:400_nogot:0
40800got:780_nogot:20

从结果中可以看出随着线程数量的不断增加,获取连接时存在超时连接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值