原文地址:http://hellojava.info/?p=464

最近出了个故障,排查的时候耗费了很长的时间,回顾整个排查过程,经验主义在这里起了不好的作用,直接导致了整个故障排查的时间非常长,这个故障的根本原因在于BlockingQueue用的有问题,顺带展开说说Java中常用的几个BlockingQueue:ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue。

当时故障的现象是应用处理请求的线程池满了,导致请求处理不了,于是dump线程,看线程都在做什么,结果发现线程都Block在写日志的地方,以前出现过很多次问题,去线程dump的时候看到也是一堆的block在写日志,但通常是别的原因引发的,所以这次也是按照这样的经验,认为肯定不会是写日志这个地方的问题,于是各种排查…折腾了N久后,回过头看发现持有那把日志锁的地方是自己人写的代码,那段代码在拿到了这个日志锁后,从线程堆栈上看,block在了ArrayBlockingQueue.put这个地方,于是翻看这段代码,结果发现这是个1024长度的BlockingQueue,那就意味着如果这个Queue被放了1024个对象的话,put就一定会被block住,而且其实翻代码的时候能看出写代码的同学是考虑到了BlockingQueue如果满了应该要处理的,代码里写着:

if (blockingQueue.remainingCapacity() < 1) { //todo } blockingQueue.put 

这里两个悲催的问题,一是这个if判断完还是直接会走到put,而不是else,二是竟然关键的满了后的处理逻辑还在//todo...
另外我觉得这段代码还反应了同学对BlockingQueue的接口不太熟,要达到这个效果,不需要这样先去判断,更合适的做法是用blockingQueue.offer,返回false再做相应的异常处理。

BlockingQueue是在生产/消费者模式下经常会用到的数据结构,通常常用的主要会是ArrayBlockingQueue、LinkedBlockingQueue和SynchronousQueue。

ArrayBlockingQeue/LinkedBlockingQueue两者的最大不同主要在于存放Queue中对象方式,一个是数组,一个是链表,代码注释里也写到了两者的不同:
Linked queues typically have higher throughput than array-based queues but less predictable performance in most concurrent applications.

SynchronousQueue是一个非常特殊的BlockingQueue,它的模式是在offer的时候,如果没有另外一个线程正在take或poll的话,那么offer就会失败;在take的时候,如果没有另外的线程正好并发在offer,也会失败,这种特殊的模式非常适合用来做要求高响应并且线程出不固定的线程池的Queue。

对于在线业务场景而言,所有的并发,外部访问阻塞的地方的一个真理就是一定要有超时机制,我不知道见过多少次由于没有超时造成的在线业务的严重故障,在线业务最强调的是快速处理掉一次请求,所以fail fast是在线业务系统设计,代码编写中的最重要原则,按照这个原则上面的代码最起码明显犯的错误就是用put而不是带超时机制的offer,或者说如果是不重要的场景,完全就应该直接用offer,false了直接抛异常或记录下异常即可。

对于BlockingQueue这种场景呢,除了超时机制外,还有一个是队列长度一定要做限制,否则默认的是Integer.MAX_VALUE,万一代码出点bug的话,内存就被玩挂了。

说到BlockingQueue,就还是要提下BlockingQueue被用的最多的地方:线程池,Java的ThreadPoolExecutor中有个参数是BlockingQueue,如果这个地方用的是ArrayBlockingQueue或LinkedBlockingQueue,而线程池的coreSize和poolSize不一样的话,在coreSize线程满了后,这个时候线程池首先会做的是offer到BlockingQueue,成功的话就结束,这种场景同样不符合在线业务的需求,在线业务更希望的是快速处理,而不是先排队,而且其实在线业务最好是不要让请求堆在排队队列里,在线业务这样做很容易引发雪崩,超出处理能力范围直接拒绝抛错是相对比较好的做法,至于在前面页面上排队什么这个是可以的,那是另外一种限流机制。

所以说在写高并发、分布式的代码时,除了系统设计外,代码细节的功力是非常非常重要的。

从一个故障说说Java的三个BlockingQueue的更多相关文章

  1. 从零开始实现一个简易的Java MVC框架(三)--实现IOC

    Spring中的IOC IoC全称是Inversion of Control,就是控制反转,他其实不是spring独有的特性或者说也不是java的特性,他是一种设计思想.而DI(Dependency ...

  2. Java EE : 三、图解Session(会话)

    目录 Java EE : 一.图解Http协议 Java EE : 二.图解 Cookie(小甜饼) Java EE : 三.图解Session(会话) 概述 一.Session由来 二.Sessio ...

  3. JAVA第三周作业(从键盘输入若干数求和)

    JAVA第三周作业(从键盘输入若干数求和) 在新的一周,我学习了JAVA的IO编程.下面的代码实现了从键盘输入若干数求和的目标.import java.util.Scanner; public cla ...

  4. [Java面试三]JavaWeb基础知识总结.

    1.web服务器与HTTP协议 Web服务器 l WEB,在英语中web即表示网页的意思,它用于表示Internet主机上供外界访问的资源. l Internet上供外界访问的Web资源分为: • 静 ...

  5. 搭建一个完整的Java开发环境

    搭建一个完整的Java开发环境 作为一个Java程序员,配置一个java开发环境是必备的技能,今天给广大菜鸟初学者补上一课.环境的配置,大概就分三个1,JDK 2,Tomcat(或者其他的)3,ecl ...

  6. Java的三种代理模式

    Java的三种代理模式 1.代理模式 代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩 ...

  7. Java的三种代理模式简述

    本文着重讲述三种代理模式在java代码中如何写出,为保证文章的针对性,暂且不讨论底层实现原理,具体的原理将在下一篇博文中讲述. 代理模式是什么 代理模式是一种设计模式,简单说即是在不改变源码的情况下, ...

  8. Effective Java 第三版——2. 当构造方法参数过多时使用builder模式

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  9. Effective Java 第三版——3. 使用私有构造方法或枚类实现Singleton属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

随机推荐

  1. Dnsmasq安装与配置-搭建本地DNS服务器 更干净更快无广告DNS解析

    默认的情况下,我们平时上网用的本地DNS服务器都是使用电信或者联通的,但是这样也导致了不少的问题,首当其冲的就是上网时经常莫名地弹出广告,或者莫名的流量被消耗掉导致网速变慢.其次是部分网站域名不能正常 ...

  2. 最简单粗暴的http文件列表

    :]: port = ])else: port = 8000server_address = ('127.0.0.1', port)Handler.protocol_version = Protoco ...

  3. Linux下WebSphereV8.5.5.0 安装详细过程

    自WAS8以后安装包不再区别OS,一份介质可以安装到多个平台.只针对Installation Manager 进行了操作系统的区分 ,Websphere产品介质必须通过专门的工具Install Man ...

  4. telnet测试制定地址端口号

    cmd下,命令 telnel+空格+ip或者网站+空格+端口号 端口可以用: 需要开通windows服务:

  5. 【leetcode】Balanced Binary Tree(middle)

    Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary ...

  6. iOS block 的底层实现

    其实swift 的闭包跟 OC的block 是一样一样的,学会了block,你swift里边的闭包就会无师自通. 参考:http://www.jianshu.com/p/e23078c11518 ht ...

  7. yii和php的一些细节

    yii   index.php ini_set("display_errors", 1); iconv这个函数不能直接用 需要检测!!! function gb2312_utf8( ...

  8. 51nod1057(python2计算n!)

    题目链接:www.51nod.com/onlineJudge/questionCode.html#!problemId=1057 思路:直接for循环呗- 代码: n = int( raw_input ...

  9. linux eclipse3.6.1 maven安装

    linux maven安装及 eclipse maven插件安装,有需要的朋友可以参考下. 1. maven的安装(apache-maven-3.0.5为例):  a.官网地址:http://mave ...

  10. python中获取当前日期在当月是第几天