首页 > 代码库 > 我用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写的连接池