线程池系列二

善治病者,必医其受病之处;
善救弊者,必塞其弊之源

书接上文线程池的设计思路,带着如何设计拒绝策略的你,又回顾了整个流程,突然你想这事因排队而起,能不能在排队的队列上有所改进。

第一部分 排队也是值得考虑的

BlockingQueue:任务队列
我们来看一下Doug Lea事先给我们设计好的队列:

1. LinkedBlockingQueue

基于链表实现的(无界的)阻塞队列,默认情况下容量是 Integer.MAX_VALUE,可以说是无界的。
只有调用这个构造函数才可以设置容量capacity,否则都是Integer.MAX_VALUE。

 public LinkedBlockingQueue(int capacity) {
       if (capacity <= 0) throw new IllegalArgumentException();
       this.capacity = capacity;
       last = head = new Node<E>(null);
   }
2. ArrayBlockingQueue

基于数组实现的有界阻塞队列。默认情况下,不保证FIFO的顺序(By default, this ordering is not guaranteed).。因为公平策略将会降低吞吐率,但是也降低了可变性以及避免了饥饿现象.(Fairness generally decreases throughput but reduces variability and avoids starvation.)

// 注意: 参数fair默认为false,  true -保证FIFO 
 public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
3. SynchronousQueue

A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa(反之亦然).
同步队列-不存储任务的阻塞队列。插入操作 和 删除操作是一一对应的。就像一个空集合(acts as an empty collection)

三者之间的联系

  1. 吞吐率角度:

SynchronousQueue > LinkedBlockingQueue > ArrayBlockingQueue

  1. FIFO的角度:

LinkedBlockingQueue 直接按照队列的FIFO设计;
SynchronousQueue, ArrayBlockingQueue 默认都是不保证FIFO顺序的,可以在构造函数中打开fairness。

  1. 容量角度:

LinkedBlockingQueue默认容量是无限制的,直接打翻了“临时工”的饭碗。即:maxiumPoolSize失去了意义。PS:2333, "正式工"已经哭晕倒厕所里啦,往死里干。

世界本来就是不公平的,面对现实吧!!!

4. PriorityBlockingQueue

具有优先级的阻塞队列,初始容量是11。Obviously, 它不保证FIFO,如果需要可以自定义类去打破其优先级(有病啊?OR闲得啦?).

还有几种阻塞队列,但是我认为记住这四种差不多就够用啦,后面的遇到再介绍。怕:消化不良 2333

BlockingQueue归纳一下:

尽情地发挥想象:

  1. LinkedBlockingQueue:为了防止插队,用绳索把每个人都串联起来(PS:这绳索默认还是无限长地(Integer.MAX_VALUE)),MMP,还得请城管大队长喝酒啊;
  2. ArrayBlockingQueue:绑起来貌似有点不厚道,还是把绳索解开,但是都别乱动啊。为了不惊动城管,不准站太多人。
  3. PriorityBlockingQueue:城管大人站在队列地尾部,对你投来迷之微笑,吓得你毛骨悚然,怕遇到“同志”。正在发愣地时候,城管大人一只手搭在你的肩膀上,老弟不请我吃一顿。此时你那还管什么FIFO啊,直接拉着城管大人地手往店里走。
  4. SynchronousQueue:城管大人说饱喝足,走出门口说:上面检查,排队影响市容市貌,不准排队。你看着办吧。只能(来一个走一个,走一个来一个)。PS:一首凉凉送给你

第二部分:学会拒绝

RejectedExecutionHandler 拒绝策略

1. AbortPolicy

简单粗暴,你值得选择。

默认策略:直接拒绝并抛出运行时异常:RejectedExecutionException

2. DiscardPolicy

冲动是魔鬼,默默地拒绝。

直接拒绝但不抛异常。

3. DiscardOldestPolicy

为了大局而牺牲局部利益

直接拒绝队列的头部,为了不犯众怒,你只好对队列的第一个人说不。毕竟:得罪一个,取悦一群啊。

4. CallerRunsPolicy

从哪来回哪去

交给调用者所在的线程来处理任务。

5. 自定义策略

随心所欲

实现RejectedExecutionHandler接口。比如送个优惠券啥的…

RejectedExecutionExecutor总结

这里假设:正是饥饿的时候,不让吃饭谁能心里舒服,谁也不愿意啊,

  1. AboryPolicy :直接拒绝结果把人给打了一顿,这样饭店也干不下去啦…
  2. DiscardPolicy:陪着笑脸,打不还手骂不还口直的拒绝
  3. DiscardOldestPolicy: 为了大部分人的利益而牺牲少数人。排队的人在后面起哄,质问前面的人怎么还没走啊。为了平复后面的人,只能牺牲一下队列首位啦。PS:电车悖论
  4. CallerRunsPolicy : 冷处理
  5. 自定义策略:为了不得罪顾客,可能你要发个优惠券啥的。

通过这两篇文章,我认为大家对ThreadPoolExecutor应该有了一个清晰的认识。更为详细的内容,后续慢慢补充。接下来要实现你做大老板的梦想——开连锁店。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章