首页 > 代码库 > 我用LinkedBlockingQueue写的连接池

我用LinkedBlockingQueue写的连接池

 

什么是连接池呢?

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

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

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

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

连接池: 

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

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

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

 

为什么要用LinkedBlockingQueue?

  LinkedBlockingQueue是实现了BlockingQueue的接口,继承了BlockingQueue的优点,同时又基

于自身链表结构,拥有自己的特色。

  在多线程环境下,使用BlockingQueue再也不需担心线程什么时候阻塞,什么时候需要唤醒线程,这些

BlockingQueue都一手包办了。当队列满了,生产者(存入数据的一方)线程就会发生阻塞,不再运行,

直到队列有空位,线程才会自动被唤醒。

  LinkedBlockingQueue继承了这些优点,而且能够高效的处理并发数据,因为其对于生产者和消费者

(取出数据的一方)分别独立采用的锁来控制数据同步,这意味着在高并发的情况下,生产者和消费者能够

可以并行的处理队列中的数据,提高队列中的并发性能。

 

 

编写一个线程池:

package org3.pool;

import java.sql.Connection;
import java.util.concurrent.LinkedBlockingQueue;

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

    //用LinkedBlockingQueue来存放Connection对象
    //设定其大小为4
    private LinkedBlockingQueue<Connection> pool = new LinkedBlockingQueue<>( 4 );

    //初始化线程池
    public void initPool() {
        //往池中添加4个连接对象
        while ( pool.size() < 4 ) {
            pool.add( DBUtil.getConnection() );
        }
        //确认一下池的大小
        System.out.println( "初始化后size= " + pool.size() );
    }

    //获取一个连接
    public Connection getConnection() {
            Connection conn = null;
            try {
                //从池中取出一个连接
                //当池中没有连接时,线程处于阻塞状态;当池中添加一个连接时,线程则被激活
                conn = pool.take();
                //确认一下池的大小
                System.out.println( "取走了一个线程,线程大小为= " + pool.size() );
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //返回一个  被代理  的连接对象
            return ConnectionProxy.getConnectionProxy( conn, pool );
    }
}

回调处理器:

package org3.pool;

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

/**
 * Created by Administrator on 2016/11/25.
 * 编写一个回调处理器
 * 用来调用目标对象的具体行为
 */
public class ConnectionInvocationHandler implements InvocationHandler {

    //定义回调目标对象
    private Connection conn;
    //定义线程池
    private LinkedBlockingQueue<Connection> pool;

    //在构造方法中传入两个成员变量
    public ConnectionInvocationHandler( Connection conn, LinkedBlockingQueue<Connection> pool ) {
        this.conn = conn;
        this.pool = pool;
    }

    //重写方法
    @Override
    public Object invoke( Object obj, Method method, Object[] args ) throws InvocationTargetException, IllegalAccessException, InterruptedException {
        //当执行close方法之前,我们把线程回收,不让它被处理
        if ( "close".equals( method.getName() ) ) {
            //回收线程
            pool.put( conn );
            System.out.println( "线程放回去了,线程大小为= " + pool.size() );
            return null;
        } else {
            //如果不是close方法,则继续执行目标的行为
            return method.invoke( pool, args );
        }
    }
}

对象代理类:

package org3.pool;

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

/**
 * Created by Administrator on 2016/11/25.
 * 编写一个对象代理类
 * 构造出一个我们传入对象的代理对象
 */
public class ConnectionProxy {

    static Connection getConnectionProxy( Connection conn, LinkedBlockingQueue<Connection> pool ) {
        //构造一个回调处理器
        ConnectionInvocationHandler handler = new ConnectionInvocationHandler( conn, pool );
        //返回一个被代理对象
        return ( Connection )Proxy.newProxyInstance( Connection.class.getClassLoader(), new Class[] { Connection.class }, handler );
    }
}

数据库连接(不同的数据,连接都不一样,我用的是Oracle):

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";

    public static Connection getConnection() {
        try {
            //加载驱动
            Class.forName( driver );
            return DriverManager.getConnection( url, userName, password );
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        } catch (SQLException e) {
            e.printStackTrace();
            return null;
        }
    }

    //连接关闭
    public static void closeConn( ResultSet rs, PreparedStatement ps, Connection conn ) {
        if ( rs != null ) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if ( ps != null ) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if ( conn != null ) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

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

线程1:

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() {
        //让线程无限循环
        while ( true ) {
            //取出两个线程
            Connection con = pool.getConnection();
            Connection con2 = pool.getConnection();
            try {
                //睡眠3秒
                Thread.sleep( 300 );
                //关闭连接
                con.close();
                //睡眠1毫秒
                Thread.sleep( 100 );
                //关闭连接
                con2.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

线程2:

package org3.pool;

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

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

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

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

    @Override
    public void run() {
        while ( true ) {
            //取出三个线程
            Connection conn = pool.getConnection();
            Connection conn2 = pool.getConnection();
            Connection conn3 = pool.getConnection();
            try {
                //睡眠1毫秒
                Thread.sleep( 100 );
                //关闭连接
                conn.close();
                Thread.sleep( 100 );
                conn2.close();
                Thread.sleep( 100 );
                conn3.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (SQLException 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.initPool();

        //实例化两个线程
        User1 u1 = new User1( pool );
        User2 u2 = new User2( pool );

        //开启线程
        u1.start();
        u2.start();
    }
}

运行结果:

技术分享

技术分享

 

 

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

我用LinkedBlockingQueue写的连接池