读书人

Fork/Join框架之双端行列

发布时间: 2013-09-05 16:02:06 作者: rapoo

Fork/Join框架之双端队列
简介

ForkJoinPool管理着ForkJoinWorkerThread线程,ForkJoinWorkerThread线程内部有一个双端队列,这个双端队列主要由一个数组queue、数组下标queueBase、数组上标queueTop三个值保证。

ForkJoinTask<?>[] queue:数组的大小必须是2的n次方,方便将取模转换为移位运算;

int queueTop:标识下一个被push或者pop的位置,这个值只会被当前线程修改,因些没有加volatile修饰;

volatile int queueBase:下一个可以被其他线程steal的位置,由于其他线程会修改这个值,所以用volatile修饰保证可见性。


初始化

在线程的run方法启动时,会调用线程的onStart()方法,在这个方法中对queue进行了初始化,长度为1 << 13,这个方法并没有对queueTop,queueBase进行赋值,采用默认值0。


扩容

当向线程中添加任务时,有可能会导致数组满的情况,如下代码所示:

for (;;) {    ForkJoinTask<?>[] q; int b, i;    if (joinMe.status < 0)        break outer;    if ((b = v.queueBase) == v.queueTop ||        (q = v.queue) == null ||        (i = (q.length-1) & b) < 0)        break;                  // empty    long u = (i << ASHIFT) + ABASE;    ForkJoinTask<?> t = q[i];    if (task.status < 0)        break outer;            // stale    if (t != null && v.queueBase == b &&        UNSAFE.compareAndSwapObject(q, u, t, null)) {        v.queueBase = b + 1;        v.stealHint = poolIndex;        ForkJoinTask<?> ps = currentSteal;        currentSteal = t;        t.doExec();        currentSteal = ps;        helped = true;    }}
1、瞄到第i个位置这个任务,i = (q.length-1) & b,i其实就是queueBase在数组中所在的位置;
2、将这个位置上的任务设置为null,并增加queueBase的值,设置stealHint表示你的东西被我偷了;

3、保存先前的currentSteal值,设置currentSteal为这个偷来的task,然后执行这个task,执行完后,恢复currentSteal的值。

读书人网 >互联网

热点推荐