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了。。。

  • 相关阅读:
    luogu P1833 樱花 看成混合背包
    luogu P1077 摆花 基础记数dp
    luogu P1095 守望者的逃离 经典dp
    Even Subset Sum Problem CodeForces
    Maximum White Subtree CodeForces
    Sleeping Schedule CodeForces
    Bombs CodeForces
    病毒侵袭持续中 HDU
    病毒侵袭 HDU
    Educational Codeforces Round 35 (Rated for Div. 2)
  • 原文地址:https://www.cnblogs.com/lcxdever/p/5334237.html
Copyright © 2011-2022 走看看