一个由CountDownLatch引发的Bug


最近恢复Venus的工作,恰逢十一假期尾声,突发一个Bug,让人匪夷所依。我们今天快速倒序追踪,层层回顾。


1. 背景

Venus交易中需要并行开数十至百个线程分别快速计算,程序中使用CountDownLatch用于计数,因为之后后做其他处理分析,需要等待所有交易结束。

程序运行稳定正常,线上也已经0.16版本(个人线上),恰逢十一假期突然出问题,CountDownLatch无法归零,导致整个主线程Hang在那里。如何破?


2. 场景分析

我们直接看一下源代码如何:


平铺直叙,代码中定义了CountDownLatch, 设定其数量为股票个数,然后线程中进行countDown.


平时运行正常不过,十一为何出问题?难道Venus想让笔者家里加班?


3. CountDownLanch

查看log问题主要出现在最终CountDownLatch无法归零,按说我们都把countDown放到finally里面了,应该不会出什么问题了。

Anyway,我们先看一下CountDownLatch吧。



API中当调用await时候,调用线程处于等待挂起状态,直至count变成0再继续。

其大体原理如下:



Java官网中给出的事例代码如下:


与我们的类似,除了多了个开始计时器,这个应该不是问题吧?官网如下的例子也说明了我们的猜测。


4. 深入研究

我们的焦点目光转移至await。

await

public boolean await(long timeout, TimeUnit unit)
throws InterruptedException
  • 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。如果当前计数为零,则此方法立刻返回true 值。

  • 如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直处于休眠状态:

    1. 由于调用 countDown() 方法,计数到达零;或者

    2. 其他某个线程中断当前线程;或者

    3. 已超出指定的等待时间。

上述API详细描述,有几个疑点值得进一步推敲,首先我们的count并未到达0,所以应该是线程调用中出现了问题,难道是有一些没有捕获的异常?可是我们是在finally做的countdown啊?

把所有捕获异常都换成Thowable, 无用!


网上有人云:

Executors.newFixedThreadPool这是个有固定活动线程数。当提交到池中的任务数大于固定活动线程数时,任务就会放到阻塞队列中等待。
主任务和子任务都放到了线程池中,就有下面的情况发生,
主任务调用一次CountDownLatch实例的await()方法时,当前线程就会一直占用一个活动线程,如果多次调用,那么就会一直占用多个活动线程,如果调用次数大于固定活动线程数,那么就可能造成阻塞队列中某些子任务一直不被执行,CountDownLatch实例的countDown()的方法一直不被调用,那么对应的主任务所在线程就会无限等待,与死锁现像一样


我们的newFixedThreadPool是大了点,直接50-100多个,而我的mac只有2核(可怜啊),跟这个有关系么?

我们把FixedThreadPool改成了默认cpu的核数,或者hard code成2,运行,无效,hang,再说以前也是50-100个,运行没有问题啊。


解决办法是最好不要用CountDownLatch实例的await(),归避长时间阻塞线程的风险,任何多线程应用程序都有死锁风险,改用CountDownLatch实例的await(long timeout, TimeUnit unit),设定超时时间,如果超时,


多线程程序确实有死锁风险, 当然安全起见可以给定超时时间。回到我们这里不解决问题啊,到底问题出在哪里?


5. 真相大白

问题到这里,我们把该怀疑的地方都怀疑了一遍,还是不得要领。难道问题出在某一股票交易中?恰逢十一假期,有关连?


好吧,只好使出大招,就是二分排查法,哈哈。说白了就是笨办法,逐一排查,股票由100个到50十个,到40,到20,正常。难道真是跟线程数量有关系?

不科学啊。

反过来,把剩下的80个来运行一下,居然正常通过。


嗯,到此,感觉就快找到问题了。问题就出现在那20个股票当中的某些有问题。继续排查,终于定位到600188,这么好的代码,有问题?


好吧,至此可以进入debug了。

终于的终于,问题定位到该股票在十一前恰好处罚交易策略,而逢十一假期,代码中一段计算nextTradingDate的算法有点问题(其实是粘贴错了变量),直接导致死循环!!!


好吧,那个高手没有写过死循环啊?


一秒钟改掉后,Venus瞬间触发100个线程,愉悦的开始交易!


总结

此问题虽然最终并非有并发导致的问题,而然其隐藏之深也与并发分不开;并发多线程是好东西,当然也要慎用,做到知其然知其所以然。

转自:http://blog.csdn.net/erixhao/article/details/52747955

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值