通过一个简单的数据库连接池分析一下“等待超时模式”

时间:2021-08-23 17:08:16

场景描述:开发人员经常会遇到这样的方法调用场景:调用一个方法时等待一段时间(一般来说是给定一个时间段),如果该方法能够在给定的时间段之内得到结果, 那么将结果立刻返回, 反之,超时返回默认结果。

·等待持续时间REMAINING=T
·时时间FUTURE=now+T
这时仅需要wait(REMAINING)即可, 在wait(REMAINING)返回之后会将行:
REMAINING=FUTURE–now。 如果REMAINING小于等于0, 表示已, 直接退出, 否
继续执wait(REMAINING)

一个简单的数据库连接池(只是简单展示一下这个模式,就不写怎么用了)

public class ConnectionPool {
		//Connection只是一个接口,具体实现是由数据库厂商决定的
		private LinkedList<Connection> pool = new LinkedList<Connection>() ;
		
		public ConnectionPool(int initialSize) {
			if (initialSize > 0) {
				for (int i = 0; i < initialSize; i++) {
				   pool. addLast(ConnectionDriver. createConnection()) ;
				}
			}
		}
		
		public void releaseConnection(Connection connection) {
			if (connection ! = null) {
				synchronized (pool) {
					// 连接释放后需要进行通知, 这样其他消费者能够感知到连接池中已经归还了一个连接
					pool.addLast(connection) ;
					pool.notifyAll() ;
				}
			}
		}
		
		// 在mills内无法获取到连接, 将会返回null
		public Connection fetchConnection(long mills) throws InterruptedException {
			synchronized (pool) {
				// 完全超时
				if (mills <= 0) {
					while (pool. isEmpty() ) {
					    pool.wait() ;
					}
					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 result = null;
					if (! pool.isEmpty() ) {
					    result = pool.removeFirst() ;
					}
					return result;
				}
			}
		}
	}

在这一段代码中

while (pool.isEmpty() && remaining > 0) {

     pool.wait(remaining) ;
     remaining = future - System.currentTimeMillis() ;
}

这里的wait()方法我是这么理解的,在wait方法执行后,一直经过了remaining毫秒后还未有其他线程唤醒他时,这个线程相当于自己唤醒了,但是这个自己唤醒自己还是有一个条件,就是他必须获取pool的锁,否则就算超时时间到了他还是被阻塞的,不能继续往下执行,所以这个线程最终的超时时间不一定是刚好的remaining毫秒。当然这里加个超时时间还是有用的,毕竟不会永远阻塞自己