ForkJoinPool 源码分析

一个ForkJoinPool 对应多个ForkJoinWorkerThread

一个ForkJoinWorkerThread 对应多个ForkJoinTask


以一个简单的求和Task为例:

public class ForkJoinTest {
	public static void main(String[] args) {
		ForkJoinPool fjp = new ForkJoinPool(2);
		Task task = new Task(0, 8);
		Future result = fjp.submit(task);
		try {
			int a = result.get();
			System.out.println(a);
		} catch (InterruptedException | ExecutionException e) {
			e.printStackTrace();
		}
	}
}

class Task extends RecursiveTask{
	
	public static final int THRESHOLD = 2;

	private int start;
	private int end;
	
	public Task(int start, int end){
		this.start = start;
		this.end = end;
	}
	
	@Override
	protected Integer compute() {
		int sum = 0;
		boolean canCompute = (end - start) <= THRESHOLD;
		if(canCompute){
			for(int i=start; i <= end; i++){
				sum += i;
			}
		} else{
			int middle = (start + end)/2;
			Task left = new Task(start, middle);
			Task right = new Task(middle, end);
			invokeAll(left, right);
			int leftResult = left.join();
			int rightResult = right.join();
			sum = leftResult + rightResult;
		}
		return sum;
	}
	
}

1. ForkJoinWorkerThread 的execTask方法(解决自己ForkJoinWorkerThread 的task调用)

    final void execTask(ForkJoinTask t) {
        currentSteal = t;
        for (;;) {
            if (t != null)
                t.doExec();
            if (queueTop == queueBase)
                break;
            t = locallyFifo ? locallyDeqTask() : popTask();
        }
        ++stealCount;
        currentSteal = null;
    }
这里就是执行task,当执行完成会取出当前ForkJoinWorkerThread的下一个ForkJoinTask,如果已经区空了就会跳出循环


2. ForkJoinWorkerThread 的scan方法(解决别人以及自己ForkJoinWorkerThread的task调用)

   private boolean scan(ForkJoinWorkerThread w, int a) {
        int g = scanGuard; // mask 0 avoids useless scans if only one active
        int m = (parallelism == 1 - a && blockedCount == 0) ? 0 : g & SMASK;
        ForkJoinWorkerThread[] ws = workers;
        if (ws == null || ws.length <= m)         // staleness check
            return false;
        for (int r = w.seed, k = r, j = -(m + m); j <= m + m; ++j) {
            ForkJoinTask t; ForkJoinTask[] q; int b, i;
            ForkJoinWorkerThread v = ws[k & m];
            if (v != null && (b = v.queueBase) != v.queueTop &&
                (q = v.queue) != null && (i = (q.length - 1) & b) >= 0) {
                long u = (i << ASHIFT) + ABASE;
                if ((t = q[i]) != null && v.queueBase == b &&
                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
                    int d = (v.queueBase = b + 1) - v.queueTop;
                    v.stealHint = w.poolIndex;
                    if (d != 0)
                        signalWork();             // propagate if nonempty
                    w.execTask(t);
                }
                r ^= r << 13; r ^= r >>> 17; w.seed = r ^ (r << 5);
                return false;                     // store next seed
            }
            else if (j < 0) {                     // xorshift
                r ^= r << 13; r ^= r >>> 17; k = r ^= r << 5;
            }
            else
                ++k;
        }
        if (scanGuard != g)                       // staleness check
            return false;
        else {                                    // try to take submission
            ForkJoinTask t; ForkJoinTask[] q; int b, i;
            if ((b = queueBase) != queueTop &&
                (q = submissionQueue) != null &&
                (i = (q.length - 1) & b) >= 0) {
                long u = (i << ASHIFT) + ABASE;
                if ((t = q[i]) != null && queueBase == b &&
                    UNSAFE.compareAndSwapObject(q, u, t, null)) {
                    queueBase = b + 1;
                    w.execTask(t);
                }
                return false;
            }
            return true;                         // all queues empty
        }
    }

当execTask循环跳出,会执行scan方法,尝试从其他的ForkJoinWorkerThread中取出ForkJoinTask 然后调用execTask方法


3. ForkJoinTask的invokeAll方法(解决如何分配task的问题)

    public static void invokeAll(ForkJoinTask t1, ForkJoinTask t2) {
        t2.fork();
        t1.invoke();
        t2.join();
    }

step 1:把t2压入当前ForkJoinWorkerThread的queue中,要么当前ForkJoinWorkerThread会去消费,要么会有空闲的ForkJoinWorkerThread去消费

step 2:当前ForkJoinWorkerThread继续执行t1

step3: 当前ForkJoinWorkerThread等待t2的完成

invokeAll方法往往是在compute()方法中调用,整体处理过程还是很符合逻辑的。




你可能感兴趣的:(Java基础)