面試官:如何實現(xiàn)一個連接池,我當(dāng)場懵了
點擊上方“JavaEdge”,關(guān)注公眾號
什么是連接池?
結(jié)構(gòu)

連接池對外提供如下接口:
獲得連接
歸還連接

連接池結(jié)構(gòu)示意圖


TCP連接的客戶端SDK,對外提供API方式
連接池和連接分離式


最佳實踐

內(nèi)置連接池


最佳實踐

非連接池


最佳實踐

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會關(guān)閉客戶端連接,導(dǎo)致連接斷開
線程1和2先后寫入get a和get b請求,Redis也返回了值1和2,但是線程2先讀取了數(shù)據(jù)1就會出現(xiàn)數(shù)據(jù)錯亂的問題。
修復(fù)

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

JedisPool
JedisPool繼承JedisPoolAbstract又繼承抽象類Pool,Pool內(nèi)部持有Apache Common的GenericObjectPool。
所以JedisPool的連接池其實就是直接復(fù)用的GenericObjectPool,并沒有自己實現(xiàn)一套池子。
往期推薦

目前交流群已有 800+人,旨在促進技術(shù)交流,可關(guān)注公眾號添加筆者微信邀請進群
喜歡文章,點個“在看、點贊、分享”素質(zhì)三連支持一下~
評論
圖片
表情















