在了解到wait、notify的使用方式以后,咱们使用wait、notify来实现一个链接池。若是还有不清楚wait、notify使用的,请进入传送门:http://www.javashuo.com/article/p-rokuvpbq-cw.htmljava
首先咱们先来了解下链接池的基本原理segmentfault
首先咱们有一个空实现的链接类Connection函数
@Data static class Connection { private String connectionName; public Connection(String connectionName) { this.connectionName = connectionName; } }
此处只为了测试,该类只有一个名字属性。另外使用了lombok来自动生成set、get方法
接下来就是链接池的基本实现测试
@Data public class ConnectionPoolOfWaitNotify { private Integer capacity = 4;//链接池中的链接数 LinkedList<Connection> linkedList = new LinkedList<>(); //链接容器 public ConnectionPoolOfWaitNotify() { IntStream.rangeClosed(1, capacity).forEach(i -> {//构造方法中初始化全部链接 linkedList.addLast(new Connection("connection-" + i)); }); } //获取链接 public Connection getConnectioin(long time) throws InterruptedException { synchronized (linkedList) { if (!linkedList.isEmpty()) {//若是存在,拿走第一个 return linkedList.removeFirst(); } if (time <= 0) {//等到拿到链接再返回 while (linkedList.isEmpty()) { linkedList.wait(); } return linkedList.removeFirst(); } long lastTime = System.currentTimeMillis() + time; long sleepTime = time; while (linkedList.isEmpty() && sleepTime > 0) { linkedList.wait(sleepTime); sleepTime = lastTime - System.currentTimeMillis(); } if (!linkedList.isEmpty()) { return linkedList.removeFirst(); } else { return null; } } } //归还链接 public void revertConnection(Connection connection) { synchronized (linkedList) { linkedList.addLast(connection); linkedList.notifyAll();//归还链接后通知其余拿链接的线程 } } }
链接池中,主要有两个方法。一个是获取链接(可控制超时时间,超时时间小于等于0则永不超时),一个是归还链接。
主要的逻辑在获取链接的方法里面,当获取不到链接时,使用wait()方法来使得当前获取链接的线程进入等待状态。而后在归还链接成功以后,调用notifyAll()方法通知全部正在等待的线程能够继续获取链接了,可是继续获取链接时,还必须继续抢夺锁,只有占锁成功的线程,才能继续执行获取链接操做。this
以后执行如下测试代码spa
public static void main(String[] args) { int allNum = 100; AtomicInteger successNum = new AtomicInteger(0); ConnectionPoolOfWaitNotify connectionPoolOfWaitNotify = new ConnectionPoolOfWaitNotify(); IntStream.rangeClosed(1, allNum).parallel().forEach(i -> { Connection connection = null; try { connection = connectionPoolOfWaitNotify.getConnectioin(100); if (null != connection) { successNum.addAndGet(1); System.out.println("线程" + i + "拿到链接" + connection.getConnectionName()); Thread.sleep(200); } else { System.out.println("线程" + i + "没有拿到链接"); } } catch (Exception e) { e.printStackTrace(); } finally { if (null != connection) { connectionPoolOfWaitNotify.revertConnection(connection); } } }); System.out.println("总共拿链接次数:" + allNum + ",拿到链接次数:" + successNum.get()); }
allNum为总共获取链接次数,successNum当中记录获取成功的次数。每次拿链接的超时时间为100毫秒,拿到链接后200的休眠(模拟业务处理)以后归还链接。并且在构造函数中直接初始化了全部的链接(读者能够考虑下如何作到按需来初始化的话)。运行后结果以下线程
线程23拿到链接connection-1 线程69没有拿到链接 线程10拿到链接connection-2 线程74拿到链接connection-4 线程25拿到链接connection-3 线程6没有拿到链接 线程70没有拿到链接 线程72没有拿到链接 线程71没有拿到链接 线程73没有拿到链接 线程75拿到链接connection-1 总共拿链接次数:100,拿到链接次数:25
100次只能拿到25次,那咱们若是设置永不超时呢?调用方式以下,修改超时时间为0便可code
connection = connectionPoolOfWaitNotify.getConnectioin(0);
以后再次运行结果以下图片
线程70拿到链接connection-1 线程58拿到链接connection-2 线程16拿到链接connection-3 线程60拿到链接connection-4 线程71拿到链接connection-1 线程59拿到链接connection-4 线程67拿到链接connection-3 线程68拿到链接connection-2 总共拿链接次数:100,拿到链接次数:100
OK,所有拿到,没毛病ci