Java多线程高并发高级篇ForkJoin框架篇(三)---ForkJoinPool中结果归并Join解密

阅读更多

我们接上篇,继续解密ForkJoinPool中的结果归并,其实很简单。

结果归并是是在计算任务完成后。我们还以上一篇帖子中的计算为例。

二、join()方法解密

上一篇最后,这时线程Thread[ForkJoinPool-1-worker-3,5,main]处理的任务【1,125】经过execTask等一系列方法后,调用computer方法,此时达到阈值,调用for循环开始计算结果,最终得到结果7875,并且设置。同理Thread[ForkJoinPool-1-worker-4,5,main]线程处理的任务【126,250】经过计算得到最后的结果23500。

这里要注意下,执行完各自计算任务的时候,在doExec()方法执行完成时,使用setCompletion(NORMAL);方法设置了完成状态(正常完成),表明该任务正常执行完成。

final void doExec() {
        if (status >= 0) {
            boolean completed;
            try {
                completed = exec();
            } catch (Throwable rex) {
                setExceptionalCompletion(rex);
                return;
            }
            if (completed)
                setCompletion(NORMAL); // must be outside try block
        }
    }

private int setCompletion(int completion) {
        for (int s;;) {
            if ((s = status) < 0)
                return s;
            if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
                if (s != 0)
                    synchronized (this) { notifyAll(); }
                return completion;
            }
        }
    }

 当工作线程Thread[ForkJoinPool-1-worker-3,5,main]和Thread[ForkJoinPool-1-worker-4,5,main]将各自的计算任务完成后,等待在计算任务【1,125】和【126,250】进行join完成的工作线程Thread[ForkJoinPool-1-worker-2,5,main]可以开始进行join操作了。

Java多线程高并发高级篇ForkJoin框架篇(三)---ForkJoinPool中结果归并Join解密_第1张图片
 

执行左任务的join方法,我们需要看下join方法的源码。

public final V join() {
        if (doJoin() != NORMAL)
            return reportResult();
        else
            return getRawResult();
    }

 在join方法的源码中,判断条件处使用了doJoin()方法,我们需要先看下它:

private int doJoin() {
        Thread t; ForkJoinWorkerThread w; int s; boolean completed;
        if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) {
            if ((s = status) < 0)
                return s;
            if ((w = (ForkJoinWorkerThread)t).unpushTask(this)) {
                try {
                    completed = exec();
                } catch (Throwable rex) {
                    return setExceptionalCompletion(rex);
                }
                if (completed)
                    return setCompletion(NORMAL);
            }
            return w.joinTask(this);
        }
        else
            return externalAwaitDone();
    }

 在doJoin()方法中,判断比较多。第一个判断if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread),因为当前线程肯定是工作线程Thread[ForkJoinPool-1-worker-2,5,main],所以这个条件成立。内层判断,if ((s = status) < 0),当前status是任务的当前状态,在开篇我们就说了,任务执行完成时使用CAS原子方法,设置了status为NORMAL(-1),所以,这里也是成立的,因此直接返回s=-1,也就是doJoin()方法返回了-1。

 

回到Join方法中,if (doJoin() != NORMAL)这个条件就不成立了。因此return getRawResult();

我们看下getRawResult()方法,它就一行代码,返回计算结果result。

public final V getRawResult() {
        return result;
    }

 因此工作线程left.join返回了7875,right.join返回了23500。因此工作线程Thread[ForkJoinPool-1-worker-2,5,main]返回的computer结果就是7875+23500=31375。

 

其他分支的流程处理方式一样,我们不再赘述。

 

最后说一句,其实写博客是件很费事的事情,读源码更是件费力的事情。

学习源码,是为了让自己理解的更透彻,而不是听别人去说,这个东西怎样怎样。

从一开始的排斥源码,慢慢的去学习设计者的想法,对自己的能力也是一种极大的提升。

 

 

 

 

 

 

  • Java多线程高并发高级篇ForkJoin框架篇(三)---ForkJoinPool中结果归并Join解密_第2张图片
  • 大小: 78.3 KB
  • 查看图片附件

你可能感兴趣的:(Java多线程高并发高级篇ForkJoin框架篇(三)---ForkJoinPool中结果归并Join解密)