在Java中使用Jedis操作Redis,在高并发的情况下,应用卡死、报无法获取连接错误的处理方式

原创 2017年03月04日 11:29:06
1.JedisUtil:工具类,单例,避免获取多个jedisPool 对象

package JedisTest;
import org.apache.commons.lang.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;


/**
 * Jedis工具类
 * @author lanchunqiu
 *
 */
public class JedisUtil {

    private static int PORT = 6379;
    /**
     * 可用连接实例的最大数目,如果不设默认为8,;如果赋值为-1表示不限制;如果pool已经分配了MAX_ACTIVE个jedis实例,则此时pool的状态为exhausted(耗尽)
     */
    private static int MAX_ACTIVE = 500;
    
    /**
     * 控制一个pool最多有多少个状态为idle(空闲)的jedis实例,不设默认值为8
     */
    private static int MAX_IDLE = 10;
    
    /**
     * 控制一个pool最少有多少个状态为空闲的jedis实例
     */
    private static int MIN_IDLE = 100;
    
    /**
     * 在borrow一个jedis实例时,是否提前进行validate(验证)操作,如果为true,则得到的jedis实例都是可用的
     */
    private static boolean TEST_ON_BOOROW = true;
    
    /**
     * 在将连接放回池中前,自动检验连接是否有效  
     */
    private static boolean TEST_ON_RETURN = true;
    
    /**
     * 自动测试池中的空闲连接是否都是可用连接  
     */
    private static boolean TEST_WHILE_IDLE = true;
    /**
     * 等待一个可用连接的最大时间,单位毫秒,默认值为-1,表示用不超时;如果超过等待时间,则直接抛出JedisConnectionException
     */
    private static int MAX_WAIT = 60000;
    
    /**
     * 每次释放连接的最大数目
     */
    private static int NUM_TESTS_PER_EVICTION_RUN = 10;
    
    /**
     * 释放连接的扫描间隔(毫秒)
     */
    private static int TIME_BETWEEN_EVICTION_RUNS_MILLIS = 10;
    
    /**
     * 连接空闲多久后释放(毫秒), 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放
     */
    private static int SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS= 100;
    
    private static int TIMEOUT = 100000;
    
    private static JedisPool jedisPool = null; 
    private static JedisUtil jedisUtil = null;
    protected JedisUtil(){
    try{
System.out.println("初始化redis缓存!"); 
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxWaitMillis(MAX_WAIT);
config.setMaxTotal(MAX_ACTIVE);
config.setMaxIdle(MAX_IDLE);
config.setMinIdle(MIN_IDLE);
config.setTestOnBorrow(TEST_ON_BOOROW);
       config.setTestOnReturn(TEST_ON_RETURN);  
       config.setTestWhileIdle(TEST_WHILE_IDLE);  
       config.setNumTestsPerEvictionRun(NUM_TESTS_PER_EVICTION_RUN);
       config.setTimeBetweenEvictionRunsMillis(TIME_BETWEEN_EVICTION_RUNS_MILLIS);
       config.setMinEvictableIdleTimeMillis(SOFT_MIN_EVICTABLE_IDLE_TIME_MILLIS);

jedisPool = new JedisPool(config, "127.0.0.1",PORT,TIMEOUT,"asopa_redis");
//jedisPool = new JedisPool(config, "127.0.0.1",PORT);
    }catch(Exception e){
System.out.println("初始化JedisPool异常:" + e);
jedisPool = null;
}
    }
    
    public static synchronized JedisUtil getInstance(){
    if(null == jedisUtil){
    jedisUtil = new JedisUtil();
    }
    return jedisUtil;
    }
    
    /**
     * 设置 String
     * @param key
     * @param value
     */
    public static void setString(String key ,String value){
    Jedis jedis = null;
        try {
        System.out.println("【存】可用连接数"+jedisPool.getNumActive());
        jedis = jedisPool.getResource();
            value = StringUtils.isEmpty(value) ? "" : value;
            jedis.set(key,value);
        } catch (Exception e) {
            System.out.println("Set key error : " + e);
        } finally{
jedisPool.returnResource(jedis);//注意:每次使用完jedis时一定要释放
}
    }
    
    /**
     * 取值
     * @param key
     * @return
     */
    public static String get(String key){
    Jedis jedis = null;
    try{
    System.out.println("【取】可用连接数"+jedisPool.getNumActive());
    jedis = jedisPool.getResource();
    return jedis.get(key);
    }
    catch(Exception e){
    System.out.println("从缓存中取值失败:"+e.getMessage());
    return null;
    } finally{
    jedisPool.returnResource(jedis);
    }
   
    }

}


2.JedisTestThread 线程类

package JedisTest;
/**
 * 
 * @author lanchunqiu
 *
 */
public class JedisTestThread extends Thread{
private JedisUtil jedisUtil = null;
public JedisTestThread(int i,JedisUtil jedisUtil){
System.out.println("=======线程"+i+"========"+jedisUtil.hashCode());
this.jedisUtil = jedisUtil;
}


public void run(){
jedisUtil.setString("foo1", "foo1");
System.out.println(jedisUtil.get("foo1"));
}
}

3.测试类:开启了1000个线程,如果想要启动更多的线程,就需要调整MAX_ACTIVE 参数值,开启1000个线程时,我设置的MAX_ACTIVE =500

package JedisTest;
import java.io.IOException;

/**
 * 
 * @author lanchunqiu
 *
 */
public class JedisTest {
public static void main(String[] args) throws IOException {
JedisUtil jedisUtil = JedisUtil.getInstance();
for (int i=0;i<1000;i++){
JedisTestThread thread1 = new JedisTestThread(i+1,jedisUtil);
thread1.start();
}
}
}

4.测试结果:就算连接数为0时也没出现异常,占用的连接会很快释放。

还请大牛多指教!

5.使用的jar包:

(1)jedis-2.8.0.jar

(2)commons-pool2-2.4.2.jar

(3)commons-lang-2.4.jar







Java之——redis并发读写锁,使用Redisson实现分布式锁

最近由于工作很忙,很长时间没有更新博客了,今天为大家带来一篇有关Redisson实现分布式锁的文章,好了,不多说了,直接进入主题。 1. 可重入锁(Reentrant Lock) Redisson的分...

java 用redis如何处理电商平台,秒杀、抢购超卖

一、刚来公司时间不长,看到公司原来的同事写了这样一段代码,下面贴出来: 1、这是在一个方法调用下面代码的部分: if (!this.checkSoldCountByRedisDate(key, l...

Redis上踩过的一些坑-美团

上上周和同事(龙哥)参加了360组织的互联网技术训练营第三期,美团网的DBA负责人侯军伟给大家介绍了美团网在redis上踩得一些坑,讲的都是干货和坑。     分为5个部分:    一、周期性...

poj 1060 Modular multiplication of polynomials

题目大意:规定加法和减法操作都是异或操作;乘法,除法操作不变。给你三个多项式f,g,h,求出f * g / h 的余下的多项式。 思路:高精度问题,按照题目要求模拟就行。 #include...

jedispool 连 redis 高并发卡死 解决方案

java端在使用jedispool 连接redis的时候,在高并发的时候经常卡死,或报连接异常,JedisConnectionException,或者getResource 异常等各种问题 在使用j...
  • liuvlun
  • liuvlun
  • 2015年11月25日 11:26
  • 9415

利用redis + lua解决抢红包高并发的问题

抢红包的需求分析 抢红包的场景有点像秒杀,但是要比秒杀简单点。 因为秒杀通常要和库存相关。而抢红包则可以允许有些红包没有被抢到,因为发红包的人不会有损失,没抢完的钱再退回给发红包的人即可。 另外像小米...

jedispool 连 redis 高并发卡死

java端在使用jedispool 连接redis的时候,在高并发的时候经常卡死,或报连接异常,JedisConnectionException,或者getResource 异常等各种问题 在使用je...
  • tuposky
  • tuposky
  • 2015年04月28日 18:20
  • 9494

redis机器物理死机问题分析(OOM)

问题的表现在测试主搜索增量bolt的loader程序的时候,它有一步是将数据加载到redis里。在平时做测试的时候,几次发生做loader导致了redis所在的测试机器死机(物理死机)。问题分析造成了...

Jedis操作Redis技巧详解

对于Redis的部署模式有两种,单机模式 和 集群模式。因此,本文的介绍也从这两个方面进行介绍。众所周知,Jedis是最著名的Redis java客户端操作类库,几乎支持所有的Redis操作。本文就是...

彻底解决 Jedis 连接池 获取不到连接,连接放回连接池错误的问题

Could not get jedis from the pool.
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:在Java中使用Jedis操作Redis,在高并发的情况下,应用卡死、报无法获取连接错误的处理方式
举报原因:
原因补充:

(最多只允许输入30个字)