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

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中使用Jedis操作Redis,在高并发的情况下,应用卡死、报无法获取连接错误的处理方式)