在网上看到好多说jedis实例是非线程安全的,然后通过JedisPool连接池去管理实例,在多线程情况下让每个线程有自己的独立的jedis实例,但是都没有说明为啥jedis实例是非线程安全的,自己对线程安全和非线程安全目前还理解不够深刻,下面就剖析一下jedis的源码。
Jedis 通过继承 BinaryJedis 来持有Client对象,Client类继承BinaryClient,BinaryClient继承Connection,下面分别介绍各个类主要做什么事情。
Connection:主要用于与redis服务器建立Socket连接,并管理连接
Protocol:主要用于redis客户端通信协议的处理
BinaryClient:是对Connection的包装,将字节数据发送Connection中进行通信协议的编码,同时实现了Redis字节命令的相关接口
Client:是对BinaryClient的包装,主要用于处理字符数据到字节数据的转换工作,然后通过BinaryClient的接口来实现后续与Redis服务器的交互,同时实现了Redis字符命令的相关接口
BinaryJedis:持有Client对象,Transaction事务对象,Pipeline管道对象,其中与Client是组成关系,强约束,其它两个是分别在使用事务和管道时才会使用到。通过持有的Client来执行相关命令的,此类处理字节命令
Jedis:继承BinaryJedis,与Client类似,Jedis处理字符命令,BinaryJedis处理字节命令。
注意:关于jedis多线程使用单实例的话线程不安全,因为发送命令和获取返回值时使用全局变量RedisOutputStream
和RedisInputStream
测试代码
/**
* @ClassName: JedisTest
* @Description:
* @author pengzhihao
* @date 2018年8月21日 下午10:41:55
*/
public class JedisTest {
public void test(){
final Jedis jedis = new Jedis("localhost", 6379);
jedis.auth("root");
// jedis.set("jedis_key", "666");
// jedis.close();
for(int i = 0; i < 100; i++){
new Thread(new Runnable() {
public void run() {
try {
String v = String.valueOf(this.hashCode());
jedis.set("jedis_key", v);
System.out.println("设置时的v:" + v + ",读取的v:" + jedis.get("jedis_key"));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
}
运行结果: