ForkJoin 源码分析之ForkJoinPool的执行

之前说到ForkJoinPool的初始化,以及Task定义的方式,现在说说这个task是怎么启动的。从我们一般写代码的话,只会这样写一句:

mainPool.invoke(task);

就是调用了mainPool的invoke()方法,但是这个方法做了些什么呢?看如下代码:

 public  T invoke(ForkJoinTask task) {
        Thread t = Thread.currentThread();
        if (task == null)
            throw new NullPointerException();
        if (shutdown)
            throw new RejectedExecutionException();
        if ((t instanceof ForkJoinWorkerThread) &&
            ((ForkJoinWorkerThread)t).pool == this)
            return task.invoke();  // bypass submit if in same pool
        else {
            addSubmission(task);
            return task.join();
        }
    }

这里首先检查队列pool是否关闭,如果关闭,则抛出异常,其次检查调用invoke方法的是否是WorkerThread,如果是,则直接执行task的invoke方法。很明显,我们这里当前线程是main线程,那么会调用addSubmission()方法,看这个方法:

private void addSubmission(ForkJoinTask t) {
        final ReentrantLock lock = this.submissionLock;
        lock.lock();
        try {
            ForkJoinTask[] q; int s, m;
            if ((q = submissionQueue) != null) {    // ignore if queue removed
                long u = (((s = queueTop) & (m = q.length-1)) << ASHIFT)+ABASE;
                UNSAFE.putOrderedObject(q, u, t);
                queueTop = s + 1;
                if (s - queueBase == m)
                    growSubmissionQueue();
            }
        } finally {
            lock.unlock();
        }
        signalWork();
    }

这个方法主要做了三件事情:

  1. 将task放入到队列中。
  2. 检查队列如果满了,则增长队列。
  3. 通知pool开始工作。

现在看pool如何开始工作。这里代码就不贴了,调用的是ForkJoinPool的signalWork方法
这个方法首先检查WorkThread中是否有工作线程,如果有,并且是挂起的状态,则将挂起的线程恢复执行,见如下代码:

if (w.eventCount == e &&
                    UNSAFE.compareAndSwapLong(this, ctlOffset, c, nc)) {
                    w.eventCount = (e + EC_UNIT) & E_MASK;
                    if (w.parked)
                        UNSAFE.unpark(w);
                    break;
                }

如果没有工作线程的话,则创建一个,这里调用了ForkJoinPool的addWorker方法。这里创建了ForkJoinWorkThread对象,并调用了start方法,执行run方法体。
这个类的run方法体的逻辑很简单:

public void run() {
        Throwable exception = null;
        try {
            onStart();
            pool.work(this);
        } catch (Throwable ex) {
            exception = ex;
        } finally {
            onTermination(exception);
        }
    }

这里主要看pool.work方法。work方法又调用了scan方法。scan方法最后又调用了ForkJoinWorkThread对象的execTask方法,这个方法最终调用了我们自己写的compute方法。

你可能感兴趣的:(Java源代码分析)