Java多线程实例——等待超时模式

1. 什么是超时等待?

什么是超时等待?

调用一个方法时,等待一段时间(一般给定一个时间段),如果该方法能够在给定的时间段内得到结果,那么将结果立刻返回,反之,超时返回默认结果。这就是超时等待。

等待/通知的经典范式,即加锁,条件循环和处理逻辑三个步骤,而这种范式无法做到超时等待。

2. 等待/通知的经典范式。
等待/通知的经典范式,可以分为两部分,分别针对等待方(消费者)和通知方(生产者)。

Java多线程实例——等待超时模式_第1张图片

3. 等待超时模式
由于经典的等待/通知范式无法做到超时等待,也就是说,当消费者在获得锁后,如果条件不满足,等待生产者改变条件之前会一直处于等待状态,在一些实际应用中,会浪费资源,降低运行效率。
事实上,只要对经典范式做出非常小的改动,就可以加入超时等待。
假设超时时间段是T,那么可以推断出,在当前时间now+T之后就会超时。
定义如下变量:
等待持续时间remaining = T;
超时时间future = now + T。
伪代码如下所示:
long future = System.currentTimeMillis() + mills;
		long remaining = mills;
		synchronized (lock) {
			while (!condition && remaining > 0) {
				wait(remaining);
				remaining = future - System.currentTimeMillis();
			}
			//处理代码
		}
4. 一个简单的数据库连接池实例。
这个代码实例使用等待超时模式来构造一个简单的数据库连接池,在实例中模拟从连接池中获取、使用和释放连接的过程,而客户端获取连接的过程被设定为等待超时的模式,在代码中设定如果再1000ms内如果无法获取到可用的连接,返回null。可以设置连接池的大小。
(1)连接池的定义,代码清单ConnectionPool.java
import java.sql.Connection;
import java.util.LinkedList;

public class ConnectionPool {
	private LinkedList pool = new LinkedList();
	
	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();
			}
		}
	}
	
	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 connection = null;
				if(!pool.isEmpty()){
					connection = pool.removeFirst();
				}
				return connection;
			}
		}
	}
}
(2)模拟数据库驱动方提供的实现了java.sql.Connection的接口的实现类,代码清单ConnectionDriver.java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.util.concurrent.TimeUnit;

public class ConnectionDriver {
	static class ConnectionHandler implements InvocationHandler {
		@Override
		public Object invoke(Object arg0, Method arg1, Object[] arg2)
				throws Throwable {
			if (arg1.getName().equals("commit")) {
				TimeUnit.MILLISECONDS.sleep(100);
			}
			return null;
		}
	}

	public static final Connection createConnection() {
		return (Connection) Proxy.newProxyInstance(
				ConnectionDriver.class.getClassLoader(),
				new Class[] { Connection.class }, new ConnectionHandler());
	}
}
3 )模拟客户端,测试连接池连接成功率,代码清单ConnectionPoolTest.java
import java.sql.Connection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;

public class ConnectionPoolTest {
	static ConnectionPool pool = new ConnectionPool(10);
	static CountDownLatch start = new CountDownLatch(1);
	static CountDownLatch end;

	public static void main(String[] args) throws Exception {
		int threadCount = 20;
		end = new CountDownLatch(threadCount);
		int count = 20;
		AtomicInteger got = new AtomicInteger();
		AtomicInteger noGot = new AtomicInteger();
		for (int i = 0; i < threadCount; i++) {
			Thread thread = new Thread(new ConnectionRunner(count,got,noGot),"ConnectionRunnerThread");
			thread.start();
		}
		start.countDown();
		end.await();
		System.out.println("total invoke: " + (threadCount * count));
		System.out.println("got connection " + got);
		System.out.println("not got connection " + noGot);
	}
	
	static class ConnectionRunner implements Runnable {
		int count;
		AtomicInteger got;
		AtomicInteger noGot;

		public ConnectionRunner(int count, AtomicInteger got,
				AtomicInteger noGot) {
			this.count = count;
			this.got = got;
			this.noGot = noGot;
		}

		@Override
		public void run() {
			try {
				start.await();
			} catch (Exception e) {
			}
			while (count > 0) {
				try {
					Connection connection = pool.fetchConnection(1000);
					if (connection != null) {
						try {
							connection.createStatement();
							connection.commit();
						} finally {
							pool.releaseConnection(connection);
							got.incrementAndGet();
						}
					} else {
						noGot.incrementAndGet();
					}
				} catch (Exception e) {
				} finally {
					count--;
				}
			}
			end.countDown();
		}
	}
}
借鉴书籍《Java并发编程的艺术》
欢迎转载,但请出名出处。

你可能感兴趣的:(Java)