面试官:如何实现一个连接池,我当场懵了
点击上方“JavaEdge”,关注公众号
什么是连接池?
结构

连接池对外提供如下接口:
获得连接
归还连接

连接池结构示意图


TCP连接的客户端SDK,对外提供API方式
连接池和连接分离式


最佳实践

内置连接池


最佳实践

非连接池


最佳实践

Jedis属于哪种呢?
@PostConstructpublic void init() {try (Jedis jedis = new Jedis("127.0.0.1", 6379)) {Assert.isTrue("OK".equals(jedis.set("a", "1")), "set a = 1 return OK");Assert.isTrue("OK".equals(jedis.set("b", "2")), "set b = 2 return OK");}}
Jedis jedis = new Jedis("127.0.0.1", 6379);new Thread(() -> {for (int i = 0; i < 1000; i++) {String result = jedis.get("a");if (!result.equals("1")) {log.warn("Expect a to be 1 but found {}", result);return;}}}).start();new Thread(() -> {for (int i = 0; i < 1000; i++) {String result = jedis.get("b");if (!result.equals("2")) {log.warn("Expect b to be 2 but found {}", result);return;}}}).start();TimeUnit.SECONDS.sleep(5);
//错误1[14:56:19.069] [Thread-28] [WARN ] [.t.c.c.redis.JedisMisreuseController:45 ] - Expect b to be 2 but found 1//错误2redis.clients.jedis.exceptions.JedisConnectionException: Unexpected end of stream.at redis.clients.jedis.util.RedisInputStream.ensureFill(RedisInputStream.java:202)at redis.clients.jedis.util.RedisInputStream.readLine(RedisInputStream.java:50)at redis.clients.jedis.Protocol.processError(Protocol.java:114)at redis.clients.jedis.Protocol.process(Protocol.java:166)at redis.clients.jedis.Protocol.read(Protocol.java:220)at redis.clients.jedis.Connection.readProtocolWithCheckingBroken(Connection.java:318)at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:255)at redis.clients.jedis.Connection.getBulkReply(Connection.java:245)at redis.clients.jedis.Jedis.get(Jedis.java:181)at org.geekbang.time.commonmistakes.connectionpool.redis.JedisMisreuseController.lambda$wrong$1(JedisMisreuseController.java:43)at java.lang.Thread.run(Thread.java:748)//错误3java.io.IOException: Socket Closedat java.net.AbstractPlainSocketImpl.getOutputStream(AbstractPlainSocketImpl.java:440)at java.net.Socket$3.run(Socket.java:954)at java.net.Socket$3.run(Socket.java:952)at java.security.AccessController.doPrivileged(Native Method)at java.net.Socket.getOutputStream(Socket.java:951)at redis.clients.jedis.Connection.connect(Connection.java:200)... 7 more
写操作互相干扰,多条命令交织,必然是非法的Redis命令,则Redis会关闭客户端连接,导致连接断开
线程1和2先后写入get a和get b请求,Redis也返回了值1和2,但是线程2先读取了数据1就会出现数据错乱的问题。
修复

public void init() {Runtime.getRuntime().addShutdownHook(new Thread(() -> {jedisPool.close();}));}
Jedis#close

JedisPool
JedisPool继承JedisPoolAbstract又继承抽象类Pool,Pool内部持有Apache Common的GenericObjectPool。
所以JedisPool的连接池其实就是直接复用的GenericObjectPool,并没有自己实现一套池子。
往期推荐

目前交流群已有 800+人,旨在促进技术交流,可关注公众号添加笔者微信邀请进群
喜欢文章,点个“在看、点赞、分享”素质三连支持一下~
评论















