我用LinkedBlockingQueue写的连接池

Posted Hmake

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我用LinkedBlockingQueue写的连接池相关的知识,希望对你有一定的参考价值。

 

什么是连接池呢?

  我们登陆上某个网站,去修改个人信息、点击下单、修改购买商品的数量......当我们做这些操作时候,

我们已经连接上数据库并修改、增加、删除数据库中的数据,完成操作后,关闭连接(避免占用资源)。

如果很多人访问这个网站并进行操作,那要创建很多个连接,而且只操作一次就关闭,这会显著的影响系统的

性能。连接池  就为解决这个难题应运而生。

连接池: 

  在系统初始化的时候,将数据库连接作为对象存放在内存中。当用户要访问数据库时,取出一个连接,

完成操作后归还到池中,等待下个用户使用。连接的创建、断开都由池来管理。我们可以设置连接池的参

数控制初始连接数、连接的上下限数、最大空闲时间......这项技术明显的提高对数据库操作的性能。

 

线程池:

package org3.pool;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * Created by Administrator on 2016/11/25.
 * 编写一个线程池
 */
public class Pool {


    private int minSize = 1;    //定义最小连接数,默认为2
    private int maxSize = 2;    //定义最大连接数,默认为4
    private int fetchCount = minSize;   //记录从数据库抓取的连接数
    private LinkedBlockingQueue<Connection> pool;   //定义一个阻塞队列,充当连接池

    public void setMinSize(int minSize) {
        this.minSize = minSize;
        this.fetchCount = minSize;
    }

    public void setMaxSize(int maxSize) {
        this.maxSize = maxSize;
    }

    //初始化线程池方法
    public void initPool() {
        //初始化连接池的最大值
        pool = new LinkedBlockingQueue<>( maxSize );
        //预先存放minSize个连接
        for ( int i = 0 ; i < minSize ; i++ ) {
            pool.add( DBUtil.getConnection() );
        }
    }

    //从数据库抓取连接方法
    public synchronized Connection getConnection() {
        //检查连接池状况,如果检查未通过将直接引发异常,程序终止
        checkFetch();
        Connection conn = null;
        try {
            conn = getProxyConnection();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return conn;
    }

    //检查连接池的状况
    private void checkFetch() {
        //当连接池大小为0 且 连接记录数还没达到最大值时
        if ( pool.isEmpty() && fetchCount < maxSize ) {
            pool.add( DBUtil.getConnection() );
        }
    }

    //从连接池获取连接,并将获取的连接创建一个代理对象
    private Connection getProxyConnection() throws InterruptedException {
        //先从池中获取未代理的连接对象
        Connection conn = pool.take();
        //将获取的链接创建代理对象
        return createProxy( conn );
    }

    //使用内部类来实现InvocationHandler
    private Connection createProxy( Connection conn ) {
        return ( Connection )Proxy.newProxyInstance( Connection.class.getClass().getClassLoader(), new Class[] { Connection.class }, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //如果客户端调用的是close方法,就将连接放回连接池
                if( "close".equals(method.getName() ) ) {
                    pool.put( conn );
                    fetchCount--;
                }
                //如果是Connection其他的方法,将正常回调,也就是放行
                return method.invoke(conn,args);
            }
        });
    }

    //查看连接池当前连接数
    public int size() {
        return pool.size();
    }
}

DBUtil:

package org3.pool;

import java.sql.*;

/**
 * Created by Administrator on 2016/11/25.
 */
public class DBUtil {

    private static String driver = "oracle.jdbc.driver.OracleDriver";   //数据库驱动
    private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";    //数据库的资源地址
    private static String userName = "mark";    //用户名
    private static String password = "mark";    //密码

    static {
        try {
            Class.forName( driver );
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static Connection getConnection() {
        Connection conn = null;
        try {
            conn = DriverManager.getConnection( url, userName, password );
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }


    //main方法(用于测试)
    public static void main(String[] args) {
        System.out.println( getConnection() );
    }
}

编写一个线程:

package org3.pool;

import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created by Administrator on 2016/11/26.
 * 编写线程1
 */
public class User1 extends Thread {

    //定义连接池对象
    private Pool pool;

    public User1( Pool pool ) {
        this.pool = pool;
    }

    //重写Thread的run方法
    @Override
    public void run() {
        Connection conn = pool.getConnection();
        System.out.println(Thread.currentThread().getName() + "获取了一个连接:" + conn);
        try {
            Thread.sleep( 500 );
            conn.close();
            System.out.println(Thread.currentThread().getName() + "归还了一个连接: " + conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

main方法:

package org3.pool;

import java.sql.SQLException;

/**
 * Created by Administrator on 2016/11/25.
 * main方法
 */
public class Main {
    public static void main(String[] args) throws SQLException {
        //实例化连接池对象
        Pool pool = new Pool();
        //给连接池设置属性
        pool.setMinSize( 2 );
        pool.setMaxSize( 5 );
        //初始化连接池
        pool.initPool();

        for( int i = 0; i < 10; i++ ){
            User1 u1 = new User1( pool );
            u1.start();
        }

        try {
            Thread.sleep( 10000 );
            System.out.println( "线程大小= " + pool.size() );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

运行结果:

 

 

-------------------------------------------------------------------------

以上是关于我用LinkedBlockingQueue写的连接池的主要内容,如果未能解决你的问题,请参考以下文章

django 部署都阿里云 怎么部署呀 我用的是pycharm写的 写完了 是直接通过FILEzilla 上传吗

Java&Go高性能队列之LinkedBlockingQueue性能测试#yyds干货盘点#

我用delphi写的二层的仓库软件,怎么才能在外网访问我的软件,路由器上有固定ip

阻塞队列之LinkedBlockingQueue

javajava 队列 LinkedBlockingQueue

源码分析-LinkedBlockingQueue