Java - 线程池&队列
发布时间:2020-12-15 00:14:50 所属栏目:C语言 来源:网络整理
导读:table class="java" tr class="li1" td class="ln"pre class="de1"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
<table class="java"> |
<tr class="li1">
<td class="ln"><pre class="de1">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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
、为何使用线程池
?
? ? ? ? 减少创建和销毁线程的次数,每个工作线程都可以被重复利用,执行多个任务。
? ? ? ? 可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机。 ?
? ?
、解决办法
?
? ? ? ? Java里面线程池的顶级接口是Executor,但严格意义上Executor并不是一个线程池,而是一个执行线程的工具。真正的线程池接口是ExecutorService。
? ?
? ?ThreadPoolExecutor corePoolSize, maximumPoolSize, keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler
? ?corePoolSize 池中所保存的线程数,包括空闲线程。
? ?maximumPoolSize池中允许的最大线程数。
? ?keepAliveTime 当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。
? ?unit keepAliveTime 参数的时间单位。
? ?workQueue 执行前用于保持任务的队列。此队列仅保持由 execute方法提交的 任务。
? ?threadFactory 执行程序创建新线程时使用的工厂。
? ?handler 由于超出线程范围和队列容量而使执行被阻塞时所使用的处理程序。
? ?
? ?其它不说了,ThreadPoolExecutor的四种线程池实现:
? ?
? ?newSingleThreadExecutor:创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
? ?newFixedThreadPool:创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
? ?newCachedThreadPool:创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
? ?newScheduledThreadPool:创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
? ?
、线程的底层实现 ? ?
?
? ? ? ? 在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
而则从另一个角度来解决多线程的并发访问。会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进。
ThreadLocalDemo
? ? ? ?
? ? ? ?
? ? ? ? ThreadLocalInteger num ThreadLocalInteger
? ? ? ? ? ? ? ? initialValue
? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ? getNextNum
? ? ? ? ? ? ? ? num.num.
? ? ? ? ? ? ? ? num.
? ? ? ?
? ? ? ?
? ? ? ? Test
? ? ? ? ? ? ? ? ThreadLocalDemo tld
?
? ? ? ? ? ? ? ? TestThreadLocalDemo tld
? ? ? ? ? ? ? ? ? ? ? ? . tld
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? run
? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? iii
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .. .. tld.
? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ? main args
? ? ? ? ? ? ? ? ThreadLocalDemo tld ThreadLocalDemo
? ? ? ? ? ? ? ? Test test1 Testtld
? ? ? ? ? ? ? ? Test test2 Testtld
? ? ? ? ? ? ? ? test1.
? ? ? ? ? ? ? ? test2.
? ? ? ?
?
二、队列
?
、队列与线程池的交互
?
? ? ? ? 如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。
? ?如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程。
? ?如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
? ?
、BlockingQueue的选择
?
? ? ? ? SynchronousQueue:首先SynchronousQueue是无界的,也就是说他存数任务的能力是没有限制的,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。
什么意思?如果你的任务A1,A2有内部关联,A1需要先运行,那么先提交A1,再提交A2,当使用SynchronousQueue我们可以保证,A1必定先被执行,在A1么有被执行前,A2不可能添加入queue中。
?
? ? ? ? LinkedBlockingQueue:无界队列。corePoolSize大小的线程数会一直运行,忙完当前的,就从队列中拿任务开始运行。所以要防止任务疯长,比如任务运行的实行比较长,而添加任务的速度远远超过处理任务的时间,而且还不断增加,不一会儿就爆了。
?
? ? ? ? ArrayBlockingQueue:有界队列。JDK不推荐使用。
?
、RejectedExecutionHandler的四种策略
?
? ? ? ? CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
? ? ? ? ? ? ? ? ? rejectedExecution r,ThreadPoolExecutor e
? ? ? ? ? ? e.
? ? ? ? ? ? ? ?r.
? ? ? ? ? ?
? ? ? ?
? ? ? ?
? ?AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionException。
? ? ? ? ? ? ? ? rejectedExecution r,ThreadPoolExecutor e
? ? ? ? ? ? RejectedExecutionException
? ? ? ?
? ? ? ?
? ?DiscardPolicy:不能执行的任务将被删除,这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。
? ?
? ?DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)
? ? ? ? ? ? ? ? rejectedExecution r,ThreadPoolExecutor e
? ? ? ? ? ? e.
? ? ? ? ? ? ? ?e..
? ? ? ? ? ? ? ?e.r
? ? ? ? ? ?
? ? ? ?
?
三、并发编程
?
Java 中的java..包下面有很多工具类。
?
、CountDownLatch用于多个并发线程全部执行完
代码:
?
AThread
? ? ? ?
? ? ? ? CopyOnWriteArrayList list
? ? ? ? CountDownLatch latch
?
? ? ? ? AThreadCopyOnWriteArrayList list,CountDownLatch latch
? ? ? ? ? ? ? ? . list