* 我们在平时开发的时候可能会遇到超时连接的场景:就是调用某个方法的时候,如何该方法在指定的时间里得到了相应的结果,那么将结果返回,如未得到结果,直接返回默认值。现在我们来模拟一下连接数据库连接池可能遇到的超时连接*
- 首先我们自定义一个数据库连接类
public class ConnectionDriver {
static class ConnectionHandler implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("commit")){
//TimeUnit用于通知基于时间的方法用什么方式计数
TimeUnit.MICROSECONDS.sleep(100);
}
return null;
}
}
public static final Connection createConnection(){
//使用动态代理返回Connection,其中ConectionDriver相当于实现类(但不是),Connection被代理的接口,ConnectionHandler代理类
return (Connection)Proxy.newProxyInstance(ConnectionDriver.class.getClassLoader(),new Class[]{Connection.class},new ConnectionHandler());
}
}
- 在定义一个连接池
public class ConnectionPool {
private LinkedList<Connection> pool=new LinkedList<Connection>();
/**
* 初始化线程数量
* @param initialSize
*/
public ConnectionPool(int initialSize){
if(initialSize>0){
for(int i=0;i<initialSize;i++){
pool.addLast(ConnectionDriver.createConnection());
}
}
}
/**
* 释放连接
* @param connection
*/
public void releaseConnection(Connection connection){
if(connection!=null){
synchronized(pool){
pool.addLast(connection);
pool.notifyAll();
}
}
}
/**
* 在抓取连接的时候,检验是否超时连接
* @param mills
* @return
* @throws InterruptedException
*/
public Connection fetchConnection(int mills) throws InterruptedException{
synchronized (pool){
//完全超时
if(mills<=0){
while (pool.isEmpty()){
pool.wait();
}
//removeFirst()移除并返回第一元素
return pool.removeFirst();
}else{
long future=System.currentTimeMillis()+mills;
long remaining=mills;
while(pool.isEmpty()&&remaining>0){
pool.wait(remaining);
remaining=future-System.currentTimeMillis();
}
Connection connection=null;
if(!pool.isEmpty()){
connection=pool.removeFirst();
}
return connection;
}
}
}
}
- 进行连接测试
/**
*数据库线程连接测试类,
*/
public class ConnectionPoolTest {
static ConnectionPool pool = new ConnectionPool(10);
static CountDownLatch start = new CountDownLatch(1);
//保证与初始化的线程数一直,若比线程数小,main线程则会被提前唤醒
static CountDownLatch end = new CountDownLatch(100);
public static void main(String[] args) throws InterruptedException{
int threadCount=100;
//使用Atomic前缀的类型保证线程安全
//获取等待了连接的数量
AtomicInteger got=new AtomicInteger();
//超时未得到连接的数量
AtomicInteger nogot=new AtomicInteger();
for(int i=0;i<threadCount;i++){
new Thread(new ConnectionRunner(20,got,nogot),"Thread"+i).start();
}
start.countDown();
//等线程都完成了才继续main后续的动作
end.await();
System.out.println("got:"+got.get()+"_"+"nogot:"+nogot.get());
}
public static class ConnectionRunner implements Runnable{
private int count;
private AtomicInteger got;
private AtomicInteger nogot;
public ConnectionRunner(int count, AtomicInteger got, AtomicInteger nogot) {
this.count = count;
this.got = got;
this.nogot = nogot;
}
public void run() {
//保证线程同时初始化完成后才开始一起获取资源
try {
start.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
while (count>0){
try {
Connection connection=pool.fetchConnection(100);
if(connection!=null){
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
pool.releaseConnection(connection);
got.incrementAndGet();
}
}else {
nogot.incrementAndGet();
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
count--;
}
}
end.countDown();
}
}
}
这里里面使用了一下concurrent包下面的一下类,不了解的可以自己百度一下。
结果比较:
线程数 | 连接次数 | 显示结果 |
---|---|---|
10 | 200 | got:200_nogot:0 |
20 | 400 | got:400_nogot:0 |
40 | 800 | got:780_nogot:20 |
从结果中可以看出随着线程数量的不断增加,获取连接时存在超时连接