Java. util. concurrent package source code reading 23 Fork/Join framework Fork tip, forkjoin
The previous article has been tracking the pushTask method of ForkJoinWorkerThread, and there is still no way to explain the Fork principle. Let's take a look at the run method of ForkJoinWorkerThread:
Public void run () {Throwable exception = null; try {// initialize the task queue onStart (); // thread run pool. work (this);} catch (Throwable ex) {exception = ex;} finally {// work onTermination (exception) after completion );}}
So we need to go back to ForkJoinPool again to see the work method:
Final void work (ForkJoinWorkerThread w) {boolean swept = false; // The scan method below does not scan the task and returns true long c; // ctl is a 64-bit long data, the format is as follows: // 48-63: AC, number of running worker threads minus the number of system threads (the actual number of threads waiting for concurrent resources at a certain moment after the system concurrency) // 32-47: TC, the number of all worker threads minus the number of system concurrency // 31: ST, 1 indicates that the thread pool is being closed // 16-30: EC, number of waits for the first waiting thread // 0-15: ID, index of the worker thread at the top of the Treiber stack (storing the waiting thread) in the thread queue of the thread pool // (int) (c = ctl)> = 0 indicates that the ST bit is 0, that is, the thread pool is not in the closed status while (! W. terminate & (int) (c = ctl)> = 0) {int a; // Number of running worker threads, the AC part in ctl // if the value of swept is false, there may be three types: // 1. scan returns false // 2. first loop // 3. tryAwaitWork succeeded if (! Swept & (a = (int) (c> AC_SHIFT) <= 0) swept = scan (w, a); else if (tryAwaitWork (w, c )) swept = false ;}}
Next, I analyzed the scan method and admitted that I was a little dizzy.
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; // The code looks dizzy. It seems that the current ForkJoinWorkerThread is not necessarily running its own // Task, but can run tasks of other forkjoinworkerthreads. // It seems a bit clear, so that Fork tasks can be executed by multiple threads. // it seems that this is a complicated algorithm 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.exe cTask (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.exe cTask (t);} return false;} return true; // all queues empty }}
But at least we can see how the Fork job is run by other threads to implement multi-thread running. In the face of such a complicated algorithm, I can only check it first and find it is originally called Work-Stealing. Well, the next article will study this Work-Stealing.