首页 新闻 会员 周边 捐助

多线程下redis的疑问,请大神指导 附源码

0
悬赏园豆:20 [待解决问题]

public class JedisConfig
{
//redis池
private static JedisPool jedisPool = null;

//redis服务器的ip
private static final String HOST = "127.0.0.1";

//端口
private static final int PORT = 6379;

//可用连接实例的最大数目
private static final int MAX_ACTIVE = 1024;

//控制一个pool最多有多少个状态为空闲的jedis实例
private static final int MAX_IDLE = 200;

//jedis池没有对象返回时,最大等待时间
private static final int MAX_WAIT = 10000;

//超时时间
private static final int TIMEOUT = 10000;

//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
private static boolean TEST_ON_BORROW = true;

private static JedisConfig instance = null;

/**
* 初始化jedisPool
*/
private void initJedisPool()
{
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, HOST, PORT, TIMEOUT);
}

public synchronized Jedis getJedis()
{
Jedis jedis = null;
if (jedisPool != null)
{
jedis = jedisPool.getResource();
}
return jedis;
}

/**
* 如果jedis为空,则进行初始化
*/
private JedisConfig()
{
if (jedisPool == null)
{
initJedisPool();
}
}

/**
* 释放jedis资源
* @param jedis
*/
public synchronized void returnResource(Jedis jedis)
{
if (jedis != null)
{
jedis.close();
}
}
/**
*
* 单例获取JedisConfig实例
*
* @return 返回当前的jedis实例
*/
public static JedisConfig getInstance()
{
if (instance == null)
{
synchronized (JedisConfig.class)
{
if (instance == null)
{
instance = new JedisConfig();
}
}

}
return instance;
}
}

这个是我的初始化代码  下面是调用代码

 

public class JedisManage
{
/**
* 获取redis实例
*/
private static Jedis jedis = JedisConfig.getInstance().getJedis();

/**
* 存储图片流信息
*
* @param key key
* @param fileId 字段值
* @param value 存储值
*/
public static void setImageInfoToRedis(String key,String fileId,String value)
{

synchronized (jedis)
{
jedis.hset(key, fileId, value);
}
}

/**
* 获取图片信息
*
*
* @param key
* @param fileId
* @return
*/
public static String getImageInfo(String key,String fileId)
{
return jedis.hget(key, fileId);
}

}

项目整个背景是前台每一次请求都会加载一个小图片,所以我想使用redis缓存图片,如果下次请求是同一个我就直接从redis中读取,由于前台的请求非常频发,一秒钟大概有400次,这样的情况下程序异常退出,不知道是自己代码写的有问题还是,求大神指导!!!!
程序在多线程环境下,异常退出,分析后发现是redis的问题,因为要是不适用redis的缓存就是好的。

 

 

 



倾慕已久的主页 倾慕已久 | 初学一级 | 园豆:182
提问于:2017-11-23 20:02
< >
分享
所有回答(1)
0

synchronized (jedis)
{
jedis.hset(key, fileId, value);
}

这个同步没意义,去掉。

异常这里看不出来,就一个hget,一个hset,这个没任何问题,其他的你看下是不是你在使用完相关方法后没有进行回收(调用你的returnResource方法,我记得较新的版本中jedis已经实现了Closeable接口,在jdk1.8中可以直接try(Jedis jedis=xxx.getResource()){...execute...})

Daniel Cai | 园豆:10424 (专家六级) | 2017-11-24 09:28

您好! 我在使用jedis时,直接在类中定义的是一个静态变量,你可以看下这样合适不

private static Jedis jedis = JedisConfig.getInstance().getJedis();

还有就是我每次hget完后需要关闭jedis吗,开始我也是hset后关闭jedis 也就是调用我的returnResource方法 hget完后也调用,但是发现hget完后调用会报错

支持(0) 反对(0) 倾慕已久 | 园豆:182 (初学一级) | 2017-11-24 10:27

@倾慕已久: jedis中的close方法实际是将连接判断后选择销毁或者还给连接池,你报错是报什么?

支持(1) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-11-24 10:43

@Daniel Cai: 按道理来说我内存中只存在一个jedis,这样多线程情况下是不是就会出现并发问题

支持(0) 反对(0) 倾慕已久 | 园豆:182 (初学一级) | 2017-11-24 11:34

@Daniel Cai: 因为我获取的是静态的jedis,而不是在每一个set或get中分别单独去获取jedis

支持(0) 反对(0) 倾慕已久 | 园豆:182 (初学一级) | 2017-11-24 11:35

@倾慕已久: 不会,首先你那是个static字段,其次你后面实例化有个标准的double check(其实这个都没必要有),多线程下这块不存在问题。

你的问题是在你第一次执行了某个命令后会回收这个jedis,而你把这个jedis对象提升到字段级别导致后面再用这个字段的时候使用的是一个已经close过的jedis对象了

你这块正确的写法应该是把你那JedisConfig作为静态字段,方法体中每次都是

try(Jedis jedis=config.getJedis()){

  ...

}

支持(1) 反对(0) Daniel Cai | 园豆:10424 (专家六级) | 2017-11-24 11:46
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册