zoukankan      html  css  js  c++  java
  • 记一个由于代码编码问题导致的死锁

      项目中使用了redis,由于项目更迭,配置也比较乱,在1点几的时候用的配置参数是maxActive等,在redis的2点几版本中其实已经废弃了,也没有仔细研究就直接去掉了,导致redis池中的可用资源一直是默认的8个,而且还有个更大的问题,配置的超时时间不对。见下图所示,配置在JedisPool的初始化参数中,这个没仔细看代码,瞄了一眼应该是不管用的。

      真正的配置应该在这里:

      JedisPoolConfig中maxTotal也应该根据项目需要选择合适的大小,否则只会是默认的8个!!

      回归正题,遇到的问题现象就是系统失去响应,查看线程dump发现所有的线程都卡在这:

    "DubboServerHandler-192.168.213.250:20889-thread-198" daemon prio=10 tid=0x00007f3a3b794800 nid=0x83b waiting on condition [0x00007f3a1ed86000]
       java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000700c6c208> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
        at org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:583)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:442)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:363)
        at redis.clients.util.Pool.getResource(Pool.java:48)
        at redis.clients.jedis.JedisPool.getResource(JedisPool.java:86)

      所有的线程都是处于WAITING状态,注意不是TIME_WAITING,也就是说如果没有别的线程去唤醒他们根本就会是一直在WAITING,关键所有的线程都在WAITING,谁去唤醒啊啊啊啊啊!!!

      看现象就是在等待获取资源,看jedis的源码也是池中没有资源了卡在那里。折腾了一上午,终于找到可能的原因,在一个方法中先去jedisPool中取了资源,在没有关闭的前提下,然后调用了另一个方法,在第二个方法中又去jedisPool中获取了资源,结合前面jedisPool中初始化只有8个资源,如果同时超过8个请求到达貌似就会造成这个问题。写代码验证,的确如此。贴下现象重现的源码:

    public class RedisTest {
        public static void main(String[] args) {
            JedisPoolConfig jpc = new JedisPoolConfig();
            jpc.setMaxIdle(20);
            jpc.setMaxTotal(20);
            //jpc.setMaxWaitMillis(10000);
            final JedisPool jedisPool = new JedisPool(jpc, "192.168.213.250", 6379);
    
            final CountDownLatch latch = new CountDownLatch(100);
            for (int i = 0; i < 100; i++) {
                final int counter = i;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        System.out.println(counter + ":ready!!!");
                        try {
                            latch.await();
                            System.out.println(counter + ":" + getInfo(jedisPool));
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
                latch.countDown();
            }
        }
    
        public static String getInfo(JedisPool jedisPool) {
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                setInfo(jedisPool);
                String key = "key123456";
                return jedis.get(key);
            } finally {
                 jedis.close();
            }
        }
        public static String setInfo(JedisPool jedisPool) {
            Jedis jedis = null;
            try {
                jedis = jedisPool.getResource();
                String key = "key123456";
                return jedis.set(key,"value123456");
            } finally {
                 jedis.close();
            }
        }
        
    }

      就是这么死锁啦,如果设置了MaxWaitMillis还好,否则只能重启JVM了。

      还有切记在用完jedis的时候一定要显式的调用下close方法,否则资源不会回到池中,很快就会用完啦,然后你就又要重启JVM了。。。

  • 相关阅读:
    Python学习(四)数据结构 —— list tuple range
    Python学习(四)数据结构 —— bool
    Python学习(四)数据结构 —— int float
    Python学习(四)数据结构(概要)
    Python学习(三)流程控制
    Python学习(二)Python 简介
    Python学习(一)安装、环境配置及IDE推荐
    iOS崩溃日志 如何看
    python 读取excel表格内不同类型的数据
    python xlrd读取excel常用方法
  • 原文地址:https://www.cnblogs.com/lcxdever/p/5334237.html
Copyright © 2011-2022 走看看