Why Sharing a Jedis Instance Across Threads Breaks Redis – Understanding Connection Pools
This article explains the concept of connection pools, compares pooled and direct TCP connections, demonstrates thread‑safety issues when reusing a Jedis instance in multithreaded code, and shows how to fix the problem by using JedisPool with proper resource management.
What Is a Connection Pool?
A connection pool provides two external interfaces—acquire a connection and return a connection—and exposes configurable parameters such as minimum idle connections and maximum connections. Internally it handles connection establishment, heartbeat maintenance, connection management, idle‑connection reclamation, and connection‑availability detection.
Connection‑Pool vs. Direct Connection
The typical XXXPool class implements the pool logic: first obtain an XXXConnection, use it to request the server, then return the connection. XXXPool must be thread‑safe because it can be accessed concurrently, while the individual XXXConnection objects are not thread‑safe.
Built‑In Connection Pools in Client SDKs
Many middleware and database client SDKs embed a connection pool. The SDK maintains the pool internally, so users interact with a higher‑level client class (e.g., XXXClient) without worrying about acquiring or releasing connections. The client class itself is thread‑safe.
Non‑Pooled Usage Pitfalls
When a client SDK does not use a pool, each operation creates a new TCP connection (a short‑lived connection). This approach incurs connection‑setup overhead, lacks thread safety, and generally yields poorer performance. The API is usually named XXXConnection to distinguish it from the pooled variant.
Case Study: Misusing Jedis in a Multithreaded Environment
First, two keys are initialized in Redis:
@PostConstruct
public 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");
}
}Then two threads share a single Jedis instance, each repeatedly reading a different key:
Jedis jedis = new Jedis("127.0.0.1", 6379);
new Thread(() -> {
for (int i = 0; i < 1000; i++) {
String result = jedis.get("a");
if (!"1".equals(result)) {
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 (!"2".equals(result)) {
log.warn("Expect b to be 2 but found {}", result);
return;
}
}
}).start();
TimeUnit.SECONDS.sleep(5);Repeated execution produces various errors, such as mismatched values, JedisConnectionException: Unexpected end of stream, and java.io.IOException: Socket Closed.
Write operations interleave, forming illegal Redis commands that cause the server to close the connection.
Even if commands are sent in order, a thread may read the response intended for another thread, leading to data corruption.
Root Cause Analysis
When a Jedis object is reused across threads, its underlying RedisOutputStream is also shared. Multiple threads writing concurrently cannot guarantee that a complete command is written atomically, nor that no other thread writes between the write and the subsequent read. This explains the observed protocol errors and value mismatches.
Fix: Use JedisPool
The proper solution is to obtain Jedis instances from the thread‑safe JedisPool. Declare the pool as a static shared resource and use try‑with‑resources (or explicit close()) to return connections automatically. Adding a shutdown hook ensures the pool is closed when the application exits.
@PostConstruct
public void init() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
jedisPool.close();
}));
}How JedisPool Works Internally
JedisPoolextends JedisPoolAbstract, which in turn extends the abstract Pool class. The Pool holds an Apache Commons GenericObjectPool that performs the actual object reuse. Therefore, JedisPool does not implement its own pooling algorithm; it delegates to GenericObjectPool.
Conclusion
The Jedis API offers both pooled and non‑pooled usage modes. JedisPool provides a thread‑safe connection pool that should be used in multithreaded applications, while a plain Jedis instance is a non‑thread‑safe single connection and must not be shared across threads.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JavaEdge
First‑line development experience at multiple leading tech firms; now a software architect at a Shanghai state‑owned enterprise and founder of Programming Yanxuan. Nearly 300k followers online; expertise in distributed system design, AIGC application development, and quantitative finance investing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
