日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
fork/join全面剖析,你可以不用,但是不能不懂!

fork/join作為一個并發(fā)框架在jdk7的時候就加入到了我們的java并發(fā)包java.util.concurrent中,并且在java 8 的lambda并行流中充當(dāng)著底層框架的角色。

在鄢陵等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計制作、成都網(wǎng)站設(shè)計 網(wǎng)站設(shè)計制作按需求定制網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),營銷型網(wǎng)站,成都外貿(mào)網(wǎng)站制作,鄢陵網(wǎng)站建設(shè)費用合理。

這樣一個優(yōu)秀的框架設(shè)計,我自己想了解一下它的底層代碼是如何實現(xiàn)的,所以我嘗試的去閱讀了JDK相關(guān)的源碼。下面我打算分享一下閱讀完之后的心得~。

1、fork/join的設(shè)計思路

了解一個框架的第一件事,就是先了解別人的設(shè)計思路!

fork/join大體的執(zhí)行過程就如上圖所示,先把一個大任務(wù)分解(fork)成許多個獨立的小任務(wù),然后起多線程并行去處理這些小任務(wù)。處理完得到結(jié)果后再進(jìn)行合并(join)就得到我們的最終結(jié)果。

顯而易見的這個框架是借助了現(xiàn)代計算機(jī)多核的優(yōu)勢并行去處理數(shù)據(jù)。這看起來好像沒有什么特別之處,這個套路很多人都會,并且工作中也會經(jīng)常運用~。其實fork/join的最特別之處在于它還運用了一種叫work-stealing(工作竊取)的算法,這種算法的設(shè)計思路在于把分解出來的小任務(wù)放在多個雙端隊列中,而線程在隊列的頭和尾部都可獲取任務(wù)。

當(dāng)有線程把當(dāng)前負(fù)責(zé)隊列的任務(wù)處理完之后,它還可以從那些還沒有處理完的隊列的尾部竊取任務(wù)來處理,這連線程的空余時間也充分利用了!。

work-stealing原理圖如下:

2、實現(xiàn)fork/join 定義了哪些角色?

了解設(shè)計原理,這僅僅是第一步!要了解別人整個的實現(xiàn)思路, 還需要了解別人為了實現(xiàn)這個框架定義了哪些角色,并了解這些角色的職責(zé)范圍是什么的。因為知道誰負(fù)責(zé)了什么,誰做什么,這樣整個邏輯才能串起來!在JAVA里面角色是以類的形式定義的,而了解類的行為最直接的方式就是看定義的公共方法~。

這里介紹JDK里面與fork/join相關(guān)的主要幾個類:

  •  ForkJoinPool:充當(dāng)fork/join框架里面的管理者,最原始的任務(wù)都要交給它才能處理。它負(fù)責(zé)控制整個fork/join有多少個workerThread,workerThread的創(chuàng)建,激活都是由它來掌控。它還負(fù)責(zé)workQueue隊列的創(chuàng)建和分配,每當(dāng)創(chuàng)建一個workerThread,它負(fù)責(zé)分配相應(yīng)的workQueue。然后它把接到的活都交給workerThread去處理,它可以說是整個frok/join的容器。
  •  ForkJoinWorkerThread:fork/join里面真正干活的"工人",本質(zhì)是一個線程。里面有一個ForkJoinPool.WorkQueue的隊列存放著它要干的活,接活之前它要向ForkJoinPool注冊(registerWorker),拿到相應(yīng)的workQueue。然后就從workQueue里面拿任務(wù)出來處理。它是依附于ForkJoinPool而存活,如果ForkJoinPool的銷毀了,它也會跟著結(jié)束。
  •  ForkJoinPool.WorkQueue: 雙端隊列就是它,它負(fù)責(zé)存儲接收的任務(wù)。
  •  ForkJoinTask:代表fork/join里面任務(wù)類型,我們一般用它的兩個子類RecursiveTask、RecursiveAction。這兩個區(qū)別在于RecursiveTask任務(wù)是有返回值,RecursiveAction沒有返回值。任務(wù)的處理邏輯包括任務(wù)的切分都集中在compute()方法里面。

3、fork/join初始化時做了什么

大到一個系統(tǒng),小到一個框架,初始化工作往往是體現(xiàn)邏輯的一個重要地方!因為這是開始的地方,后面的邏輯會有依賴!所以把初始化看明白了,后面很多邏輯就容易理解多了。

下面上一段代碼,(ps:這段代碼是在網(wǎng)上找到的,并做了一小部分的修改) 

 
 
 
 
  1. public class CountTask extends RecursiveTask {  
  2.     private static final int THRESHOLD = 2; //閥值  
  3.     private int start;  
  4.     private int end;  
  5.     public CountTask(int start,int end){  
  6.         this.start = start;  
  7.         this.end = end;  
  8.     }  
  9.     @Override  
  10.     protected Integer compute() {  
  11.          int sum = 0;  
  12.          boolean canCompute = (end - start) <= THRESHOLD;  
  13.          if(canCompute){  
  14.              for(int i = start; i <= end; i++){  
  15.                  sum += i;  
  16.              }  
  17.          }else{  
  18.              int middle = (start + end) / 2;  
  19.              CountTask leftTask = new CountTask(start,middle);  
  20.              CountTask rightTask = new CountTask(middle + 1,end);  
  21.              //執(zhí)行子任務(wù)  
  22.              leftTask.fork();  
  23.              rightTask.fork();  
  24.              //等待子任務(wù)執(zhí)行完,并得到其結(jié)果  
  25.              Integer rightResult = rightTask.join();  
  26.              Integer leftResult = leftTask.join();  
  27.              //合并子任務(wù)  
  28.              sum = leftResult + rightResult;  
  29.          }  
  30.          return sum;  
  31.     }  
  32.     public static void main(String[] args) throws ExecutionException, InterruptedException {  
  33.         ForkJoinPool forkJoinPool = new ForkJoinPool();  
  34.         CountTask countTask = new CountTask(1,200);  
  35.         ForkJoinTask forkJoinTask = forkJoinPool.submit(countTask);  
  36.         System.out.println(forkJoinTask.get());  
  37.     }  

代碼的執(zhí)行過程解釋起來也是很簡單就是把[1,200],分成[1,100],[101,200],然后再對每個部分進(jìn)行一個遞歸分解最終分解成[1,2],[3,4],[5,6]…..[199,200]獨立的小任務(wù),然后兩兩求和合并。

其實顯然易見負(fù)責(zé)整個fork/join初始化工作的就是ForkJoinPool!初始化代碼就是那一行 ForkJoinPool forkJoinPool = new ForkJoinPool(),點進(jìn)去查看源碼。 

 
 
 
 
  1. ForkJoinPool forkJoinPool = new ForkJoinPool();  
  2. //最終調(diào)用到這段代碼  
  3. public ForkJoinPool(int parallelism,  
  4.                     ForkJoinWorkerThreadFactory factory,  
  5.                     UncaughtExceptionHandler handler,  
  6.                     boolean asyncMode) {  
  7.     this(checkParallelism(parallelism), //并行度,當(dāng)前機(jī)器的cpu核數(shù)  
  8.             checkFactory(factory), //工作線程創(chuàng)建工廠  
  9.             handler, //異常處理handler  
  10.             asyncMode ? FIFO_QUEUE : LIFO_QUEUE, //任務(wù)隊列出隊模式 異步:先進(jìn)先出,同步:后進(jìn)先出  
  11.             "ForkJoinPool-" + nextPoolId() + "-worker-");  
  12.     checkPermission();  

看完初始化的代碼我們可以知道原來創(chuàng)建ForkJoinPool創(chuàng)建workerThread的工作都是統(tǒng)一由一個叫ForkJoinWorkerThreadFactory的工廠去創(chuàng)建,創(chuàng)建出來的線程都有一個統(tǒng)一的前輟名稱"ForkJoinPool-" + nextPoolId() + "-worker-".隊列出隊模式是LIFO(后進(jìn)先出),那這樣后面的入隊的任務(wù)是會被先處理的。

所以上面提到對代碼做了一些修改就是先處理rightTask,再處理leftTask。這其實是對代碼的一種優(yōu)化! 

 
 
 
 
  1. //執(zhí)行子任務(wù)  
  2.  leftTask.fork();  
  3.  rightTask.fork();  
  4.  Integer rightResult = rightTask.join();  
  5.  Integer leftResult = leftTask.join(); 

4、任務(wù)的提交邏輯?

fork/join其實大部分邏輯處理操作都集中在提交任務(wù)和處理任務(wù)這兩塊,了解任務(wù)的提交基本上后面就很容易理解了。

fork/join提交任務(wù)主要分為兩種:

第一種:第一次提交到forkJoinPool 

 
 
 
 
  1. ForkJoinTask forkJoinTask = forkJoinPool.submit(countTask); 

第二種:任務(wù)切分之后的提交 

 
 
 
 
  1. leftTask.fork();  
  2. rightTask.fork(); 

提交到forkJoinPool :

代碼調(diào)用路徑 submit(ForkJoinTask task) -> externalPush(ForkJoinTask task) -> externalSubmit(ForkJoinTask task)

下面貼上externalSubmit的詳細(xì)代碼,著重留意注釋的部分。 

 
 
 
 
  1. private void externalSubmit(ForkJoinTask task) {  
  2.        int r;                                    // initialize caller's probe  
  3.        if ((r = ThreadLocalRandom.getProbe()) == 0) {  
  4.            ThreadLocalRandom.localInit();  
  5.            r = ThreadLocalRandom.getProbe();  
  6.        }  
  7.        for (;;) { //采用循環(huán)入隊的方式  
  8.            WorkQueue[] ws; WorkQueue q; int rs, m, k;  
  9.            boolean move = false;  
  10.            if ((rs = runState) < 0) {  
  11.                tryTerminate(false, false);     // help terminate  
  12.                throw new RejectedExecutionException();  
  13.            }  
  14.            else if ((rs & STARTED) == 0 ||     // initialize 初始化操作  
  15.                     ((ws = workQueues) == null || (m = ws.length - 1) < 0)) {  
  16.                int ns = 0;  
  17.                rs = lockRunState();  
  18.                try {  
  19.                    if ((rs & STARTED) == 0) {  
  20.                        U.compareAndSwapObject(this, STEALCOUNTER, null,  
  21.                                               new AtomicLong());  
  22.                        // create workQueues array with size a power of two  
  23.                        int p = config & SMASK; // ensure at least 2 slots //config就是cpu的核數(shù)  
  24.                        int n = (p > 1) ? p - 1 : 1;  
  25.                        n |= n >>> 1; n |= n >>> 2;  n |= n >>> 4;  
  26.                        n |= n >>> 8; n |= n >>> 16; n = (n + 1) << 1; //算出workQueues的大小n,n一定是2的次方數(shù)  
  27.                        workQueues = new WorkQueue[n];  //初始化隊列,然后跳到最外面的循環(huán)繼續(xù)把任務(wù)入隊~  
  28.                        ns = STARTED;  
  29.                    }  
  30.                } finally {  
  31.                    unlockRunState(rs, (rs & ~RSLOCK) | ns);  
  32.                }  
  33.            }  
  34.            else if ((q = ws[k = r & m & SQMASK]) != null) { //選中了一個一個非空隊列  
  35.                if (q.qlock == 0 && U.compareAndSwapInt(q, QLOCK, 0, 1)) { //利用cas操作加鎖成功!  
  36.                    ForkJoinTask[] a = q.array;  
  37.                    int s = q.top;  
  38.                    boolean submitted = false; // initial submission or resizing  
  39.                    try {                      // locked version of push  
  40.                        if ((a != null && a.length > s + 1 - q.base) ||  
  41.                            (a = q.growArray()) != null) {  
  42.                            int j = (((a.length - 1) & s) << ASHIFT) + ABASE; //計算出任務(wù)在隊列中的位置  
  43.                            U.putOrderedObject(a, j, task);  //把任務(wù)放在隊列中  
  44.                            U.putOrderedInt(q, QTOP, s + 1); //更新一次存放的位置  
  45.                            submitted = true;  
  46.                        }  
  47.                    } finally {  
  48.                        U.compareAndSwapInt(q, QLOCK, 1, 0); //利用cas操作釋放鎖!  
  49.                    }  
  50.                    if (submitted) {  
  51.                        signalWork(ws, q);  
  52.                        return; //任務(wù)入隊成功了!跳出循環(huán)!  
  53.                    }  
  54.                }  
  55.                move = true;                   // move on failure  
  56.            }  
  57.            else if (((rs = runState) & RSLOCK) == 0) { // create new queue 選中的隊列是空,初始化完隊列,然后繼續(xù)入隊!  
  58.                q = new WorkQueue(this, null);  
  59.                q.hint = r;  
  60.                q.config = k | SHARED_QUEUE;  
  61.                q.scanState = INACTIVE;  
  62.                rs = lockRunState();           // publish index  
  63.                if (rs > 0 &&  (ws = workQueues) != null &&  
  64.                    k < ws.length && ws[k] == null)  
  65.                    ws[k] = q;                 // else terminated  
  66.                unlockRunState(rs, rs & ~RSLOCK);  
  67.            }  
  68.            else  
  69.                move = true;                   // move if busy  
  70.            if (move)  
  71.                r = ThreadLocalRandom.advanceProbe(r);  
  72.        }  
  73.    } 

通過對externalSubmit方法的代碼進(jìn)行分析,我們知道了第一次提交任務(wù)給forkJoinPool時是在無限循環(huán)for (;;)中入隊。第一步先檢查workQueues是不是還沒有創(chuàng)建,如果沒有,則進(jìn)行創(chuàng)建。之后跳到外層for循環(huán)并隨機(jī)選取workQueues里面一個隊列,并判斷隊列是否已創(chuàng)建。沒有創(chuàng)建,則進(jìn)行創(chuàng)建!后又跳到外層for循環(huán)直到選到一個非空隊列并且加鎖成功!這樣最后才把任務(wù)入隊~。

所以我們知道fork/join的任務(wù)隊列workQueues并不是初始化的時候就創(chuàng)建好了,而是在有任務(wù)提交的時候才創(chuàng)建!并且每次入隊時都需要利用cas操作來進(jìn)行加鎖和釋放鎖!

任務(wù)切分之后的提交: 

 
 
 
 
  1. public final ForkJoinTask fork() {  
  2.       Thread t;  
  3.       if ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) 
  4.           ((ForkJoinWorkerThread)t).workQueue.push(this); //workerThread直接入自己的workQueue  
  5.       else  
  6.           ForkJoinPool.common.externalPush(this);  
  7.       return this;  
  8.   }  
 
 
 
 
  1. final void externalPush(ForkJoinTask task) {  
  2.         WorkQueue[] ws; WorkQueue q; int m;  
  3.         int r = ThreadLocalRandom.getProbe();  
  4.         int rs = runState;  
  5.         if ((ws = workQueues) != null && (m = (ws.length - 1)) >= 0 &&  
  6.             (q = ws[m & r & SQMASK]) != null && r != 0 && rs > 0 &&  
  7.             U.compareAndSwapInt(q, QLOCK, 0, 1)) { //隨機(jī)選取了一個非空隊列,并且加鎖成功!下面是普通的入隊過程~  
  8.             ForkJoinTask[] a; int am, n, s;  
  9.             if ((a = q.array) != null &&  
  10.                 (aam = a.length - 1) > (n = (s = q.top) - q.base)) {  
  11.                 int j = ((am & s) << ASHIFT) + ABASE;  
  12.                 U.putOrderedObject(a, j, task);  
  13.                 U.putOrderedInt(q, QTOP, s + 1);  
  14.                 U.putIntVolatile(q, QLOCK, 0); 
  15.                  if (n <= 1)  
  16.                     signalWork(ws, q);  
  17.                 return; //結(jié)束方法  
  18.             }  
  19.             U.compareAndSwapInt(q, QLOCK, 1, 0); //一定要釋放鎖!  
  20.         }
            //這個就是上面的externalSummit方法,邏輯是一樣的~  
  21.         externalSubmit(task);  
  22.     } 

從代碼中我們知道了提交一個fork任務(wù)的過程和第一次提交到forkJoinPool的過程是大同小異的。主要區(qū)分了提交任務(wù)的線程是不是workerThread,如果是,任務(wù)直接入workerThread當(dāng)前的workQueue,不是則嘗試選中一個workQueue q。如果q非空并且加鎖成功則進(jìn)行入隊,否則執(zhí)行與第一次任務(wù)提交到forkJoinPool差不多的邏輯~。

5、任務(wù)的消費

提交到任務(wù)的最終目的,是為了消費任務(wù)并最終獲取到我們想要的結(jié)果。介紹任務(wù)消費之前我們先了解一個我們的任務(wù)ForkJoinTask有哪些關(guān)鍵屬性和方法。 

 
 
 
 
  1. /** The run status of this task */  
  2. volatile int status; // accessed directly by pool and workers  
  3. static final int DONE_MASK   = 0xf0000000;  // mask out non-completion bits  
  4. static final int NORMAL      = 0xf0000000;  // must be negative  
  5. static final int CANCELLED   = 0xc0000000;  // must be < NORMAL  
  6. static final int EXCEPTIONAL = 0x80000000;  // must be < CANCELLED  
  7. static final int SIGNAL      = 0x00010000;  // must be >= 1 << 16  
  8. static final int SMASK       = 0x0000ffff;  // short bits for tags  
 
 
 
 
  1. final int doExec() { //任務(wù)的執(zhí)行入口  
  2.   int s; boolean completed;  
  3.   if ((s = status) >= 0) {  
  4.       try {  
  5.           completed = exec();  
  6.       } catch (Throwable rex) {  
  7.           return setExceptionalCompletion(rex);  
  8.       }  
  9.       if (completed)  
  10.           s = setCompletion(NORMAL);  
  11.   }  
  12.   return s;  
  13.  } 

再看一下RecursiveTask的定義 

 
 
 
 
  1. public abstract class RecursiveTask extends ForkJoinTask {  
  2.     private static final long serialVersionUID = 5232453952276485270L;  
  3.     /**  
  4.      * The result of the computation.  
  5.      */  
  6.     V result;  
  7.     /**  
  8.      * The main computation performed by this task.  
  9.      * @return the result of the computation 
  10.      */  
  11.     protected abstract V compute(); //我們實現(xiàn)的處理邏輯  
  12.     public final V getRawResult() { //獲取返回計算結(jié)果  
  13.         return result;  
  14.     }  
  15.     protected final void setRawResult(V value) {  
  16.         result = value;  
  17.     }  
  18.     /**  
  19.      * Implements execution conventions for RecursiveTask.  
  20.      */  
  21.     protected final boolean exec() {  
  22.         result = compute(); //存儲計算結(jié)果  
  23.         return true;  
  24.     }  

在代碼中我們看到任務(wù)的真正執(zhí)行鏈路是 doExec -> exec -> compute -> 最后設(shè)置status 和 result。既然定義狀態(tài)status并且還是volatile類型我們可以推斷出workerThread在獲取到執(zhí)行任務(wù)之后都會先判斷status是不是已完成或者異常狀態(tài),才決定要不要處理該任務(wù)。

下面看一下任務(wù)真正的處理邏輯代碼! 

 
 
 
 
  1. Integer rightResult = rightTask.join()  
  2.   public final V join() {  
  3.       int s;  
  4.       if ((s = doJoin() & DONE_MASK) != NORMAL)  
  5.           reportException(s);  
  6.       return getRawResult();  
  7.    }  
  8.   //執(zhí)行處理前先判斷staus是不是已完成,如果完成了就直接返回  
  9.  //因為這個任務(wù)可能被其它線程竊取過去處理完了  
  10.   private int doJoin() {  
  11.       int s; Thread t; ForkJoinWorkerThread wt; ForkJoinPool.WorkQueue w;  
  12.       return (s = status) < 0 ? s :  
  13.           ((t = Thread.currentThread()) instanceof ForkJoinWorkerThread) ?  
  14.           (w = (wt = (ForkJoinWorkerThread)t).workQueue).  
  15.           tryUnpush(this) && (s = doExec()) < 0 ? s :  
  16.           wt.pool.awaitJoin(w, this, 0L) :  
  17.           externalAwaitDone();  
  18.   }  

代碼的調(diào)用鏈?zhǔn)菑纳系较?。整體處理邏輯如下:

線程是workerThread:

先判斷任務(wù)是否已經(jīng)處理完成,任務(wù)完成直接返回,沒有則直接嘗試出隊tryUnpush(this) 然后執(zhí)行任務(wù)處理doExec()。如果沒有出隊成功或者處理成功,則執(zhí)行wt.pool.awaitJoin(w, this, 0L)。wt.pool.awaitJoin(w, this, 0L)的處理邏輯簡單來說也是在一個for(;;)中不斷的輪詢?nèi)蝿?wù)的狀態(tài)是不是已完成,完成就直接退出方法。否就繼續(xù)嘗試出隊處理。直到任務(wù)完成或者超時為止。

線程不是workerThread:

直接進(jìn)行入externalAwaitDone() 

 
 
 
 
  1. private int externalAwaitDone() {  
  2.        int s = ((this instanceof CountedCompleter) ? // try helping  
  3.                 ForkJoinPool.common.externalHelpComplete(  
  4.                     (CountedCompleter)this, 0) :  
  5.                 ForkJoinPool.common.tryExternalUnpush(this) ? doExec() : 0);  
  6.        if (s >= 0 && (s = status) >= 0) {  
  7.            boolean interrupted = false;  
  8.            do {  
  9.                if (U.compareAndSwapInt(this, STATUS, s, s | SIGNAL)) {  
  10.                    synchronized (this) {  
  11.                        if (status >= 0) {  
  12.                            try {  
  13.                                wait(0L);  
  14.                            } catch (InterruptedException ie) {  
  15.                                interrupted = true;  
  16.                            }  
  17.                        } 
  18.                        else  
  19.                            notifyAll();  
  20.                    }  
  21.                }  
  22.            } while ((s = status) >= 0);  
  23.            if (interrupted)  
  24.                Thread.currentThread().interrupt();  
  25.        }  
  26.        return s; 

externalAwaitDone的處理邏輯其實也比較簡單,當(dāng)前線程自己先嘗試把任務(wù)出隊ForkJoinPool.common.tryExternalUnpush(this) ? doExec()然后處理掉,如果不成功就交給workerThread去處理,然后利用object/wait的經(jīng)典方法去監(jiān)聽任務(wù)status的狀態(tài)變更。

6、任務(wù)的竊取

一直說fork/join的任務(wù)是work-stealing(工作竊取),那任務(wù)究竟是怎么被竊取的呢。我們分析一下任務(wù)是由workThread來竊取的,workThread是一個線程。線程的所有邏輯都是由run()方法執(zhí)行,所以任務(wù)的竊取邏輯一定在run()方法中可以找到! 

 
 
 
 
  1. public void run() { //線程run方法  
  2.        if (workQueue.array == null) { // only run once  
  3.            Throwable exception = null;  
  4.            try {  
  5.                onStart();  
  6.                pool.runWorker(workQueue);  //在這里處理任務(wù)隊列!  
  7.            } catch (Throwable ex) {  
  8.                exexception = ex; 
  9.            } finally {  
  10.                try {  
  11.                    onTermination(exception);  
  12.                } catch (Throwable ex) {  
  13.                    if (exception == null)  
  14.                        exexception = ex;  
  15.                } finally {  
  16.                    pool.deregisterWorker(this, exception);  
  17.                }  
  18.            }  
  19.        }  
  20.    }  
  21.   /**  
  22.     * Top-level runloop for workers, called by ForkJoinWorkerThread.run.  
  23.     */  
  24.    final void runWorker(WorkQueue w) {  
  25.        w.growArray();                   // allocate queue  進(jìn)行隊列的初始化  
  26.        int seed = w.hint;               // initially holds randomization hint  
  27.        int r = (seed == 0) ? 1 : seed;  // avoid 0 for xorShift  
  28.        for (ForkJoinTask t;;) { //又是無限循環(huán)處理任務(wù)!  
  29.            if ((t = scan(w, r)) != null) //在這里獲取任務(wù)!  
  30.                w.runTask(t);  
  31.            else if (!awaitWork(w, r))  
  32.                break;  
  33.            r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // xorshift  

  34. 分享文章:fork/join全面剖析,你可以不用,但是不能不懂!
    網(wǎng)站網(wǎng)址:http://www.5511xx.com/article/dhssodi.html