Java数据库连接池简单模拟(等待/通知模式,多线程)

本文深入探讨Java中数据库连接池的实现原理与实践,通过自定义ConnectionPool类,采用等待/通知经典范式,实现线程安全的连接获取与释放。并通过ConnectionTest类模拟多线程环境下连接池的高效运作。

数据库连接池

Java对于数据库的操作,需要创建相应的数据库连接,connection的创建和释放是耗时的。于是有了数据库连接池,提前创建好若干connection,需要用就去池子里面取,不用了直接放回池子就OK,之后可以供他人使用。
Java常用的数据库连接池有DBCP、C3P0等等

等待/通知经典范式

等待方:
1.获取对象锁
2.while循环判断条件是否满足,不满足则调用对象的wait方法,进入等待队列
3.被通知后依然检查条件是否满足,满足则执行后续逻辑

synchronized (对象){
            while(条件判断){
                对象.wait();
            }
            后续代码
        }

通知方
1.获取对象锁
2.改变相关条件
3.通知所有等待在该对象上面的线程

synchronized (对象){
            改变条件
            对象.notifyAll();        
        }

多线程模拟

ConnectionPool类:维护一个LinkedList,包含获取连接、释放连接两个方法。

public class ConnectionPool {
    //利用LinkedList集合存储Connection
    private LinkedList<Connection> pool = new LinkedList();
    //带参构造,初始化连接数
    public ConnectionPool(int initialSize){
        for(int i=0;i<initialSize;i++){
            pool.add(getConnection());
        }
    }
    //尝试获取连接(millisecond毫秒内获取不到返回null)
    public Connection tryFetchConnection(long millisecond){
        synchronized (pool){
            Connection result = null;
            try {
                long current = System.currentTimeMillis();
                //假如初始millisecond<=0,表示无时间限制
                if(millisecond<=0){
                    while(pool.isEmpty()){
                        pool.wait();
                    }
                    return pool.removeFirst();
                }else{
                    //否则 利用等待/通知范式 在指定时间内去尝试获取连接
                    //result不为null直接返回,超时直接返回
                    while (result==null && millisecond>0){

                        if (pool.isEmpty()){
                            pool.wait();
                            millisecond = current+millisecond-System.currentTimeMillis();
                        }else {
                            result = pool.removeFirst();
                        }

                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return result;
        }
    }


    //释放连接,假如Connection不为null,重新加入LinkedList
    public void releaseConnection(Connection connection){
        synchronized (pool){
            if(connection != null){
                pool.add(connection);
                //同时唤醒所有等待在pool的线程
                pool.notifyAll();
            }
        }

    }
    //Connection一般都是数据库厂商编写,这里为了方便,通过代理模式创建一个自定义Connection对象
    private Connection getConnection(){
        Connection connection = (Connection)Proxy.newProxyInstance(ConnectionPool.class.getClassLoader(), new Class[]{Connection.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                if(method.getName().equals("commit")){
                    //在commit里面睡10ms模拟数据库操作
                    TimeUnit.MILLISECONDS.sleep(10);
                }
                return null;
            }
        });
        return connection;
    }
}

ConnectionTest类:测试类,包含一个静态内部类(ConnectionUser,用来模拟用户获取Connection连接)

public class ConnectionTest {
    static ConnectionPool connectionPool = new ConnectionPool(10);
    //保证所有用户线程的run方法同时开始
    static CountDownLatch start;
    //保证所有用户线程执行完毕,再打印got(成功获取数量)和unGot(未成功获取数量)
    static CountDownLatch end;
    public static void main(String[] args) {
        int threadCount = 30;
        int count = 20;
        AtomicInteger got = new AtomicInteger(0);
        AtomicInteger unGot = new AtomicInteger(0);
        start = new CountDownLatch(1);
        end = new CountDownLatch(threadCount);
        for(int i=0;i<threadCount;i++){
            new Thread(new ConnectionUser(got,unGot,count)).start();
        }
        start.countDown();
        try {
            end.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //最后通过打印两个值,可以查看成功获取和未成功获取的数量
        System.out.println("got:"+got);
        System.out.println("unGot:"+unGot);

    }

    //模拟用户线程
    static class ConnectionUser implements Runnable{
        AtomicInteger got;
        AtomicInteger unGot;
        int count;
        public ConnectionUser(AtomicInteger got,AtomicInteger unGot,int count){
            this.got = got;
            this.unGot = unGot;
            this.count = count;
        }
        @Override
        public void run() {
            try {
                //等待所有用户线程初始化完毕
                start.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //一个线程获取count次连接
            while (count>0){
                //尝试获取连接,最大等待时间1000ms
                Connection connection = connectionPool.tryFetchConnection(1000);
                if(connection != null){
                    try {
                        //获取到got加1,利用commit睡10ms
                        got.incrementAndGet();
                        connection.createStatement();
                        connection.commit();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }finally {
                        //释放连接,将connection放回LinkedList
                        connectionPool.releaseConnection(connection);
                    }
                }else {
                    //未获取到 unGot加1
                    unGot.incrementAndGet();
                }
                count--;

            }

            //countDownLatch数量减一,代表一个用户线程执行完毕
            end.countDown();


        }
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值