线程应用实例--一个简单的数据库连接池示例

        我们使用等待超时模式来构造一个简单的数据库连接池,在示例中模拟从连接池中获取、使用和释放连接的过程。而客户端获取连接的过程被设定为等待超时模式,也就是在1000毫秒内如果无法获取到可用的连接,将会返回客户端一个null。设定连接池的大小为10个,然后通过调节客户端的线程数来模拟无法获取连接的场景。

一、Connection接口

        由于java.sql.Connection是一个接口,最终的实现是由数据库驱动提供方来实现的,考虑到只是一个示例,我们通过动态代理构造了一个Connection,该Connection的代理实现仅仅是在commit()方法调用时休眠100毫秒。

public class ConnectionDriver {

        static class ConnectionHandler implements InvocationHandler {

                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{

                        if (method.getName().equals("commit")) {

                                TimeUnit.MILLISECONDS.sleep(100);

                        }

                        return null;

                  }

            }

            public static final Connection createConnection() {

                return (Connection) Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),

                                  new Class[]{Connection.class},

                                  new ConnectionHandler());

            }

}

二、连接池定义

        连接池通过构造函数初始化连接池的最大上限,通过一个双向队列来维护连接,调用方需要先调用fetchConnection(long)方法来指定在多少毫秒内超时获取连接,当连接使用完成以后,需要调用releaseConnection(Connection)方法将连接放回线程池。

public class ConnectionPool {

        //用来存放数据库连接

        private LinkedList<Connection> pool = new LinkedList<Connection>();

        //初始化数据连接池连接

        public ConnectionPool(int initialSize) {

            if (initialSize > 0) {

                    for (int i = 0; i < initialSize; i++) {

                        pool.addLast(ConnectionDriver.createConnection());

                    }

            }

        }

        //释放连接

        public void releaseConnection(Connection connection) {

                if (connection != null) {

                    synchronized (pool) {

                            //将连接放回连接池

                            pool.addLast(connection);

                            //通知连接池对象已经释放了连接

                            pool.notifyAll();

                    }

            }

        }

        //超时获取连接

        public Connection fetchConnection(long mills) throws InterruptedException {

                synchronized (pool) {

                     // 完全超时

                    if (mills <= 0) {

                            while (pool.isEmpty()) {

                                    pool.wait();

                            }

                            return pool.removeFirst();

                    } else {

                            //等到后超时时间后的将来的时间

                            long future = System.currentTimeMillis() + mills;

                            //等待时间

                            long remaining = mills;

                            //如果连接池为空 而且等待时间大于0则需要等待

                            while (pool.isEmpty() && remaining > 0) {

                                    pool.wait(remaining);

                                    remaining = future - System.currentTimeMillis();

                            }

                            //连接池有连接或者已经等待完超时时间,则获取数据库连接

                            Connection result = null;

                            if (!pool.isEmpty()) {

                                    result = pool.removeFirst();

                            }

                            return result;

                    }

            }

        }

}

三、测试类

public class ConnectionPoolTest {

        static ConnectionPool pool = new ConnectionPool(10);

        static CountDownLatch start = new CountDownLatch(1);

        static CountDownLatch end;

        public static void main(String[] args) throws Exception {

                int threadCount = 10;

                end = new CountDownLatch(threadCount);

                int count = 20;

                AtomicInteger got = new AtomicInteger();

                AtomicInteger notGot = new AtomicInteger();

                for (int i = 0; i < threadCount; i++) {

                        Thread thread = new Thread(new ConnetionRunner(count, got, notGot),

                            "ConnectionRunnerThread");

                         thread.start();

                }

                start.countDown();

                //等待所有获取连接线程执行完

                end.await();

                System.out.println("total invoke: " + (threadCount * count));

                System.out.println("got connection: " + got);

                System.out.println("not got connection " + notGot);

        }

        static class ConnetionRunner implements Runnable {

                int count;

                AtomicInteger got;

                AtomicInteger notGot;

                public ConnetionRunner(int count, AtomicInteger got, AtomicInteger notGot) {

                        this.count = count;

                        this.got = got;

                        this.notGot = notGot;

                }

                public void run() {

                    try {

                        //所有线程在此等待并发去获取连接

                        start.await();

                    } catch (Exception ex) {

                    }

                    while (count > 0) {

                            try {

                                    Connection connection = pool.fetchConnection(1000);

                                     if (connection != null) {

                                            try {

                                                    connection.createStatement();

                                                    connection.commit();

                                            } finally {

                                                    pool.releaseConnection(connection);

                                                    got.incrementAndGet();

                                            }

                                    } else {

                                            notGot.incrementAndGet();

                                    }

                            } catch (Exception ex) {

                            } finally {

                                    count--;

                            }

                   }

                  end.countDown();

            }

        }

}

        上述示例中使用了CountDownLatch来确保ConnectionRunnerThread能够同时开始执行,并且在全部结束之后,才使main线程从等待状态中返回。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,622评论 6 544
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,716评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,746评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,991评论 1 318
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,706评论 6 413
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 56,036评论 1 329
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 44,029评论 3 450
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,203评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,725评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,451评论 3 361
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,677评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,161评论 5 365
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,857评论 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,266评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,606评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,407评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,643评论 2 380

推荐阅读更多精彩内容