写了一个简单的数据库连接池

时间:2022-04-25 23:48:15
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);
}
}