记一个腾讯信鸽引发的线程卡死问题

一天公司的游戏有大量玩家报自动战斗、种植等操作无法进行,第一时间想到可能是因为玩家的定时任务线程卡死了。用jstack查看线程堆栈日志,发现都卡在了一个http read的地方。

公司使用腾讯信鸽做手游的系统推送,卡住的地方就是调用信鸽的服务端sdk向信鸽服务器发送http请求,并等待回应的时候。

因为是调用第三方jar包,所以无法直接设置读超时。在网上搜索到一种方法是通过系统变量设置超时时间:

 System.setProperty("sun.net.client.defaultReadTimeout", 3000);

测试过有效之后上线。

本以为万事大吉了。结果过了一段时间又报出大量玩家无法自动战斗,后面一看还是这个问题。

说明设置的系统变量并未生效。

于是在线下详细测试,发现一个奇怪的问题:在两个不同的工程中设置这个系统变量,一个是有效的,一个是无效的。

不过能够复现问题就是件好事。查看堆栈对应的jdk源码,发现是sun包下的,不开源。再找到openjdk源码,研究后发现是NetworkClient的static代码块的执行时机的问题。

原来java在第一次生成http请求时,会从系统变量sun.net.client.defaultReadTimeout读取默认读超时时间并放在缓存里,以后即使修改了这个系统变量,也不会影响默认读超时时间了。

知道了问题的原因,那就知道解决办法了:将默认读超时设在程序的起始位置,或者启动脚本中

后面向腾讯信鸽写邮件反映这个问题。在最新版的SDK中看到已经得以修正。

总结:

  1. 使用http请求一定要设置连接超时和读超时,否则网络一出问题就会卡死。
  2. 在涉及第三方类库时使用单独的线程池,与业务线程池分离。因为你永远不知道里面会有什么未知的问题。

猜你喜欢

转载自blog.csdn.net/needmorecode/article/details/75801670