forked from itwanger/toBeBetterJavaer
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfork-join.html
More file actions
227 lines (209 loc) · 80.5 KB
/
Copy pathfork-join.html
File metadata and controls
227 lines (209 loc) · 80.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="generator" content="VuePress 2.0.0-beta.46" />
<meta name="theme" content="VuePress Theme Hope" />
<meta property="og:url" content="https://tobebetterjavaer.com/thread/fork-join.html"><meta property="og:site_name" content="Java 程序员进阶之路"><meta property="og:title" content="深入理解Java并发编程之Fork/Join框架"><meta property="og:type" content="article"><meta property="og:updated_time" content="2022-05-12T08:24:21.000Z"><meta property="og:locale" content="zh-CN"><meta property="article:tag" content="Java"><meta property="article:modified_time" content="2022-05-12T08:24:21.000Z"><script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?5230ac143650bf5eb3c14f3fb9b1d3ec";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script><link rel="stylesheet" href="//at.alicdn.com/t/font_3180624_7cy10l7jqqh.css"><link rel="icon" href="/favicon.ico"><link rel="icon" href="/assets/icon/chrome-mask-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-mask-192.png" type="image/png" sizes="192x192"><link rel="icon" href="/assets/icon/chrome-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-192.png" type="image/png" sizes="192x192"><link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials"><meta name="theme-color" content="#46bd87"><link rel="apple-touch-icon" href="/assets/icon/apple-icon-152.png"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="msapplication-TileImage" content="/assets/icon/ms-icon-144.png"><meta name="msapplication-TileColor" content="#ffffff"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"><title>深入理解Java并发编程之Fork/Join框架 | Java 程序员进阶之路</title><meta name="description" content="一份通俗易懂、风趣幽默的Java学习指南,内容涵盖Java基础、Java并发编程、Java虚拟机、Java企业级开发、Java面试等核心知识点。学Java,就认准Java程序员进阶之路">
<style>
:root {
--bg-color: #fff;
}
html[data-theme="dark"] {
--bg-color: #1d2025;
}
html,
body {
background-color: var(--bg-color);
}
</style>
<script>
const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
const systemDarkMode =
window.matchMedia &&
window.matchMedia("(prefers-color-scheme: dark)").matches;
if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
document.querySelector("html").setAttribute("data-theme", "dark");
}
</script>
<link rel="stylesheet" href="/assets/style.c081fa20.css">
<link rel="modulepreload" href="/assets/app.41bad062.js"><link rel="modulepreload" href="/assets/fork-join.html.27c6a8e8.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper.21dcd24c.js"><link rel="modulepreload" href="/assets/fork-join.html.f967d485.js">
</head>
<body>
<div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="skip-link sr-only">Skip to content</a><!--]--><div class="theme-container has-toc"><!--[--><!--[--><header class="navbar"><div class="navbar-left"><button class="toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!----><a href="/" class="brand"><img class="logo" src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/logo-02.png" alt="Java 程序员进阶之路"><!----><span class="site-name hide-in-pad">Java 程序员进阶之路</span></a><!----></div><div class="navbar-center"><!----><nav class="nav-links"><div class="nav-item hide-in-mobile"><a href="/blog.html" class="nav-link" aria-label="博客"><span class="icon iconfont icon-gaishu" style=""></span>博客<!----></a></div><div class="nav-item hide-in-mobile"><a href="/home.html" class="nav-link" aria-label="进阶之路"><span class="icon iconfont icon-lujing" style=""></span>进阶之路<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zhishixingqiu/" class="nav-link" aria-label="知识星球"><span class="icon iconfont icon-Artboard" style=""></span>知识星球<!----></a></div><div class="nav-item hide-in-mobile"><a href="/xuexiluxian/" class="nav-link" aria-label="学习路线"><span class="icon iconfont icon-luxian" style=""></span>学习路线<!----></a></div><div class="nav-item hide-in-mobile"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="珍藏资源"><span class="title"><span class="icon iconfont icon-youzhi" style=""></span>珍藏资源</span><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><a href="/download/java.html" class="nav-link" aria-label="电子书下载"><span class="icon iconfont icon-java" style=""></span>电子书下载<!----></a></li><li class="dropdown-item"><a href="/sidebar/sanfene/nixi.html" class="nav-link" aria-label="面渣逆袭"><span class="icon iconfont icon-zhunbei" style=""></span>面渣逆袭<!----></a></li><li class="dropdown-item"><a href="/download/nicearticle.html" class="nav-link" aria-label="优质文章"><span class="icon iconfont icon-youzhi" style=""></span>优质文章<!----></a></li><li class="dropdown-item"><a href="/download/history.html" class="nav-link" aria-label="网络日志"><span class="icon iconfont icon-rizhi" style=""></span>网络日志<!----></a></li><li class="dropdown-item"><a href="/nice-article/itmind/" class="nav-link" aria-label="破解合集"><span class="icon iconfont icon-zhongyaotishi" style=""></span>破解合集<!----></a></li></ul></button></div></div><div class="nav-item hide-in-mobile"><a href="https://space.bilibili.com/513340480" rel="noopener noreferrer" target="_blank" aria-label="B站视频" class="nav-link"><span class="icon iconfont icon-bzhan" style=""></span>B站视频<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div></nav><!----></div><div class="navbar-right"><!----><div class="nav-item"><!----></div><div class="nav-item"><a class="repo-link" href="https://github.com/itwanger/toBeBetterJavaer" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" class="icon github-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="github icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M511.957 21.333C241.024 21.333 21.333 240.981 21.333 512c0 216.832 140.544 400.725 335.574 465.664 24.49 4.395 32.256-10.07 32.256-23.083 0-11.69.256-44.245 0-85.205-136.448 29.61-164.736-64.64-164.736-64.64-22.315-56.704-54.4-71.765-54.4-71.765-44.587-30.464 3.285-29.824 3.285-29.824 49.195 3.413 75.179 50.517 75.179 50.517 43.776 75.008 114.816 53.333 142.762 40.79 4.523-31.66 17.152-53.377 31.19-65.537-108.971-12.458-223.488-54.485-223.488-242.602 0-53.547 19.114-97.323 50.517-131.67-5.035-12.33-21.93-62.293 4.779-129.834 0 0 41.258-13.184 134.912 50.346a469.803 469.803 0 0 1 122.88-16.554c41.642.213 83.626 5.632 122.88 16.554 93.653-63.488 134.784-50.346 134.784-50.346 26.752 67.541 9.898 117.504 4.864 129.834 31.402 34.347 50.474 78.123 50.474 131.67 0 188.586-114.73 230.016-224.042 242.09 17.578 15.232 33.578 44.672 33.578 90.454v135.85c0 13.142 7.936 27.606 32.854 22.87C862.25 912.597 1002.667 728.747 1002.667 512c0-271.019-219.648-490.667-490.71-490.667z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><div id="docsearch-container"></div><!----><button class="toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span class="button-container"><span class="button-top"></span><span class="button-middle"></span><span class="button-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow left"></span></div><aside class="sidebar"><!--[--><!----><!--]--><ul class="sidebar-links"><li><!--[--><a href="/home.html" class="nav-link sidebar-link sidebar-page" aria-label="一、前言"><!---->一、前言<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">二、Java核心</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.1 Java概述</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.2 Java语法基础</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.3 数组&字符串</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.4 面向对象编程</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.5 集合框架(容器)</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.6 IO</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.7 异常处理</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.8 常用工具类</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.9 Java新特性</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.10 Java重要知识点</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">2.11 并发编程</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><a href="/thread/wangzhe-thread.html" class="nav-link sidebar-link sidebar-page" aria-label="创建Java线程的3种方式"><!---->创建Java线程的3种方式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/thread-state-and-method.html" class="nav-link sidebar-link sidebar-page" aria-label="线程的6种状态及切换"><!---->线程的6种状态及切换<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/thread-group-and-thread-priority.html" class="nav-link sidebar-link sidebar-page" aria-label="线程组和线程优先级"><!---->线程组和线程优先级<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/why-need-thread.html" class="nav-link sidebar-link sidebar-page" aria-label="进程与线程的区别"><!---->进程与线程的区别<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/thread-bring-some-problem.html" class="nav-link sidebar-link sidebar-page" aria-label="并发编程带来了哪些问题"><!---->并发编程带来了哪些问题<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/jmm.html" class="nav-link sidebar-link sidebar-page" aria-label="Java内存模型"><!---->Java内存模型<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/volatile.html" class="nav-link sidebar-link sidebar-page" aria-label="volatile"><!---->volatile<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/synchronized.html" class="nav-link sidebar-link sidebar-page" aria-label="synchronized"><!---->synchronized<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/cas.html" class="nav-link sidebar-link sidebar-page" aria-label="CAS的原理"><!---->CAS的原理<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/aqs.html" class="nav-link sidebar-link sidebar-page" aria-label="AQS详解"><!---->AQS详解<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/lock.html" class="nav-link sidebar-link sidebar-page" aria-label="锁"><!---->锁<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/reentrantLock.html" class="nav-link sidebar-link sidebar-page" aria-label="重入锁ReentrantLock"><!---->重入锁ReentrantLock<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/ReentrantReadWriteLock.html" class="nav-link sidebar-link sidebar-page" aria-label="读写锁ReentrantReadWriteLock"><!---->读写锁ReentrantReadWriteLock<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/condition.html" class="nav-link sidebar-link sidebar-page" aria-label="线程协作类Condition"><!---->线程协作类Condition<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/LockSupport.html" class="nav-link sidebar-link sidebar-page" aria-label="线程阻塞唤醒类LockSupport"><!---->线程阻塞唤醒类LockSupport<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/map.html" class="nav-link sidebar-link sidebar-page" aria-label="并发集合容器"><!---->并发集合容器<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/ConcurrentHashMap.html" class="nav-link sidebar-link sidebar-page" aria-label="ConcurrentHashMap"><!---->ConcurrentHashMap<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/ConcurrentLinkedQueue.html" class="nav-link sidebar-link sidebar-page" aria-label="ConcurrentLinkedQueue"><!---->ConcurrentLinkedQueue<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/CopyOnWriteArrayList.html" class="nav-link sidebar-link sidebar-page" aria-label="CopyOnWriteArrayList"><!---->CopyOnWriteArrayList<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/ThreadLocal.html" class="nav-link sidebar-link sidebar-page" aria-label="ThreadLocal"><!---->ThreadLocal<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/BlockingQueue.html" class="nav-link sidebar-link sidebar-page" aria-label="BlockingQueue"><!---->BlockingQueue<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/pool.html" class="nav-link sidebar-link sidebar-page" aria-label="线程池"><!---->线程池<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/ScheduledThreadPoolExecutor.html" class="nav-link sidebar-link sidebar-page" aria-label="计划任务"><!---->计划任务<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/atomic.html" class="nav-link sidebar-link sidebar-page" aria-label="原子操作类"><!---->原子操作类<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/thread/CountDownLatch.html" class="nav-link sidebar-link sidebar-page" aria-label="通信工具类CountDownLatch"><!---->通信工具类CountDownLatch<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a aria-current="page" href="/thread/fork-join.html" class="router-link-active router-link-exact-active nav-link active sidebar-link sidebar-page active" aria-label="Fork/Join框架"><!---->Fork/Join框架<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#什么是fork-join" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="什么是Fork/Join"><!---->什么是Fork/Join<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#工作窃取算法" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="工作窃取算法"><!---->工作窃取算法<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#fork-join的具体实现" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="Fork/Join的具体实现"><!---->Fork/Join的具体实现<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#forkjointask" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="ForkJoinTask"><!---->ForkJoinTask<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#forkjoinpool" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="ForkJoinPool"><!---->ForkJoinPool<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/thread/fork-join.html#fork-join的使用" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="Fork/Join的使用"><!---->Fork/Join的使用<!----></a><ul class="sidebar-sub-headers"></ul></li></ul><!--]--></li><li><!--[--><a href="/thread/shengchanzhe-xiaofeizhe.html" class="nav-link sidebar-link sidebar-page" aria-label="生产者-消费者模式"><!---->生产者-消费者模式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.12 JVM</span><span class="arrow right"></span></button><!----></section><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">三、Java企业级开发</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">四、数据库</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">五、计算机基础</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">六、求职面试</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">七、学习资源</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">八、学习建议</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">九、知识库搭建</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">十、联系作者</span><span class="arrow right"></span></button><!----></section><!--]--></li></ul><!--[--><!----><!--]--></aside><!--[--><main class="page" id="main-content"><!--[--><!----><nav class="breadcrumb disable"></nav><div class="page-title"><h1><!---->深入理解Java并发编程之Fork/Join框架</h1><div class="page-info"><span class="author-info" aria-label="作者🖊" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><a class="author-item" href="/about-the-author/" target="_blank" rel="noopener noreferrer">沉默王二</a></span><span property="author" content="沉默王二"></span></span><!----><span class="date-info" aria-label="写作日期📅" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon calendar-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="calendar icon"><path d="M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"></path></svg><span>2022年3月23日</span><meta property="datePublished" content="2022-03-23T12:08:58.000Z"></span><span class="category-info" aria-label="分类🌈" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon category-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="category icon"><path d="M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"></path></svg><ul class="categories-wrapper"><li class="category category0 clickable" role="navigation">Java核心</li><li class="category category6 clickable" role="navigation">并发编程</li><meta property="articleSection" content="Java核心,并发编程"></ul></span><span aria-label="标签🏷" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon tag-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="tag icon"><path d="M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"></path></svg><ul class="tags-wrapper"><li class="tag tag4 clickable" role="navigation">Java</li></ul><meta property="keywords" content="Java"></span><span class="reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 9 分钟</span><meta property="timeRequired" content="PT9M"></span></div><hr></div><div class="toc-place-holder"><aside id="toc"><div class="toc-header">此页内容</div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#什么是fork-join" class="router-link-active router-link-exact-active toc-link level2">什么是Fork/Join</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#工作窃取算法" class="router-link-active router-link-exact-active toc-link level2">工作窃取算法</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#fork-join的具体实现" class="router-link-active router-link-exact-active toc-link level2">Fork/Join的具体实现</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#forkjointask" class="router-link-active router-link-exact-active toc-link level3">ForkJoinTask</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#forkjoinpool" class="router-link-active router-link-exact-active toc-link level3">ForkJoinPool</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/thread/fork-join.html#fork-join的使用" class="router-link-active router-link-exact-active toc-link level2">Fork/Join的使用</a></li><!----><!--]--></ul></div></aside></div><!----><div class="theme-hope-content"><h2 id="什么是fork-join" tabindex="-1"><a class="header-anchor" href="#什么是fork-join" aria-hidden="true">#</a> 什么是Fork/Join</h2><p>Fork/Join框架是一个实现了ExecutorService接口的多线程处理器,它专为那些可以通过递归分解成更细小的任务而设计,最大化的利用多核处理器来提高应用程序的性能。</p><p>与其他ExecutorService相关的实现相同的是,Fork/Join框架会将任务分配给线程池中的线程。而与之不同的是,Fork/Join框架在执行任务时使用了<strong>工作窃取算法</strong>。</p><p><strong>fork</strong>在英文里有分叉的意思,<strong>join</strong>在英文里连接、结合的意思。顾名思义,fork就是要使一个大任务分解成若干个小任务,而join就是最后将各个小任务的结果结合起来得到大任务的结果。</p><p>Fork/Join的运行流程大致如下所示:</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/thread/fork-join-ba0c0e3f-dc9b-445d-874a-5878503a98f7.png" alt="fork/join流程图"></p><p>需要注意的是,图里的次级子任务可以一直分下去,一直分到子任务足够小为止。用伪代码来表示如下:</p><div class="language-pseudocode ext-pseudocode line-numbers-mode"><pre class="language-pseudocode"><code>solve(任务):
if(任务已经划分到足够小):
顺序执行任务
else:
for(划分任务得到子任务)
solve(子任务)
结合所有子任务的结果到上一层循环
return 最终结合的结果
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过上面伪代码可以看出,我们通过递归嵌套的计算得到最终结果,这里有体现<strong>分而治之(divide and conquer)</strong> 的算法思想。</p><h2 id="工作窃取算法" tabindex="-1"><a class="header-anchor" href="#工作窃取算法" aria-hidden="true">#</a> 工作窃取算法</h2><p>工作窃取算法指的是在多线程执行不同任务队列的过程中,某个线程执行完自己队列的任务后从其他线程的任务队列里窃取任务来执行。</p><p>工作窃取流程如下图所示:</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/thread/fork-join-819f4ad9-25ce-4e7e-a1d7-e36a70e584a4.png" alt="工作窃取算法流程"></p><p>值得注意的是,当一个线程窃取另一个线程的时候,为了减少两个任务线程之间的竞争,我们通常使用<strong>双端队列</strong>来存储任务。被窃取的任务线程都从双端队列的<strong>头部</strong>拿任务执行,而窃取其他任务的线程从双端队列的<strong>尾部</strong>执行任务。</p><p>另外,当一个线程在窃取任务时要是没有其他可用的任务了,这个线程会进入<strong>阻塞状态</strong>以等待再次“工作”。</p><h2 id="fork-join的具体实现" tabindex="-1"><a class="header-anchor" href="#fork-join的具体实现" aria-hidden="true">#</a> Fork/Join的具体实现</h2><p>前面我们说Fork/Join框架简单来讲就是对任务的分割与子任务的合并,所以要实现这个框架,先得有<strong>任务</strong>。在Fork/Join框架里提供了抽象类<code>ForkJoinTask</code>来实现任务。</p><h3 id="forkjointask" tabindex="-1"><a class="header-anchor" href="#forkjointask" aria-hidden="true">#</a> ForkJoinTask</h3><p>ForkJoinTask是一个类似普通线程的实体,但是比普通线程轻量得多。</p><p><strong>fork()方法</strong>:使用线程池中的空闲线程异步提交任务</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 本文所有代码都引自Java 8</span>
<span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">ForkJoinTask</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">V</span><span class="token punctuation">></span></span> <span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Thread</span> t<span class="token punctuation">;</span>
<span class="token comment">// ForkJoinWorkerThread是执行ForkJoinTask的专有线程,由ForkJoinPool管理</span>
<span class="token comment">// 先判断当前线程是否是ForkJoin专有线程,如果是,则将任务push到当前线程所负责的队列里去</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>t <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">ForkJoinWorkerThread</span><span class="token punctuation">)</span>
<span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">ForkJoinWorkerThread</span><span class="token punctuation">)</span>t<span class="token punctuation">)</span><span class="token punctuation">.</span>workQueue<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span>
<span class="token comment">// 如果不是则将线程加入队列</span>
<span class="token comment">// 没有显式创建ForkJoinPool的时候走这里,提交任务到默认的common线程池中</span>
<span class="token class-name">ForkJoinPool</span><span class="token punctuation">.</span>common<span class="token punctuation">.</span><span class="token function">externalPush</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>其实fork()只做了一件事,那就是<strong>把任务推入当前工作线程的工作队列里</strong>。</p><p><strong>join()方法</strong>:等待处理任务的线程处理完毕,获得返回值。</p><p>来看下join()的源码:</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token class-name">V</span> <span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> s<span class="token punctuation">;</span>
<span class="token comment">// doJoin()方法来获取当前任务的执行状态</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>s <span class="token operator">=</span> <span class="token function">doJoin</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&</span> DONE_MASK<span class="token punctuation">)</span> <span class="token operator">!=</span> NORMAL<span class="token punctuation">)</span>
<span class="token comment">// 任务异常,抛出异常</span>
<span class="token function">reportException</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 任务正常完成,获取返回值</span>
<span class="token keyword">return</span> <span class="token function">getRawResult</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token doc-comment comment">/**
* doJoin()方法用来返回当前任务的执行状态
**/</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> <span class="token function">doJoin</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> s<span class="token punctuation">;</span> <span class="token class-name">Thread</span> t<span class="token punctuation">;</span> <span class="token class-name">ForkJoinWorkerThread</span> wt<span class="token punctuation">;</span> <span class="token class-name">ForkJoinPool<span class="token punctuation">.</span>WorkQueue</span> w<span class="token punctuation">;</span>
<span class="token comment">// 先判断任务是否执行完毕,执行完毕直接返回结果(执行状态)</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>s <span class="token operator">=</span> status<span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0</span> <span class="token operator">?</span> s <span class="token operator">:</span>
<span class="token comment">// 如果没有执行完毕,先判断是否是ForkJoinWorkThread线程</span>
<span class="token punctuation">(</span><span class="token punctuation">(</span>t <span class="token operator">=</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">currentThread</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">instanceof</span> <span class="token class-name">ForkJoinWorkerThread</span><span class="token punctuation">)</span> <span class="token operator">?</span>
<span class="token comment">// 如果是,先判断任务是否处于工作队列顶端(意味着下一个就执行它)</span>
<span class="token comment">// tryUnpush()方法判断任务是否处于当前工作队列顶端,是返回true</span>
<span class="token comment">// doExec()方法执行任务</span>
<span class="token punctuation">(</span>w <span class="token operator">=</span> <span class="token punctuation">(</span>wt <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ForkJoinWorkerThread</span><span class="token punctuation">)</span>t<span class="token punctuation">)</span><span class="token punctuation">.</span>workQueue<span class="token punctuation">)</span><span class="token punctuation">.</span>
<span class="token comment">// 如果是处于顶端并且任务执行完毕,返回结果</span>
<span class="token function">tryUnpush</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token punctuation">(</span>s <span class="token operator">=</span> <span class="token function">doExec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator"><</span> <span class="token number">0</span> <span class="token operator">?</span> s <span class="token operator">:</span>
<span class="token comment">// 如果不在顶端或者在顶端却没未执行完毕,那就调用awitJoin()执行任务</span>
<span class="token comment">// awaitJoin():使用自旋使任务执行完成,返回结果</span>
wt<span class="token punctuation">.</span>pool<span class="token punctuation">.</span><span class="token function">awaitJoin</span><span class="token punctuation">(</span>w<span class="token punctuation">,</span> <span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token number">0L</span><span class="token punctuation">)</span> <span class="token operator">:</span>
<span class="token comment">// 如果不是ForkJoinWorkThread线程,执行externalAwaitDone()返回任务结果</span>
<span class="token function">externalAwaitDone</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>我们在之前介绍过说Thread.join()会使线程阻塞,而ForkJoinPool.join()会使线程免于阻塞,下面是ForkJoinPool.join()的流程图: <img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/thread/fork-join-8e03485d-efe0-4edf-8516-a9b10dea6e7f.png" alt="join流程图"></p><p><strong>RecursiveAction和RecursiveTask</strong></p><p>通常情况下,在创建任务的时候我们一般不直接继承ForkJoinTask,而是继承它的子类<strong>RecursiveAction</strong>和<strong>RecursiveTask</strong>。</p><p>两个都是ForkJoinTask的子类,<strong>RecursiveAction可以看做是无返回值的ForkJoinTask,RecursiveTask是有返回值的ForkJoinTask</strong>。</p><p>此外,两个子类都有执行主要计算的方法compute(),当然,RecursiveAction的compute()返回void,RecursiveTask的compute()有具体的返回值。</p><h3 id="forkjoinpool" tabindex="-1"><a class="header-anchor" href="#forkjoinpool" aria-hidden="true">#</a> ForkJoinPool</h3><p>ForkJoinPool是用于执行ForkJoinTask任务的执行(线程)池。</p><p>ForkJoinPool管理着执行池中的线程和任务队列,此外,执行池是否还接受任务,显示线程的运行状态也是在这里处理。</p><p>我们来大致看下ForkJoinPool的源码:</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@sun.misc.Contended</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ForkJoinPool</span> <span class="token keyword">extends</span> <span class="token class-name">AbstractExecutorService</span> <span class="token punctuation">{</span>
<span class="token comment">// 任务队列</span>
<span class="token keyword">volatile</span> <span class="token class-name">WorkQueue</span><span class="token punctuation">[</span><span class="token punctuation">]</span> workQueues<span class="token punctuation">;</span>
<span class="token comment">// 线程的运行状态</span>
<span class="token keyword">volatile</span> <span class="token keyword">int</span> runState<span class="token punctuation">;</span>
<span class="token comment">// 创建ForkJoinWorkerThread的默认工厂,可以通过构造函数重写</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">ForkJoinWorkerThreadFactory</span> defaultForkJoinWorkerThreadFactory<span class="token punctuation">;</span>
<span class="token comment">// 公用的线程池,其运行状态不受shutdown()和shutdownNow()的影响</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">ForkJoinPool</span> common<span class="token punctuation">;</span>
<span class="token comment">// 私有构造方法,没有任何安全检查和参数校验,由makeCommonPool直接调用</span>
<span class="token comment">// 其他构造方法都是源自于此方法</span>
<span class="token comment">// parallelism: 并行度,</span>
<span class="token comment">// 默认调用java.lang.Runtime.availableProcessors() 方法返回可用处理器的数量</span>
<span class="token keyword">private</span> <span class="token class-name">ForkJoinPool</span><span class="token punctuation">(</span><span class="token keyword">int</span> parallelism<span class="token punctuation">,</span>
<span class="token class-name">ForkJoinWorkerThreadFactory</span> factory<span class="token punctuation">,</span> <span class="token comment">// 工作线程工厂</span>
<span class="token class-name">UncaughtExceptionHandler</span> handler<span class="token punctuation">,</span> <span class="token comment">// 拒绝任务的handler</span>
<span class="token keyword">int</span> mode<span class="token punctuation">,</span> <span class="token comment">// 同步模式</span>
<span class="token class-name">String</span> workerNamePrefix<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token comment">// 线程名prefix</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>workerNamePrefix <span class="token operator">=</span> workerNamePrefix<span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>factory <span class="token operator">=</span> factory<span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>ueh <span class="token operator">=</span> handler<span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>config <span class="token operator">=</span> <span class="token punctuation">(</span>parallelism <span class="token operator">&</span> SMASK<span class="token punctuation">)</span> <span class="token operator">|</span> mode<span class="token punctuation">;</span>
<span class="token keyword">long</span> np <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token operator">-</span>parallelism<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// offset ctl counts</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>ctl <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>np <span class="token operator"><<</span> AC_SHIFT<span class="token punctuation">)</span> <span class="token operator">&</span> AC_MASK<span class="token punctuation">)</span> <span class="token operator">|</span> <span class="token punctuation">(</span><span class="token punctuation">(</span>np <span class="token operator"><<</span> TC_SHIFT<span class="token punctuation">)</span> <span class="token operator">&</span> TC_MASK<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="workqueue" tabindex="-1"><a class="header-anchor" href="#workqueue" aria-hidden="true">#</a> WorkQueue</h4><p>双端队列,ForkJoinTask存放在这里。</p><p>当工作线程在处理自己的工作队列时,会从队列首取任务来执行(FIFO);如果是窃取其他队列的任务时,窃取的任务位于所属任务队列的队尾(LIFO)。</p><p>ForkJoinPool与传统线程池最显著的区别就是它维护了一个<strong>工作队列数组</strong>(volatile WorkQueue[] workQueues,ForkJoinPool中的<strong>每个工作线程都维护着一个工作队列</strong>)。</p><h4 id="runstate" tabindex="-1"><a class="header-anchor" href="#runstate" aria-hidden="true">#</a> runState</h4><p>ForkJoinPool的运行状态。<strong>SHUTDOWN</strong>状态用负数表示,其他用2的幂次表示。</p><h2 id="fork-join的使用" tabindex="-1"><a class="header-anchor" href="#fork-join的使用" aria-hidden="true">#</a> Fork/Join的使用</h2><p>上面我们说ForkJoinPool负责管理线程和任务,ForkJoinTask实现fork和join操作,所以要使用Fork/Join框架就离不开这两个类了,只是在实际开发中我们常用ForkJoinTask的子类RecursiveTask 和RecursiveAction来替代ForkJoinTask。</p><p>下面我们用一个计算斐波那契数列第n项的例子来看一下Fork/Join的使用:</p><blockquote><p>斐波那契数列数列是一个线性递推数列,从第三项开始,每一项的值都等于前两项之和:</p><p>1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89······</p><p>如果设f(n)为该数列的第n项(n∈N*),那么有:f(n) = f(n-1) + f(n-2)。</p></blockquote><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">FibonacciTest</span> <span class="token punctuation">{</span>
<span class="token keyword">class</span> <span class="token class-name">Fibonacci</span> <span class="token keyword">extends</span> <span class="token class-name">RecursiveTask</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> n<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">Fibonacci</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>n <span class="token operator">=</span> n<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 主要的实现逻辑都在compute()里</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">protected</span> <span class="token class-name">Integer</span> <span class="token function">compute</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 这里先假设 n >= 0</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>n <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> n<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token comment">// f(n-1)</span>
<span class="token class-name">Fibonacci</span> f1 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fibonacci</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
f1<span class="token punctuation">.</span><span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// f(n-2)</span>
<span class="token class-name">Fibonacci</span> f2 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fibonacci</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
f2<span class="token punctuation">.</span><span class="token function">fork</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// f(n) = f(n-1) + f(n-2)</span>
<span class="token keyword">return</span> f1<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> f2<span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testFib</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ExecutionException</span><span class="token punctuation">,</span> <span class="token class-name">InterruptedException</span> <span class="token punctuation">{</span>
<span class="token class-name">ForkJoinPool</span> forkJoinPool <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ForkJoinPool</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"CPU核数:"</span> <span class="token operator">+</span> <span class="token class-name">Runtime</span><span class="token punctuation">.</span><span class="token function">getRuntime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">availableProcessors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Fibonacci</span> fibonacci <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Fibonacci</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Future</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">></span></span> future <span class="token operator">=</span> forkJoinPool<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span>fibonacci<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>future<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"耗时:%d millis"</span><span class="token punctuation">,</span> end <span class="token operator">-</span> start<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面例子在本机的输出:</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>CPU核数:4
计算结果:102334155
耗时:9490 millis
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>需要注意的是,上述计算时间复杂度为<code>O(2^n)</code>,随着n的增长计算效率会越来越低,这也是上面的例子中n不敢取太大的原因。</p><p>此外,也并不是所有的任务都适合Fork/Join框架,比如上面的例子任务划分过于细小反而体现不出效率,下面我们试试用普通的递归来求f(n)的值,看看是不是要比使用Fork/Join快:</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 普通递归,复杂度为O(2^n)</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">plainRecursion</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>n <span class="token operator">==</span> <span class="token number">1</span> <span class="token operator">||</span> n <span class="token operator">==</span> <span class="token number">2</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token function">plainRecursion</span><span class="token punctuation">(</span>n <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token function">plainRecursion</span><span class="token punctuation">(</span>n <span class="token operator">-</span> <span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testPlain</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> result <span class="token operator">=</span> <span class="token function">plainRecursion</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"计算结果:"</span> <span class="token operator">+</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"耗时:%d millis"</span><span class="token punctuation">,</span> end <span class="token operator">-</span>start<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>普通递归的例子输出:</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>计算结果:102334155
耗时:436 millis
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>通过输出可以很明显的看出来,使用普通递归的效率都要比使用Fork/Join框架要高很多。</p><p>这里我们再用另一种思路来计算:</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 通过循环来计算,复杂度为O(n)</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> <span class="token function">computeFibonacci</span><span class="token punctuation">(</span><span class="token keyword">int</span> n<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 假设n >= 0</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>n <span class="token operator"><=</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> n<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> first <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> second <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> third <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> n<span class="token punctuation">;</span> i <span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 第三个数是前两个数之和</span>
third <span class="token operator">=</span> first <span class="token operator">+</span> second<span class="token punctuation">;</span>
<span class="token comment">// 前两个数右移</span>
first <span class="token operator">=</span> second<span class="token punctuation">;</span>
second <span class="token operator">=</span> third<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> third<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testComputeFibonacci</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">long</span> start <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> result <span class="token operator">=</span> <span class="token function">computeFibonacci</span><span class="token punctuation">(</span><span class="token number">40</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">long</span> end <span class="token operator">=</span> <span class="token class-name">System</span><span class="token punctuation">.</span><span class="token function">currentTimeMillis</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"计算结果:"</span> <span class="token operator">+</span> result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"耗时:%d millis"</span><span class="token punctuation">,</span> end <span class="token operator">-</span>start<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>上面例子在笔者所用电脑的输出为:</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>计算结果:102334155
耗时:0 millis
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div></div></div><p>这里耗时为0不代表没有耗时,是表明这里计算的耗时几乎可以忽略不计,大家可以在自己的电脑试试,即使是n取大很多量级的数据(注意int溢出的问题)耗时也是很短的,或者可以用System.nanoTime()统计纳秒的时间。</p><p>为什么在这里普通的递归或循环效率更快呢?因为Fork/Join是使用多个线程协作来计算的,所以会有线程通信和线程切换的开销。</p><p>如果要计算的任务比较简单(比如我们案例中的斐波那契数列),那当然是直接使用单线程会更快一些。但如果要计算的东西比较复杂,计算机又是多核的情况下,就可以充分利用多核CPU来提高计算速度。</p><p>另外,Java 8 Stream的并行操作底层就是用到了Fork/Join框架,下一章我们将从源码及案例两方面介绍Java 8 Stream的并行操作。</p><hr><blockquote><p>编辑:沉默王二,内容大部分来源以下三个开源仓库:</p><ul><li><a href="http://concurrent.redspider.group/" target="_blank" rel="noopener noreferrer">深入浅出 Java 多线程<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li><li><a href="https://github.com/CL0610/Java-concurrency" target="_blank" rel="noopener noreferrer">并发编程知识总结<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li><li><a href="https://github.com/CoderLeixiaoshuai/java-eight-part" target="_blank" rel="noopener noreferrer">Java八股文<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></li></ul></blockquote><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png"></div><!----><footer class="page-meta"><div class="meta-item edit-link"><a href="https://github.com/itwanger/toBeBetterJavaer/edit/master/docs/thread/fork-join.md" rel="noopener noreferrer" target="_blank" aria-label="在 GitHub 上编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->在 GitHub 上编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><div class="meta-item update-time"><span class="label">上次编辑于: </span><span class="info">2022/5/12 下午4:24:21</span></div><div class="meta-item contributors"><span class="label">贡献者: </span><!--[--><!--[--><span class="contributor" title="email: [email protected]">itwanger</span>,<!--]--><!--[--><span class="contributor" title="email: [email protected]">沉默王二</span><!--]--><!--]--></div></footer><nav class="page-nav"><a href="/thread/CountDownLatch.html" class="nav-link prev" aria-label="通信工具类CountDownLatch"><div class="hint"><span class="arrow left"></span>上一页</div><div class="link"><!---->通信工具类CountDownLatch</div></a><a href="/thread/shengchanzhe-xiaofeizhe.html" class="nav-link next" aria-label="生产者-消费者模式"><div class="hint">下一页<span class="arrow right"></span></div><div class="link">生产者-消费者模式<!----></div></a></nav><div class="giscus-wrapper input-top" style="display:block;">Loading...</div><!----><!--]--></main><!--]--><footer class="footer-wrapper"><div class="footer"><a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备2021038026号-1</a><img src="https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/beian.png" height="15px" width="15px" /><a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=41030502000411"><span>豫公网安备 41030502000411号</span></a></div><div class="copyright">Copyright © 2022 沉默王二</div></footer><!--]--></div><!--]--><!----><!----><!--]--></div>
<script type="module" src="/assets/app.41bad062.js" defer></script>
</body>
</html>