redis 连接池并发读取数据,连接池无法回收连接

我自己编写了一个redis的客户端,在测并发的时候发现获取到的redis连接无法归还到连接池

这是单元测试类

public class RedisTest {

    private static final ExecutorService executorService = Executors.newFixedThreadPool(1000);
    private static CyclicBarrier c = new CyclicBarrier(200);


    @Test
    public void simpleTest() {
        System.out.println(RedisUtil.get("yany_test"));
    }

    @Test
    public void test() throws Exception {
        for (int i = 0; i < 300; i++) {

            executorService.submit(() -> {
//                try {
//                    c.await();
//                } catch (Exception e) {
//                    e.printStackTrace();
//                }

                System.out.println("num  end end====" + c.getNumberWaiting() + "   " + Thread.currentThread().getId() + " " + Thread.currentThread().getName());
                System.out.println("id =====>:" + Thread.currentThread().getId() + " " + Thread.currentThread().getName() + " " + RedisUtil.get("yany_test"));

            });
        }
        Thread.sleep(200000);
    }
}

基本配置

jedis.pool.maxActive=20
jedis.pool.maxIdle=5
jedis.pool.maxWait=100

连接的工厂类

public class RedisFactory {

    private static JedisPool jedisPool = null;
    //把redis连接对象放到本地线程中

    static {
        try {
            Properties props = new Properties();
            //加载连接池配置文件
            props.load(RedisFactory.class.getClassLoader().getResourceAsStream("redis-config.properties"));
            // 创建jedis池配置实例
            JedisPoolConfig config = new JedisPoolConfig();
            // 设置池配置项值
            config.setMaxTotal(Integer.valueOf(props.getProperty("jedis.pool.maxActive")));
            config.setMaxIdle(Integer.valueOf(props.getProperty("jedis.pool.maxIdle")));
            config.setMaxWaitMillis(Long.valueOf(props.getProperty("jedis.pool.maxWait")));
            config.setTestOnBorrow(Boolean.valueOf(props.getProperty("jedis.pool.testOnBorrow")));
            config.setTestOnReturn(Boolean.valueOf(props.getProperty("jedis.pool.testOnReturn")));
            // 根据配置实例化jedis池
            jedisPool = new JedisPool(config, props.getProperty("redis.ip"),
                    Integer.valueOf(props.getProperty("redis.port")),
                    Integer.valueOf(props.getProperty("redis.timeout")),
                    props.getProperty("redis.passWord"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获得连接
     *
     * @return Jedis
     */
    public static Jedis getConn() {
        //Redis对象
        return jedisPool.getResource();
    }

    //新版本用close归还连接
    public static void closeConn(Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    //关闭池
    public static void closePool() {
        if (jedisPool != null) {
            jedisPool.close();
        }
    }

    public static JedisPool getJedisPool() {
        return jedisPool;
    }
}

封装的操作类


public class RedisUtil {

    public static String get(String key) {
        Jedis jedis = null;
        try {
            jedis = RedisFactory.getConn();
            return jedis.get(key);
        } finally {
            RedisFactory.closeConn(jedis);
        }
    }
}

这是输出结果: 并发之后只有20个线程能读出来,其他线程一直在等待,也不报超时
图片描述

理论上不应该,所有线程都能读出来吗?当一个线程执行完之后,会返回连接,问什么出现连接不够的现象?

阅读 4.8k
1 个回答

按照题主的代码执行了一下,都能读到值,看题中的图片,线程265也已经读到了值,不知道题主是怎么判断只有20个线程能读出来的,另外所有线程都会阻塞,这是因为你使用了FixedThreadPool,然而却没有显示的去关闭它,FixedThreadPool的核心线程没有超时策略,所以并不会自动关闭。当他执行完一个任务后会阻塞等待下一个任务,如果没有下一个任务,他会一直阻塞。这就是为什么其他线程一直在等待,也不报超时的原因。题主可以换一个线程池或者手动显示的去关闭它(所有线程执行完成后调用shutdown方法)。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题