java fork-join框架

yang9527
  • 139

背景:《java核心技术》书籍中提到

有些应用使用了大量线程,大其中大多数是空闲的。举例来说,一个Web服务器可能会为每个连接分别使用一个线程。另外一些应用可能对每个处理器内核分别使用一个线程,来完成计算密集型任务,如图像或者视频处理。Java SE7中新引入了fork-join框架,专门用来支持后一类应用。

在后台,fork-join框架使用一种有效的智能方法来平衡可用线程的工作负载,这种方法称为工作密取(work stealing)。每个工作线程都有一个双端队列(deque)来完成任务。一个工作线程将子任务压入其双端队列的队头。(只有一个线程可用访问队头,所以不需要加锁。)一个工作线程空闲时,它会从另一个双端队列的队尾“密取”一个任务。由于大的子任务都在队尾,这种密取很少出现。

对于这句话:
由于大的子任务都在队尾,这种密取很少出现。

没有搞懂啥意思,求帮忙解释。

回复
阅读 539
1 个回答

举个例子,计算从1+2+3+4+5+...+99,一种行至有效的方式是按照二分法拆成一个一个的子任务,假设每个子任务负责2个数(threshold)的加法,那么这个时候总共拆分为50+25+13+...+2个子任务,类似于层层归并,我们知道拆成2个子任务的情况是两边各50个数,最先入队列,亦即2个最大的子任务,依次类推,知道拆分到每个子任务足够小(小于threshold)的情形下才开始处理,按照双端队列的原则,最小的子任务总是位于表头优先被处理,当所有的cpu理想情况下处理速度完全一致的情形下,每个工作线程只需要处理自己的工作队列的任务即可,但通常情况下现代操作系统都是多任务,不可能只运行一个任务,这样就会导致每个工作线程处理工作队列的任务有快有慢,为了避免多个工作线程争抢表头同一个子任务,一种巧妙的设计就是处理速度快的工作线程,当它处理完自己工作队列里面的任务后,如果此时其他的工作线程队列还有任务存在,便会尝试从其他工作线程队列尾部"窃取"任务,这种设计是为了最大限度的利用cpu资源,有一点需要注意的是即便从其他队列尾部拿到了任务,由于这个任务是一个"大任务",需要依赖队列比他靠前的两个子任务的产生的结果,所以这个时候如果当前线程想要处理这个"大任务",两种情况可能会发生,一种是其他线程刚好处理完了前置的子任务,结果集有了,一种是当前线程继续"窃取"其他线程的任务,直到拿到合适的数据结果集能执行后续的子任务处理,在子任务拆分细化的前提下以及操作系统调度均衡的情况下,各个工作线程执行的任务数大致是平衡的,因此这种任务窃取其实发生的场景比较少

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
宣传栏