import java.sql.Connection; import java.sql.SQLException; import java.util.Iterator; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ConnectionPool { private static ConcurrentHashMap<String,ConnectionEntity> idelConnections=null; private static ConcurrentHashMap<String,ConnectionEntity> activeConnections=null; private static int initSize; private static int maxSize; private static AtomicInteger idelSize=new AtomicInteger(0); private static AtomicInteger activeSize=new AtomicInteger(0); private static ConnectionPool instance=null; private static Lock lock= new ReentrantLock(); private Object object=new Object(); private ConnectionPool(int initSize,int maxSize){ this.initSize=initSize; this.maxSize=maxSize; idelConnections=new ConcurrentHashMap<String,ConnectionEntity>(); activeConnections=new ConcurrentHashMap<String,ConnectionEntity>(); initConnections(); new DetectFailConnection().start(); } public ConnectionEntity getConnection() throws InterruptedException, SQLException{ lock.lock(); try{ if(idelSize.get()>0){ if(idelConnections.size()<=0){ throw new RuntimeException(""); } String key=idelConnections.entrySet().iterator().next().getKey(); ConnectionEntity entity=idelConnections.entrySet().iterator().next().getValue(); entity.setStatus(Connection_Status.active); idelConnections.remove(key); idelSize.decrementAndGet(); if(entity.getConnection().isClosed()){ return getConnection(); } activeConnections.put(key, entity); activeSize.incrementAndGet(); return entity; } }finally{ lock.unlock(); } if(activeSize.get()>maxSize){ throw new RuntimeException("活跃数量大于最大值"); } if(activeSize.get()==maxSize){ synchronized (object) { object.wait(); } } Connection conn=OracleUtils.getConnection(); String id=UUID.randomUUID().toString(); ConnectionEntity entity=new ConnectionEntity(); entity.setId(id); entity.setConnection(conn); entity.setStatus(Connection_Status.active); activeConnections.put(id, entity); activeSize.incrementAndGet(); return entity; } public void releaseConnection(String id) throws SQLException{ if(idelSize.get()==maxSize){ OracleUtils.closeConnection(activeConnections.remove(id).getConnection()); }else{ ConnectionEntity entity=activeConnections.remove(id); entity.setStatus(Connection_Status.idel); idelConnections.put(id, entity); idelSize.incrementAndGet(); activeSize.decrementAndGet(); synchronized (object) { object.notify(); } } } private void initConnections(){ for(int i=0;i<this.initSize;i++){ ConnectionEntity entity=new ConnectionEntity(); String id=UUID.randomUUID().toString(); entity.setId(id); entity.setConnection(OracleUtils.getConnection()); entity.setStatus(Connection_Status.idel); idelConnections.put(id, entity); idelSize.getAndAdd(1); } } public int getIdelSize(){ return this.idelSize.get(); } public int getActiveSize(){ return this.activeSize.get(); } public static ConnectionPool getInstance(int initSize,int maxSize){ if(initSize<0||maxSize<1){ throw new RuntimeException("initSize必须不小于0,maxsize必须大于等于1"); } if(initSize>maxSize){ initSize=maxSize; } synchronized (ConnectionPool.class) { if(instance==null){ instance=new ConnectionPool(initSize,maxSize); } } return instance; } public static class ConnectionEntity{ private String id; private Connection connection; private Connection_Status status; public Connection getConnection() { return connection; } public void setConnection(Connection connection) { this.connection = connection; } public Connection_Status getStatus() { return status; } public void setStatus(Connection_Status status) { this.status = status; } public String getId() { return id; } public void setId(String id) { this.id = id; } } private enum Connection_Status{ idel,active,close } class DetectFailConnection extends Thread{ @Override public void run() { Iterator<String> itIdel=idelConnections.keySet().iterator(); while(itIdel.hasNext()){ String key =itIdel.next(); ConnectionEntity entity=idelConnections.get(key); try { if(entity.getConnection().isClosed()){ idelConnections.remove(key); idelSize.decrementAndGet(); } } catch (SQLException e) { e.printStackTrace(); } } Iterator<String> itActive=activeConnections.keySet().iterator(); while(itActive.hasNext()){ String key=itActive.next(); ConnectionEntity entity=activeConnections.get(key); try { if(entity.getConnection().isClosed()){ activeConnections.remove(key); activeSize.decrementAndGet(); } } catch (SQLException e) { e.printStackTrace(); } } try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
测试用例
public class TestConnectionPool extends TestCase { private ConnectionPool pool=null; @Override protected void setUp() throws Exception { pool=ConnectionPool.getInstance(3, 10); } public void testGetConnection() throws InterruptedException, SQLException{ Assert.assertEquals(0,pool.getActiveSize()); Assert.assertEquals(3,pool.getIdelSize()); ConnectionEntity entity=pool.getConnection(); ConnectionEntity entity1=pool.getConnection(); ConnectionEntity entity2=pool.getConnection(); Assert.assertEquals(3,pool.getActiveSize()); Assert.assertEquals(0,pool.getIdelSize()); pool.releaseConnection(entity.getId()); pool.releaseConnection(entity1.getId()); pool.releaseConnection(entity2.getId()); Assert.assertEquals(0,pool.getActiveSize()); Assert.assertEquals(3,pool.getIdelSize()); final CountDownLatch latch=new CountDownLatch(5); for(int i=0;i<5;i++){ new Thread(){ public void run() { try { ConnectionEntity entity=pool.getConnection(); latch.countDown(); } catch (InterruptedException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); } }; }.start(); } latch.await(); Assert.assertEquals(5,pool.getActiveSize()); Assert.assertEquals(0,pool.getIdelSize()); final CountDownLatch latch2=new CountDownLatch(5); for(int i=0;i<5;i++){ new Thread(){ public void run() { try { for(int i=0;i<20;i++){ ConnectionEntity entity=pool.getConnection(); pool.releaseConnection(entity.getId()); } latch2.countDown(); } catch (InterruptedException e) { e.printStackTrace(); }catch (SQLException e) { e.printStackTrace(); } }; }.start(); } latch2.await(); System.out.println(1); } }