-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
5818 lines (5335 loc) · 593 KB
/
search.xml
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
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>2020年尾声规划</title>
<url>/2020/08/16/2020-plan/</url>
<content><![CDATA[<p>2020年还有4个月就结束了,今年从疫情期间忙忙碌碌,时间过得飞快。想到了诸葛亮的诫子书一句话,年与时驰,意与日去,遂成枯落,多不接世,悲守穷庐,将复何及。觉得很惭愧,思想提高慢,能力提高慢,技术深度提高慢,希望制定以下计划来日益精进自我的技术。</p>
<p>经过思考以下几个点需要不断提高:</p>
<ol>
<li>体系化思考,深度思考能力(欠缺)</li>
<li>提高技术鉴赏力,品味(一般)</li>
<li>算法能力(严重短板)</li>
<li>工程,架构以及软件设计能力(一般)</li>
<li>项目管理能力(欠缺)</li>
<li>英语读写,中文读写,文档能力(欠缺)</li>
<li>面试能力,BQ,面试题 (不满意)</li>
</ol>
]]></content>
<categories>
<category>规划</category>
</categories>
<tags>
<tag>2020尾声规划</tag>
</tags>
</entry>
<entry>
<title>惊奇的工程算法简介</title>
<url>/2021/01/03/Algorithm-Engineering/</url>
<content><![CDATA[<h1 id="简介"><a href="#简介" class="headerlink" title="简介"></a>简介</h1><p>本系列主要介绍比较经典/常用的工程算法,理解这些算法非常有意义,对于程序优化有很有帮助,会发出惊奇的感慨。这里算法以工程为出发点,而非严谨意义上的数学证明算法。</p>
<h1 id="工程算法分类"><a href="#工程算法分类" class="headerlink" title="工程算法分类"></a>工程算法分类</h1><p>算法主要分为以下几类:</p>
<h2 id="单机系统"><a href="#单机系统" class="headerlink" title="单机系统"></a>单机系统</h2><ol>
<li>Membership: HashSet.constains, BitSet.get, Bloom Filter,Counting Bloom Filter</li>
<li>Cardinality: HashSet.size, BitSet.cardinality, Linear counter,Log Log,HyperLogLog</li>
<li>Frequency: HashMap.put, HashMultiset.count, Count Sketch,Count-Min Sketch</li>
<li>Hash算法和一致性Hash算法</li>
<li>时间轮算法:Hashed and Hierarchical Timing Wheel</li>
<li>唯一ID生成器:snowflake,</li>
<li>负载均衡算法:Round robin,Weighted round robin</li>
<li>限流算法:Token Bucket,Leaky Bucket,Fixed Window,Sliding Log,Sliding Window</li>
<li>缓存淘汰算法:LFU,LRU,FIFO</li>
</ol>
<h2 id="分布式系统"><a href="#分布式系统" class="headerlink" title="分布式系统"></a>分布式系统</h2><ol>
<li>共识算法:ZAB,Paxos,Raft,Viewstamped Replication,PBFT,Atomic Broadcast</li>
<li>选举算法:Bully,Ring</li>
<li>快照算法:Chandy Lamport,Lightweight Asynchronous Snapshots</li>
</ol>
]]></content>
<categories>
<category>算法</category>
<category>工程算法</category>
</categories>
<tags>
<tag>algorithm</tag>
</tags>
</entry>
<entry>
<title>CompletionService设计与实现</title>
<url>/2020/11/13/CompletionService-Design-And-Implementation/</url>
<content><![CDATA[<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p>使用ExecutorService时候,我们只是向其中不断提交任务,然后通过Future获取get任务结果,但是有时候get需要等待,虽然可行,但是比较繁琐,可以有更好的方式,比如CompletionService实现了将完成的任务放在完成队列中,使得获取任务结果可以向队列一样通过take和poll任务结果,这样比ExecutorService更加方便。CompletionService通过ExecutorCompletionService实现,这两个实现均非常简单。</p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><img src="/images/CompletionService.png" style="zoom:60%;" />
<p>通过类图,可以看出CompletionService并没有继承ExecutorService,而是内部包含了AbstractExecutorService类,CompletionService和ExecutorService比较类似地方是都有submit方法,而CompletionService获取执行结果是根据take和poll的方式去获取。</p>
<h1 id="API"><a href="#API" class="headerlink" title="API"></a>API</h1><h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1><h2 id="任务结果排队的QueueingFuture"><a href="#任务结果排队的QueueingFuture" class="headerlink" title="任务结果排队的QueueingFuture"></a>任务结果排队的QueueingFuture</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//全部final,说明在构造函数里面会创建好这些实例变量</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> Executor executor;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> AbstractExecutorService aes;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue<Future<V>> completionQueue;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * FutureTask extension to enqueue upon completion.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">QueueingFuture</span><<span class="title">V</span>> <span class="keyword">extends</span> <span class="title">FutureTask</span><<span class="title">Void</span>> </span>{</span><br><span class="line"> QueueingFuture(RunnableFuture<V> task,</span><br><span class="line"> BlockingQueue<Future<V>> completionQueue) {</span><br><span class="line"> <span class="keyword">super</span>(task, <span class="keyword">null</span>);</span><br><span class="line"> <span class="keyword">this</span>.task = task;</span><br><span class="line"> <span class="keyword">this</span>.completionQueue = completionQueue;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Future<V> task;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue<Future<V>> completionQueue;</span><br><span class="line"> <span class="comment">//FutureTask的钩子方法,用户任务结束时候的扩展,QueueingFuture继承了该方法,并将结束的</span></span><br><span class="line"> <span class="comment">//任务放入阻塞队列</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span> </span>{ completionQueue.add(task); }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ExecutorCompletionService</span><span class="params">(Executor executor)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (executor == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="keyword">this</span>.executor = executor;</span><br><span class="line"> <span class="keyword">this</span>.aes = (executor <span class="keyword">instanceof</span> AbstractExecutorService) ?</span><br><span class="line"> (AbstractExecutorService) executor : <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">this</span>.completionQueue = <span class="keyword">new</span> LinkedBlockingQueue<Future<V>>();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ExecutorCompletionService</span><span class="params">(Executor executor,</span></span></span><br><span class="line"><span class="function"><span class="params"> BlockingQueue<Future<V>> completionQueue)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (executor == <span class="keyword">null</span> || completionQueue == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="keyword">this</span>.executor = executor;</span><br><span class="line"> <span class="keyword">this</span>.aes = (executor <span class="keyword">instanceof</span> AbstractExecutorService) ?</span><br><span class="line"> (AbstractExecutorService) executor : <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">this</span>.completionQueue = completionQueue;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="提交任务submit"><a href="#提交任务submit" class="headerlink" title="提交任务submit"></a>提交任务submit</h2><p>提交任务和AbstractExecutorService类似,只不过提交的是返回结果排队的QueueingFuture.</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Future<V> <span class="title">submit</span><span class="params">(Callable<V> task)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture<V> f = newTaskFor(task);</span><br><span class="line"> executor.execute(<span class="keyword">new</span> QueueingFuture<V>(f, completionQueue));</span><br><span class="line"> <span class="keyword">return</span> f;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future<V> <span class="title">submit</span><span class="params">(Runnable task, V result)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture<V> f = newTaskFor(task, result);</span><br><span class="line"> executor.execute(<span class="keyword">new</span> QueueingFuture<V>(f, completionQueue));</span><br><span class="line"> <span class="keyword">return</span> f;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="从阻塞队列获取任务结果take,poll"><a href="#从阻塞队列获取任务结果take,poll" class="headerlink" title="从阻塞队列获取任务结果take,poll"></a>从阻塞队列获取任务结果take,poll</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//如果没有完成的任务会阻塞等待</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future<V> <span class="title">take</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">return</span> completionQueue.take();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//如果没有完成的任务返回null</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future<V> <span class="title">poll</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> completionQueue.poll();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//带有超时的获取任务结果,任务超时,则被中断</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Future<V> <span class="title">poll</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">return</span> completionQueue.poll(timeout, unit);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="实战"><a href="#实战" class="headerlink" title="实战"></a>实战</h1>]]></content>
<categories>
<category>JDK源码</category>
<category>Java并发框架</category>
</categories>
<tags>
<tag>java.util.concurrent</tag>
</tags>
</entry>
<entry>
<title>动态代理Proxy的设计与实现</title>
<url>/2020/11/21/Dynamic-Proxy/</url>
<content><![CDATA[<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p>Java动态代理实现是基于反射和动态生成Class文件的技术,Proxy,InvocationHandler,Method是三个核心类,Proxy是代理类的入口,用来获取代理类,创建代理实例,获取InvocationHandler,判断某个类是否是代理类,InvocationHandler是方法调用的拦截,invoke方法是接口唯一方法,Method是反射的方法,用来完成方法调用。</p>
<h1 id="案例看行为"><a href="#案例看行为" class="headerlink" title="案例看行为"></a>案例看行为</h1><p>我们先通过一个Person案例来看动态代理生成的代理类的模样。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//公共接口</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Person</span> </span>{</span><br><span class="line"> <span class="function">String <span class="title">getName</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span></span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//公共接口实现</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">PersonImpl</span> <span class="keyword">implements</span> <span class="title">Person</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>{ <span class="keyword">return</span> name; }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>{ <span class="keyword">this</span>.name = name; }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//调用处理器</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyInvocationHandler</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Person person;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">MyInvocationHandler</span><span class="params">(Person person)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.person = person;</span><br><span class="line"> }</span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>{</span><br><span class="line"> System.out.println(<span class="string">"before invoke"</span>);</span><br><span class="line"> Object invoke = method.invoke(person, args);</span><br><span class="line"> System.out.println(<span class="string">"after invoke"</span>);</span><br><span class="line"> <span class="keyword">return</span> invoke;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PersonProxy</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> <span class="comment">//生成动态代理类文件</span></span><br><span class="line"> System.getProperties().put(<span class="string">"jdk.proxy.ProxyGenerator.saveGeneratedFiles"</span>, <span class="string">"true"</span>);</span><br><span class="line"> <span class="comment">//通过Proxy.newProxyInstance创建动态代理类,并且转型成Person。Person本质是$Proxy0代理类。</span></span><br><span class="line"> Person person = (Person) Proxy.newProxyInstance(</span><br><span class="line"> Person<span class="class">.<span class="keyword">class</span>.<span class="title">getClassLoader</span>(), //类加载器</span></span><br><span class="line"> new Class[]{Person.class}, //接口</span><br><span class="line"> <span class="keyword">new</span> MyInvocationHandler(<span class="keyword">new</span> PersonImpl()) <span class="comment">//调用处理器</span></span><br><span class="line"> );</span><br><span class="line"> person.setName(<span class="string">"lili"</span>);<span class="comment">//动态代理类调用setName</span></span><br><span class="line"> System.out.println(person.getName());<span class="comment">//动态代理类调用getName</span></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我们可以看下生成的$Proxy0类,该类是真正的代理类。分析可知:该类是final说明不可被子类化,并且继承Proxy的构造函数,这也就是Proxy构造函数为什么是protect的原因,同时实现了Person接口,说明代理类可以转型为Person,从而可以调用Person方法产生代理行为,在方法层面,所有的方法都是final方法。在$Proxy0 m0,m1,m2始终为hashCode,equals,toString方法,而m3,m4 …… 为目标接口的方法,我们可以看到当$Proxy0调用setName时候,实质调用了h.invoke(this, m4, new Object[]{var1})方法,也就是我们自定义的MyInvocationHandler#invoke方法,从而产生代理行为。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> $<span class="title">Proxy0</span> <span class="keyword">extends</span> <span class="title">Proxy</span> <span class="keyword">implements</span> <span class="title">Person</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Method m0;<span class="comment">//hashCode</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Method m1;<span class="comment">//equals</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Method m2;<span class="comment">//toString</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Method m3;<span class="comment">//getName</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Method m4;<span class="comment">//setName</span></span><br><span class="line"> <span class="comment">//继承Proxy构造方法</span></span><br><span class="line"> <span class="keyword">public</span> $Proxy0(InvocationHandler param1) {</span><br><span class="line"> <span class="keyword">super</span>(var1);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Integer)<span class="keyword">super</span>.h.invoke(<span class="keyword">this</span>, m0, (Object[])<span class="keyword">null</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object var1)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (Boolean)<span class="keyword">super</span>.h.invoke(<span class="keyword">this</span>, m1, <span class="keyword">new</span> Object[]{var1});</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (String)<span class="keyword">super</span>.h.invoke(<span class="keyword">this</span>, m2, (Object[])<span class="keyword">null</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (String)<span class="keyword">super</span>.h.invoke(<span class="keyword">this</span>, m3, (Object[])<span class="keyword">null</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String var1)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>.h.invoke(<span class="keyword">this</span>, m4, <span class="keyword">new</span> Object[]{var1});</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//获取到method对象</span></span><br><span class="line"> <span class="keyword">static</span> { </span><br><span class="line"> m0 = Class.forName(<span class="string">"java.lang.Object"</span>).getMethod(<span class="string">"hashCode"</span>);</span><br><span class="line"> m1 = Class.forName(<span class="string">"java.lang.Object"</span>).getMethod(<span class="string">"equals"</span>, Class.forName(<span class="string">"java.lang.Object"</span>));</span><br><span class="line"> m2 = Class.forName(<span class="string">"java.lang.Object"</span>).getMethod(<span class="string">"toString"</span>);</span><br><span class="line"> m3 = Class.forName(<span class="string">"org.lili.jdk.lang.reflect.Person"</span>).getMethod(<span class="string">"getName"</span>);</span><br><span class="line"> m4 = Class.forName(<span class="string">"org.lili.jdk.lang.reflect.Person"</span>).getMethod(<span class="string">"setName"</span>, Class.forName(<span class="string">"java.lang.String"</span>));</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><p>通过案例,我们可以勾画出动态代理的结构</p>
<p><img src="/images/Proxy.png" alt=""></p>
<p>$Proxy0作为Proxy,Person作为Subject,而PersonImpl作为RealSubject是和设计模式代理模式一模一样。</p>
<p><img src="/images/GOF-Proxy.png" alt=""></p>
<h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1>]]></content>
<categories>
<category>JDK源码</category>
<category>Java核心</category>
</categories>
<tags>
<tag>java.lang.reflect</tag>
<tag>Java-Core</tag>
</tags>
</entry>
<entry>
<title>Java集合框架(3)-HashMap设计与实现</title>
<url>/2020/11/14/HashMap-Design-And-Implementation/</url>
<content><![CDATA[<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p> HashMap在面试中被频繁问到,从我入行(2015年)问到了现在,我一直思考,就一个Map的实现有什么好问的,曾经对问我HashMap的面试官忍不住吐槽:难道你们没别的问的了?但是不可避免这个问题的出现频率,因为这体现你的“Java基础”。于是为了回答好这个问题,我从网上看了很多资料,从此面试时候不在被HashMap所难倒,但是我好像除了应付面试,从HashMap并没有学到什么东西,有一天,我下定决心,真正地重新学习HashMap的实现,从此好像发现了宝藏一样,对我的代码水平提高也很有帮助,从最初的迷惑,不屑,到现在对HashMap的喜欢,也是见证自己对技术从实用主义到真正渴望理解的一个提高,也是从浮躁到沉淀的一个见证。所以这篇文章总结了自己对HashMap的设计与实现的认识。</p>
<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p> HashMap作为最经典的Map接口实现,内部实现细节非常复杂,但是设计本身实现却是一致的,没有脱离Map接口和整个集合框架带给我们的抽象。<strong>Node</strong>和<strong>TreeNode</strong>作为<strong>Map.Entry</strong>的实现类,代表了<strong>HashMap</strong>内部的不同类型<strong>Entry</strong>, <strong>KeySet,Values,EntrySet</strong>分别作为Map的key,value,Entry的视图. 而<strong>HashIterator,KeyInterator,ValueIterator,EntryIterator</strong>分别作为KeySet,Values,EntrySet的迭代器实现,用于遍历Map,而<strong>HashMapSpliterator,KeySpliterator,ValueSpliterator,EntrySpliterator</strong>作为HashMap支持流式编程的Spliterator的实现。虽然看着类很多,但是抽象围绕<strong>迭代器,分割器,视图,Entry</strong>去实现的。由此可以得知,支持HashMap的实现由这些基本抽象组成。在接下来结构中,可以体现这些细节。</p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><p>HashMap的内部结构较多,但是并不难以理解。</p>
<p><img src="/images/HashMap.png" alt=""></p>
<h1 id="HashMap的API"><a href="#HashMap的API" class="headerlink" title="HashMap的API"></a>HashMap的API</h1><h1 id="HashMap的实现"><a href="#HashMap的实现" class="headerlink" title="HashMap的实现"></a>HashMap的实现</h1><h1 id="启示"><a href="#启示" class="headerlink" title="启示"></a>启示</h1>]]></content>
<categories>
<category>JDK源码</category>
<category>Java集合框架</category>
</categories>
<tags>
<tag>java.util.*</tag>
<tag>java collection framework</tag>
</tags>
</entry>
<entry>
<title>AQS(AbstractQueuedSynchronizer) API分析</title>
<url>/2020/11/08/AQS-api-explain/</url>
<content><![CDATA[<h1 id="AQS概述"><a href="#AQS概述" class="headerlink" title="AQS概述"></a>AQS概述</h1><p>AbstractQueuedSynchronizer是Java用于替代 <strong>Synchronized+内置等待通知(wait/notify)+内置条件队列</strong>的抽象队列同步器,该同步器管理锁,条件变量(状态变量),条件谓词三元关系,从而技术上实现了锁,条件队列,等待通知,阻塞等同步语义。在JUC中广泛使用,其中有ReentrantLock,ReentrantReadWriteLock,Semaphore,CountDownLatch,ThreadPoolExecutor#Worker,而这些基石又组成了部分并发集合,可见其重要性,该同步器比内置的伸缩性和容错性更好,并且功能比内置的更加强大,文章主要分析AQS API设计,以及如何使用该类实现自定义的锁和同步器。</p>
<h1 id="AQS-API一览"><a href="#AQS-API一览" class="headerlink" title="AQS API一览"></a>AQS API一览</h1><p>AQS API主要分为以下几类,1 public final 方法 ,用于实现类调用以完成获取锁/释放锁的操作,2 protected final方法,用于实现类获取,原子修改状态变量, 3 protected方法,用于实现类覆写,并且协同 protected final从而真正完成等待/通知的同步语义, 4 私有方法,作为内部实现,并非API,故不分析私有方法。</p>
<h2 id="public-final-方法"><a href="#public-final-方法" class="headerlink" title="public final 方法"></a>public final 方法</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))</span><br><span class="line"> selfInterrupt();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">线程以独占方式用于获取锁,如果获取到,tryAcquire(arg)将会实现状态修改,否则线程将会入队,被阻塞。</span><br><span class="line"> </span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquireInterruptibly</span><span class="params">(<span class="keyword">int</span> arg)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">if</span> (Thread.interrupted())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InterruptedException();</span><br><span class="line"> <span class="keyword">if</span> (!tryAcquire(arg))</span><br><span class="line"> doAcquireInterruptibly(arg);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">线程以响应中断的方式获取锁。</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquireShared</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (tryAcquireShared(arg) < <span class="number">0</span>)</span><br><span class="line"> doAcquireShared(arg);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">小于<span class="number">0</span>,共享获取失败,则线程入队阻塞。</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">acquireSharedInterruptibly</span><span class="params">(<span class="keyword">int</span> arg)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">if</span> (Thread.interrupted())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InterruptedException();</span><br><span class="line"> <span class="keyword">if</span> (tryAcquireShared(arg) < <span class="number">0</span>)</span><br><span class="line"> doAcquireSharedInterruptibly(arg);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">以可响应中断的方式共享获取。</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">release</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (tryRelease(arg)) {</span><br><span class="line"> Node h = head;</span><br><span class="line"> <span class="keyword">if</span> (h != <span class="keyword">null</span> && h.waitStatus != <span class="number">0</span>)</span><br><span class="line"> unparkSuccessor(h);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">以独占方式释放,释放成功将unparkSuccessor.</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">releaseShared</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (tryReleaseShared(arg)) {</span><br><span class="line"> doReleaseShared();</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">以共享方式释放。</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> Collection<Thread> <span class="title">getWaitingThreads</span><span class="params">(ConditionObject condition)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getWaitQueueLength</span><span class="params">(ConditionObject condition)</span> </span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">hasContended</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquireNanos</span><span class="params">(<span class="keyword">int</span> arg, <span class="keyword">long</span> nanosTimeout)</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquireSharedNanos</span><span class="params">(<span class="keyword">int</span> arg, <span class="keyword">long</span> nanosTimeout)</span></span></span><br></pre></td></tr></table></figure>
<p>基本获取/释放方法包含了以<strong>tryXXX</strong>开头的方法,这些方法都需要实现类自己来定义,通过对tryXXX方法覆写,从而实现自定义的获取释放操作。</p>
<h2 id="protect方法"><a href="#protect方法" class="headerlink" title="protect方法"></a>protect方法</h2><p>tryAcquire, tryRelease,isHeldExclusively是实现<strong>独占语义</strong>需要覆写的方法,而tryAcquireShared,tryReleaseShared是实现<strong>共享语义</strong>需要覆写的方法,其内部实现均为throw new UnsupportedOperationException();简单而言,就是通过状态变量的修改来决定获取锁成功,获取锁失败被阻塞,释放锁失败,释放锁成功唤醒被阻塞线程的简单语义。本质是Synchronized+wait+notify+条件队列语义的高级实现。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> arg)</span> <span class="keyword">true</span>,成功获取,<span class="keyword">false</span>,失败获取,线程将入队阻塞。</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryRelease</span><span class="params">(<span class="keyword">int</span> arg)</span> <span class="keyword">true</span>,成功释放,唤醒被阻塞的线程,<span class="keyword">false</span>,释放失败。</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isHeldExclusively</span><span class="params">()</span> <span class="keyword">true</span>,被当前线程持有,<span class="keyword">false</span>,非当前线程持有。</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> arg)</span> 负值,获取失败,线程入队被阻塞,零值,以独占方式获取,正值,以共享方式获取</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryReleaseShared</span><span class="params">(<span class="keyword">int</span> arg)</span> <span class="keyword">true</span>,使得所有在获取时候阻塞的线程恢复执行,<span class="keyword">false</span> 释放失败</span></span><br></pre></td></tr></table></figure>
<p>当理解了protect的语义后,就需要在protect中调用protect final来真正操作状态变量了。</p>
<h2 id="protect-final-方法"><a href="#protect-final-方法" class="headerlink" title="protect final 方法"></a>protect final 方法</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getState</span><span class="params">()</span> 获取状态</span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">void</span> <span class="title">setState</span><span class="params">(<span class="keyword">int</span> newState)</span> 设置状态 </span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">compareAndSetState</span><span class="params">(<span class="keyword">int</span> expect, <span class="keyword">int</span> update)</span> 原子更新状态</span></span><br></pre></td></tr></table></figure>
<h1 id="AQS使用实战"><a href="#AQS使用实战" class="headerlink" title="AQS使用实战"></a>AQS使用实战</h1><p>当我们实现一个锁或者同步器时候,最重要的思考是你的状态变量是什么?条件谓词是什么?状态变量和条件谓词之间的转换关系?首先应该清晰理解你需要被AQS管理的状态,其次是这些状态之间转换。可以说,状态变量及其转换带来的同步语义是最重要的设计思考。我们先从官方API实例Mutex 和BooleanLatch说起,然后深入JDK例子CountDownLatch,ReentrantLock,Semaphore,最后总结实现AQS的模板。</p>
<h2 id="Mutex锁实现"><a href="#Mutex锁实现" class="headerlink" title="Mutex锁实现"></a>Mutex锁实现</h2><p>互斥锁是最经典的锁,同一时刻只能有一个线程获取锁,并且不可重入。我们可以以0为释放,1为获取作为状态,当获取锁时候,将状态从0置为1,新的线程再次获取时候,将被阻塞。当释放锁时候,将状态从1置为0,并且唤醒之前被阻塞的线程。</p>
<p>1 状态是什么? 是否获取锁</p>
<p>2 状态转换? 获取锁时候,状态从0修改为1,释放锁时候,状态从1修改为0.</p>
<p>3 实现细节? 实现Lock接口,内部静态final类实现Sync,用于实现AQS的protected方法 ,公共方法调用AQS的public final方法。</p>
<p>我们来看实现:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Mutex</span> <span class="keyword">implements</span> <span class="title">Lock</span>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 内部助手类,桥接模式</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Sync</span> <span class="keyword">extends</span> <span class="title">AbstractQueuedSynchronizer</span> </span>{</span><br><span class="line"> <span class="comment">// Reports whether in locked state</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isHeldExclusively</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//状态为1,认为是当前线程独占</span></span><br><span class="line"> <span class="keyword">return</span> getState() == <span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Acquires the lock if state is zero</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">assert</span> acquires == <span class="number">1</span>; <span class="comment">// Otherwise unused</span></span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>)) {</span><br><span class="line"> <span class="comment">//获取锁时候将状态从0原子更新到1,并且设置当前获取者是自己,获取成功返回true</span></span><br><span class="line"> setExclusiveOwnerThread(Thread.currentThread());</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Releases the lock by setting state to zero</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryRelease</span><span class="params">(<span class="keyword">int</span> releases)</span> </span>{</span><br><span class="line"> <span class="keyword">assert</span> releases == <span class="number">1</span>; <span class="comment">// Otherwise unused</span></span><br><span class="line"> <span class="comment">//释放锁时候状态不能为0</span></span><br><span class="line"> <span class="keyword">if</span> (getState() == <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> IllegalMonitorStateException();</span><br><span class="line"> setExclusiveOwnerThread(<span class="keyword">null</span>);</span><br><span class="line"> <span class="comment">//状态更新为0</span></span><br><span class="line"> setState(<span class="number">0</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="comment">// Provides a Condition</span></span><br><span class="line"> <span class="function">Condition <span class="title">newCondition</span><span class="params">()</span> </span>{ <span class="keyword">return</span> <span class="keyword">new</span> ConditionObject(); }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Deserializes properly</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(ObjectInputStream s)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> IOException, ClassNotFoundException </span>{</span><br><span class="line"> s.defaultReadObject();</span><br><span class="line"> setState(<span class="number">0</span>); <span class="comment">// reset to unlocked state</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// The sync object does all the hard work. We just forward to it.</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Sync sync = <span class="keyword">new</span> Sync();</span><br><span class="line"> <span class="comment">//实现lock接口,并且公共方法调用AQS的public final方法</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{ sync.acquire(<span class="number">1</span>); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryLock</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.tryAcquire(<span class="number">1</span>); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unlock</span><span class="params">()</span> </span>{ sync.release(<span class="number">1</span>); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Condition <span class="title">newCondition</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.newCondition(); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isLocked</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.isHeldExclusively(); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasQueuedThreads</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.hasQueuedThreads(); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lockInterruptibly</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> sync.acquireInterruptibly(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryLock</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">return</span> sync.tryAcquireNanos(<span class="number">1</span>, unit.toNanos(timeout));</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h2 id="BooleanLatch-同步器实现"><a href="#BooleanLatch-同步器实现" class="headerlink" title="BooleanLatch 同步器实现"></a>BooleanLatch 同步器实现</h2><p>布尔Latch,可以来回切换,只允许一个信号被唤醒,但是是共享获取的,所以使用tryAcquireShared,tryReleaseShared.</p>
<p>1 状态是什么?获取成功或者失败</p>
<p>2 状态转换? 成功1,失败-1</p>
<p>3 实现细节? </p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">BooleanLatch</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Sync</span> <span class="keyword">extends</span> <span class="title">AbstractQueuedSynchronizer</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isSignalled</span><span class="params">()</span> </span>{ <span class="keyword">return</span> getState() != <span class="number">0</span>; }</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> ignore)</span> </span>{</span><br><span class="line"> <span class="comment">//1 共享获取成功 -1 共享获取失败,线程阻塞</span></span><br><span class="line"> <span class="keyword">return</span> isSignalled() ? <span class="number">1</span> : -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryReleaseShared</span><span class="params">(<span class="keyword">int</span> ignore)</span> </span>{</span><br><span class="line"> <span class="comment">//释放锁时候,将状态设置为1,并且唤醒被阻塞的线程</span></span><br><span class="line"> setState(<span class="number">1</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Sync sync = <span class="keyword">new</span> Sync();</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isSignalled</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.isSignalled(); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">signal</span><span class="params">()</span> </span>{ sync.releaseShared(<span class="number">1</span>); }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">await</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> sync.acquireSharedInterruptibly(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h2 id="CountDownLatch同步器实现"><a href="#CountDownLatch同步器实现" class="headerlink" title="CountDownLatch同步器实现"></a>CountDownLatch同步器实现</h2><p>1 状态是什么? 当前计数值</p>
<p>2 状态转换?每次减少一个计数值,直到0,才进行唤醒,当计数器大于0的时候,一直等待计数器降为0</p>
<p>3 实现细节?共享获取,</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//构造函数初始化内部同步器的计数值</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">CountDownLatch</span><span class="params">(<span class="keyword">int</span> count)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (count < <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"count < 0"</span>);</span><br><span class="line"> <span class="keyword">this</span>.sync = <span class="keyword">new</span> Sync(count);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//sync的实现</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Sync</span> <span class="keyword">extends</span> <span class="title">AbstractQueuedSynchronizer</span> </span>{</span><br><span class="line"></span><br><span class="line"> Sync(<span class="keyword">int</span> count) {</span><br><span class="line"> <span class="comment">//初始化状态设置计数值为count</span></span><br><span class="line"> setState(count);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">getCount</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getState();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//共享获取,状态为0的时候,获取成功,不为0的时候,获取失败,被阻塞</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (getState() == <span class="number">0</span>) ? <span class="number">1</span> : -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//每次countDown时候,在for循环中不断减少初始化计数值,当减少到0的时候,释放成功,将会唤醒等待线程,当已经成为0的时候</span></span><br><span class="line"> <span class="comment">//将一直释放失败,所以CountDownLatch只能用一次。</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryReleaseShared</span><span class="params">(<span class="keyword">int</span> releases)</span> </span>{</span><br><span class="line"> <span class="comment">// Decrement count; signal when transition to zero</span></span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">int</span> c = getState();</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">int</span> nextc = c-<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(c, nextc))</span><br><span class="line"> <span class="comment">//降低到0的那一次,返回true,唤醒await的线程</span></span><br><span class="line"> <span class="keyword">return</span> nextc == <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公共API实现</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">await</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> sync.acquireSharedInterruptibly(<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">countDown</span><span class="params">()</span> </span>{</span><br><span class="line"> sync.releaseShared(<span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>在EffectiveJava3的item17中有句话点评到:构造器应该创建完全初始化的对象,并且建立起所有约束关系。CountDownLatch是可变的,但是它的状态被刻意设计的非常小,比如创建一个实例,只能用一次,一旦定时器的计数达到0,就不能再用了。</p>
<h2 id="ReentrantLock锁实现"><a href="#ReentrantLock锁实现" class="headerlink" title="ReentrantLock锁实现"></a>ReentrantLock锁实现</h2><p>1 状态是什么?获取锁操作次数</p>
<p>2 状态转换是什么?同一个线程多次获取锁,累加锁操作次数,对应的多次释放锁,减少锁操作次数</p>
<p>3 实现细节?实现Lock接口,独占锁</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//抽象同步器,设计为静态类,作为公平同步器和非公平同步器的父类</span></span><br><span class="line"><span class="keyword">abstract</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Sync</span> <span class="keyword">extends</span> <span class="title">AbstractQueuedSynchronizer</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = -<span class="number">5179523762034025860L</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Performs non-fair tryLock. tryAcquire is implemented in</span></span><br><span class="line"><span class="comment"> * subclasses, but both need nonfair try for trylock method.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">nonfairTryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">final</span> Thread current = Thread.currentThread();</span><br><span class="line"> <span class="keyword">int</span> c = getState();</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, acquires)) {</span><br><span class="line"> setExclusiveOwnerThread(current);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) {</span><br><span class="line"> <span class="keyword">int</span> nextc = c + acquires;</span><br><span class="line"> <span class="keyword">if</span> (nextc < <span class="number">0</span>) <span class="comment">// overflow</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Maximum lock count exceeded"</span>);</span><br><span class="line"> setState(nextc);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryRelease</span><span class="params">(<span class="keyword">int</span> releases)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> c = getState() - releases;</span><br><span class="line"> <span class="keyword">if</span> (Thread.currentThread() != getExclusiveOwnerThread())</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalMonitorStateException();</span><br><span class="line"> <span class="keyword">boolean</span> free = <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>) {</span><br><span class="line"> free = <span class="keyword">true</span>;</span><br><span class="line"> setExclusiveOwnerThread(<span class="keyword">null</span>);</span><br><span class="line"> }</span><br><span class="line"> setState(c);</span><br><span class="line"> <span class="keyword">return</span> free;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">isHeldExclusively</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// While we must in general read state before owner,</span></span><br><span class="line"> <span class="comment">// we don't need to do so to check if current thread is owner</span></span><br><span class="line"> <span class="keyword">return</span> getExclusiveOwnerThread() == Thread.currentThread();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> ConditionObject <span class="title">newCondition</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ConditionObject();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> Thread <span class="title">getOwner</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getState() == <span class="number">0</span> ? <span class="keyword">null</span> : getExclusiveOwnerThread();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getHoldCount</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> isHeldExclusively() ? getState() : <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">isLocked</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getState() != <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公平同步器,静态final类</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">FairSync</span> <span class="keyword">extends</span> <span class="title">Sync</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{acquire(<span class="number">1</span>);}</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">final</span> Thread current = Thread.currentThread();</span><br><span class="line"> <span class="keyword">int</span> c = getState();</span><br><span class="line"> <span class="keyword">if</span> (c == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//第一次获取,判断如果没有后继者,将锁操作次数修改为acquires,并且设置自己是锁的拥有者,</span></span><br><span class="line"> <span class="comment">//setExclusiveOwnerThread是中的AbstractOwnableSynchronizer方法</span></span><br><span class="line"> <span class="keyword">if</span> (!hasQueuedPredecessors() && compareAndSetState(<span class="number">0</span>, acquires)) {</span><br><span class="line"> setExclusiveOwnerThread(current);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//第二次获取,如果还是自己,则将锁获取次数累加,并且修改状态为锁的获取次数,这里也是可重入的实现,当超过</span></span><br><span class="line"> <span class="comment">//锁最大可获取次数,则抛出Error,注意Error是非受检异常</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (current == getExclusiveOwnerThread()) {</span><br><span class="line"> <span class="keyword">int</span> nextc = c + acquires;</span><br><span class="line"> <span class="keyword">if</span> (nextc < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Maximum lock count exceeded"</span>);</span><br><span class="line"> setState(nextc);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//非公平同步器,静态final类</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">NonfairSync</span> <span class="keyword">extends</span> <span class="title">Sync</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">7316153563782823691L</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Performs lock. Try immediate barge, backing up to normal</span></span><br><span class="line"><span class="comment"> * acquire on failure.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(<span class="number">0</span>, <span class="number">1</span>))</span><br><span class="line"> setExclusiveOwnerThread(Thread.currentThread());</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> acquire(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> nonfairTryAcquire(acquires);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公有API</span></span><br><span class="line"><span class="comment">//构造器</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//默认非公平</span></span><br><span class="line"> sync = <span class="keyword">new</span> NonfairSync();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ReentrantLock</span><span class="params">(<span class="keyword">boolean</span> fair)</span> </span>{</span><br><span class="line"> sync = fair ? <span class="keyword">new</span> FairSync() : <span class="keyword">new</span> NonfairSync();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lock</span><span class="params">()</span> </span>{sync.lock();}</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">lockInterruptibly</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{sync.acquireInterruptibly(<span class="number">1</span>);}</span><br><span class="line"><span class="function"><span class="keyword">public</span> Condition <span class="title">newCondition</span><span class="params">()</span> </span>{ <span class="keyword">return</span> sync.newCondition();}</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">tryLock</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//tryLock时候,无论公平锁还是非公平锁,都是非公平获取</span></span><br><span class="line"> <span class="keyword">return</span> sync.nonfairTryAcquire(<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">unlock</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//减少一次锁获取次数</span></span><br><span class="line"> sync.release(<span class="number">1</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>由此我们可以看到,可重入锁的最大次数是int最大值,也就是2147483647 ,同一个线程最大可以递归获取锁21亿次。</p>
<h2 id="Semaphore同步器实现"><a href="#Semaphore同步器实现" class="headerlink" title="Semaphore同步器实现"></a>Semaphore同步器实现</h2><p>1 状态是什么?当前可用许可数量</p>
<p>2 状态切换? 每当有一个线程获取到许可时候,就将许可减1,当许可减低为0的时候,阻塞线程,直到许可大于0</p>
<p>3 实现细节?可共享获取</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Sync</span> <span class="keyword">extends</span> <span class="title">AbstractQueuedSynchronizer</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">long</span> serialVersionUID = <span class="number">1192457210091910933L</span>;</span><br><span class="line"></span><br><span class="line"> Sync(<span class="keyword">int</span> permits) {</span><br><span class="line"> setState(permits);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">int</span> <span class="title">getPermits</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getState();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">int</span> <span class="title">nonfairTryAcquireShared</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="comment">//可用许可</span></span><br><span class="line"> <span class="keyword">int</span> available = getState();</span><br><span class="line"> <span class="comment">//剩余许可</span></span><br><span class="line"> <span class="keyword">int</span> remaining = available - acquires;</span><br><span class="line"> <span class="comment">//剩余许可小于0或者将可用修改为剩余</span></span><br><span class="line"> <span class="keyword">if</span> (remaining < <span class="number">0</span> || compareAndSetState(available, remaining))</span><br><span class="line"> <span class="keyword">return</span> remaining;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">final</span> <span class="keyword">boolean</span> <span class="title">tryReleaseShared</span><span class="params">(<span class="keyword">int</span> releases)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">int</span> current = getState();</span><br><span class="line"> <span class="keyword">int</span> next = current + releases;</span><br><span class="line"> <span class="keyword">if</span> (next < current) <span class="comment">// overflow</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Maximum permit count exceeded"</span>);</span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(current, next))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">reducePermits</span><span class="params">(<span class="keyword">int</span> reductions)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">int</span> current = getState();</span><br><span class="line"> <span class="keyword">int</span> next = current - reductions;</span><br><span class="line"> <span class="keyword">if</span> (next > current) <span class="comment">// underflow</span></span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> Error(<span class="string">"Permit count underflow"</span>);</span><br><span class="line"> <span class="keyword">if</span> (compareAndSetState(current, next))</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">int</span> <span class="title">drainPermits</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">int</span> current = getState();</span><br><span class="line"> <span class="keyword">if</span> (current == <span class="number">0</span> || compareAndSetState(current, <span class="number">0</span>))</span><br><span class="line"> <span class="keyword">return</span> current;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公平同步器</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">FairSync</span> <span class="keyword">extends</span> <span class="title">Sync</span> </span>{</span><br><span class="line"> FairSync(<span class="keyword">int</span> permits) {</span><br><span class="line"> <span class="keyword">super</span>(permits);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="comment">//是否有前继者,如果线程有前继者,说明已有线程被阻塞,直接返回获取失败</span></span><br><span class="line"> <span class="keyword">if</span> (hasQueuedPredecessors())</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> <span class="keyword">int</span> available = getState();</span><br><span class="line"> <span class="keyword">int</span> remaining = available - acquires;</span><br><span class="line"> <span class="comment">//剩余小于0或者可用修改为剩余,如果大于0,则获取成功,如果等于0,则独占获取,如果小于0,则获取失败</span></span><br><span class="line"> <span class="comment">//所有当剩余许可小于0的时候,也就是信号量使用完的时候,线程获取锁将被阻塞</span></span><br><span class="line"> <span class="keyword">if</span> (remaining < <span class="number">0</span> || compareAndSetState(available, remaining))</span><br><span class="line"> <span class="keyword">return</span> remaining;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//非公平同步器</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">NonfairSync</span> <span class="keyword">extends</span> <span class="title">Sync</span> </span>{</span><br><span class="line"> NonfairSync(<span class="keyword">int</span> permits) {</span><br><span class="line"> <span class="keyword">super</span>(permits);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> acquires)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> nonfairTryAcquireShared(acquires);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//公共API</span></span><br><span class="line"><span class="comment">//构造函数</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Semaphore</span><span class="params">(<span class="keyword">int</span> permits)</span> </span>{ sync = <span class="keyword">new</span> NonfairSync(permits);}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">Semaphore</span><span class="params">(<span class="keyword">int</span> permits, <span class="keyword">boolean</span> fair)</span> </span>{</span><br><span class="line"> sync = fair ? <span class="keyword">new</span> FairSync(permits) : <span class="keyword">new</span> NonfairSync(permits);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> sync.acquireSharedInterruptibly(<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">acquire</span><span class="params">(<span class="keyword">int</span> permits)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">if</span> (permits < <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> sync.acquireSharedInterruptibly(permits);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">()</span> </span>{</span><br><span class="line"> sync.releaseShared(<span class="number">1</span>);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">release</span><span class="params">(<span class="keyword">int</span> permits)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (permits < <span class="number">0</span>) <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> sync.releaseShared(permits);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我们可以看到,Semaphore是初始化N个许可,线程无需等待,然后每一个线程会消耗信号量,当消耗完时,会阻塞后面线程,而CountDownLatch是初始化N个计数器,然后线程等待,当计数器降为0的时候,唤醒初始化等待的线程,这两者有些相反的含义在里面。两种同用共享获取方式,共享释放释放。</p>
<h1 id="4-总结"><a href="#4-总结" class="headerlink" title="4 总结"></a>4 总结</h1><p>在实现锁或者同步器时候,需要思考以下几点:</p>
<p>1 状态变量以及状态变量的转换</p>
<p>2 是独占的还是共享的</p>
<p>当想明白以上两个问题时候,就可以动手实现你要的同步器的,一般是以内部静态类的方式继承AQS的protected方法,在protected方法中,调用protected final方法,然后在你要公共API中调用你的内部同步器的public final方法既可。如下实现模板:</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> MyLock implements Lock, or MySync {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//内部同步器,继承AQS的protected方法,里面调用AQS的protected final方法修改状态</span></span><br><span class="line"> innerStaticSync extends AbstractQueuedSynchronizer{</span><br><span class="line"></span><br><span class="line"> <span class="comment">//独占获取 tryAcquire,tryRelease,isHeldExclusively</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryAcquire</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{</span><br><span class="line"> getState/setState/compareAndSetState</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryRelease</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{}</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">isHeldExclusively</span><span class="params">()</span> </span>{}</span><br><span class="line"> <span class="comment">//共享获取 tryAcquireShared,tryReleaseShared</span></span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">int</span> <span class="title">tryAcquireShared</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{}</span><br><span class="line"> <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">tryReleaseShared</span><span class="params">(<span class="keyword">int</span> arg)</span> </span>{}</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//构造函数实例化</span></span><br><span class="line"> <span class="keyword">public</span> MyLock or MySync {</span><br><span class="line"> innerStaticSync = <span class="keyword">new</span> MyLock() <span class="function">or new <span class="title">MySync</span><span class="params">()</span></span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">//public api 调用AQS的public final方法</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">acquire</span><span class="params">()</span></span>{innerStaticSync.acquire();}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">release</span><span class="params">()</span></span>{innerStaticSync.release();}</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>Done!</p>
]]></content>
<categories>
<category>JDK源码</category>
<category>Java并发框架</category>
</categories>
<tags>
<tag>java.util.concurrent</tag>
</tags>
</entry>
<entry>
<title>java.lang.OutOfMemoryError内存溢出</title>
<url>/2020/08/16/OOM/</url>
<content><![CDATA[<p>对这个问题的深入理解,取决于对GC,内存本身的理解。终极问题。</p>
<p>内存,GC,</p>
<p>内存溢出指的是程序需要内存超出系统所有的内存,如果是正常情况调大jvm内存即可,如果是</p>
<p>Java内存区域分为这么几个区域</p>
<p>堆区:老年代,新生代</p>
<p>非堆:metaspace</p>
<p>FullGC之后空间不足,内存没有回收。</p>
<p>Java OOM情况有以下几种,</p>
<h3 id="java-heap-space"><a href="#java-heap-space" class="headerlink" title="java heap space"></a>java heap space</h3><p>原因:1 应用需要更多对空间 2 内存泄漏(类加载器内存泄露,ThreadLocal 不remove内存泄漏,和线程池一起使用会泄漏)</p>
<p>举例:</p>
<p>解决方案:</p>
<p>这种情况属于fullgc之后,堆空间不足,内存泄漏是内存溢出的一个原因,但是内存泄漏不一定导致内存溢出。</p>
<h3 id="GC-Overhead-limit-exceeded"><a href="#GC-Overhead-limit-exceeded" class="headerlink" title="GC Overhead limit exceeded"></a>GC Overhead limit exceeded</h3><p>频繁FullGC导致该错误</p>
<h3 id="Permgen-space"><a href="#Permgen-space" class="headerlink" title="Permgen space"></a>Permgen space</h3><p>Java7 持久代空间不足</p>
<h3 id="Metaspace"><a href="#Metaspace" class="headerlink" title="Metaspace"></a>Metaspace</h3><p>Java8</p>
<p>1 应用加载类太多了</p>
<p>2 classloader内存泄漏</p>
<p>元空间不足,java8之后才会有</p>
<h3 id="Unable-to-create-new-native-thread"><a href="#Unable-to-create-new-native-thread" class="headerlink" title="Unable to create new native thread"></a>Unable to create new native thread</h3><p>本地线程创建数量超过操作系统的线程数</p>
<h3 id="Out-of-swap-space?"><a href="#Out-of-swap-space?" class="headerlink" title="Out of swap space?"></a>Out of swap space?</h3><p>交换区</p>
<h3 id="Compressed-class-space"><a href="#Compressed-class-space" class="headerlink" title="Compressed class space"></a>Compressed class space</h3><h3 id="Requested-array-size-exceeds-VM-limit"><a href="#Requested-array-size-exceeds-VM-limit" class="headerlink" title="Requested array size exceeds VM limit"></a>Requested array size exceeds VM limit</h3><h3 id="reason-stack-trace-with-native-method"><a href="#reason-stack-trace-with-native-method" class="headerlink" title="reason stack_trace_with_native_method"></a>reason stack_trace_with_native_method</h3><h3 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h3><ol>
<li>Oracle官网 <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html#CIHHJDJE" target="_blank" rel="noopener">Understand the OutOfMemoryError Exception</a></li>
<li>Plumbr The 8 symptoms that surface <a href="https://plumbr.io/outofmemoryerror" target="_blank" rel="noopener">outofmemoryerror</a></li>
<li>Wikipedia <a href="https://en.wikipedia.org/wiki/Out_of_memory" target="_blank" rel="noopener">Out of memory</a></li>
<li>Ponnam Parhar的slide <a href="https://www.slideshare.net/PoonamBajaj5/get-rid-of-outofmemoryerror-messages" target="_blank" rel="noopener">Slides</a> <a href="https://www.youtube.com/watch?v=iixQAYnBnJw" target="_blank" rel="noopener">Video</a></li>
</ol>
]]></content>
<categories>
<category>JVM</category>
</categories>
<tags>
<tag>内存溢出</tag>
<tag>内存泄露</tag>
</tags>
</entry>
<entry>
<title>Java集合框架(1)-接口定义类型</title>
<url>/2020/11/09/JCF-HighLevel/</url>
<content><![CDATA[<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p>集合框架是任何语言的技术体现,是语言的综合使用的类库,大部分工作可以用集合完成,但是单独的看每一个集合实现类难以对集合框架产生一个宏观认识,所以需要从高层角度来看集合技术,本系列将分析集合框架的设计与实现。</p>
<p>集合设计包括<strong>接口,实现和算法</strong>三大核心功能。接口包括类型接口和迭代器接口,类型接口是List,Set,Map,Queue等接口,而迭代器接口包括顺序迭代器和分割器,实现包括骨架实现,视图实现,数据结构实现,骨架实现就是AbstractList,AbstractSet,AbstractMap,AbstractQueue等实现,视图实现比如ArrayList的SubList,HashMap的KeySet,Values和EntrySet,而数据结构实现是特定的类型实现比如List有ArrayList和LinkedList,算法主要有排序,查找,shuffle 等,这三个功能构成了集合的设计核心。</p>
<p>使用集合类型有非常多的好处:</p>
<p>1</p>
<p>2</p>
<p>3</p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><p>集合中最重要的是接口,接口定义了数据类型,抽象类实现了接口,而具体集合类实现了真正的类型。接下来会分析每种数据结构类型接口方法,根本特征以及不同类型之间的真正区别。</p>
<h3 id="基本接口"><a href="#基本接口" class="headerlink" title="基本接口"></a>基本接口</h3><img src="/images/JCF-Base.png" style="zoom:67%;" />
<p>集合的基本组成是元素,元素即对象。这些元素本身是普通对象,但是被集合框架管理起来就具有鲜明特点,如可以迭代,可以被分割,可以比较大小排序,而正是这些基础的能力构成了集合最核心的三大接口:<strong>Iterator,Spliterator,Comparator</strong>.</p>
<p><strong>Iterator</strong>提供了种不需要知道集合实现就能遍历的能力,也是经典的设计模式。</p>
<p><strong>Spliterator</strong>提供了分割集合的能力,在并行遍历中常用。</p>
<p><strong>Comparator</strong>提供了元素比较大小的能力,在排序中常用。</p>
<h3 id="Collection接口"><a href="#Collection接口" class="headerlink" title="Collection接口"></a>Collection接口</h3><p>Collection是JCF的顶级接口,该接口定义了集合的基本操作,其中分为查询,修改,块操作,基本对象操作。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//查询</span></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">size</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Object o)</span></span>;</span><br><span class="line"><span class="function">Iterator<E> <span class="title">iterator</span><span class="params">()</span></span>;</span><br><span class="line">Object[] toArray();</span><br><span class="line"><T> T[] toArray(T[] a);</span><br><span class="line"><span class="comment">//修改,在List/Set/Queue中也会重新定义这些方法,因为这些方法在这些接口中有了新的含义,异常也和Collection</span></span><br><span class="line"><span class="comment">//add接口异常也不一样,因为add对于不同接口意思不同,,如List.add只是添加元素,Set.add添加不同元素,Queue.add</span></span><br><span class="line"><span class="comment">//如果超过了Queue长度,会抛出异常。</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">remove</span><span class="params">(Object o)</span></span>;</span><br><span class="line"><span class="comment">//块操作</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">containsAll</span><span class="params">(Collection<?> c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">addAll</span><span class="params">(Collection<? extends E> c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">removeAll</span><span class="params">(Collection<?> c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">retainAll</span><span class="params">(Collection<?> c)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span></span>;</span><br><span class="line"><span class="comment">//基本对象操作</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object o)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<p>这些操作定义了Collection基本操作,也是契约。而这些子接口Set,List,Queue有些重新定义了Collection接口方法,有些则没有,因为不同接口的含义不同。比如List,Set,Queue都重新定义了add方法,但是List,Set定义size()方法,Queue却没有定义,因为我认为size方法在List和Set(cardinality)含义不同,但是Queue的size含义和Collection一样。这种<strong>父接口定义方法,在子接口重新定义方法</strong>的技巧在JCF中广泛使用。</p>
<h3 id="List接口"><a href="#List接口" class="headerlink" title="List接口"></a>List接口</h3><img src="/images/List-Impl.png" style="zoom:67%;" />
<p>List是一种Collection,但是Collection不一样,List支持index访问,所以List接口新加了关于index的方法,index是List最重要的抽象之一.同时List也把Collection中的方法重新定义了下,</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(<span class="keyword">int</span> index, E element)</span></span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">addAll</span><span class="params">(<span class="keyword">int</span> index, Collection<? extends E> c)</span></span>;</span><br><span class="line"><span class="function">E <span class="title">get</span><span class="params">(<span class="keyword">int</span> index)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">indexOf</span><span class="params">(Object o)</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">lastIndexOf</span><span class="params">(Object o)</span></span>;</span><br><span class="line"><span class="function">ListIterator<E> <span class="title">listIterator</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function">ListIterator<E> <span class="title">listIterator</span><span class="params">(<span class="keyword">int</span> index)</span></span>;</span><br><span class="line"><span class="function">E <span class="title">remove</span><span class="params">(<span class="keyword">int</span> index)</span></span>;</span><br><span class="line"><span class="function">E <span class="title">set</span><span class="params">(<span class="keyword">int</span> index, E element)</span></span>;</span><br><span class="line"><span class="function">List<E> <span class="title">subList</span><span class="params">(<span class="keyword">int</span> fromIndex, <span class="keyword">int</span> toIndex)</span></span>;</span><br></pre></td></tr></table></figure>
<h3 id="Set接口"><a href="#Set接口" class="headerlink" title="Set接口"></a>Set接口</h3><img src="/images/set-impl.jpg" style="zoom:67%;" />
<p>Set接口将Collection方法几乎全部定义了遍,因为Set具有数学意义上集合的含义,所以集合操作需要新定义一套契约,用来表达Set的不同于Collection之处。</p>
<h3 id="Queue接口"><a href="#Queue接口" class="headerlink" title="Queue接口"></a>Queue接口</h3><p><img src="/images/Queue-Impl.png" alt=""></p>
<p>Queue也是一种Collection,但是接口中并没有新加任何方法,只是把Collection接口方法重新定义了下,因为和Collection内涵不一样。但是仅仅重新定义了add方法,其他方法并没有重新定义,因为add方法在Queue满的时候会抛出异常。这和List,Set,Collection均不一样。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//入队,如果队列满抛出IllegalStateException异常</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span></span>;</span><br><span class="line"><span class="comment">//入队,如果队列满返回false</span></span><br><span class="line"><span class="function"><span class="keyword">boolean</span> <span class="title">offer</span><span class="params">(E e)</span></span>;</span><br><span class="line"><span class="comment">//出队队头元素,没有元素则抛出NoSuchElementException异常</span></span><br><span class="line"><span class="function">E <span class="title">remove</span><span class="params">()</span></span>;</span><br><span class="line"><span class="comment">//出队队头元素,没有元素则返回false</span></span><br><span class="line"><span class="function">E <span class="title">poll</span><span class="params">()</span></span>;</span><br><span class="line"><span class="comment">//查看队头元素,没有元素则抛出NoSuchElementException异常</span></span><br><span class="line"><span class="function">E <span class="title">element</span><span class="params">()</span></span>;</span><br><span class="line"><span class="comment">//查看队头元素,没有元素则返回false</span></span><br><span class="line"><span class="function">E <span class="title">peek</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<p>队列方法比较对称,add/remove,offer/poll,element/peek,这也是API对称设计的范例。</p>
<h3 id="Deque接口"><a href="#Deque接口" class="headerlink" title="Deque接口"></a>Deque接口</h3><p><img src="/images/Deque-Impl.png" alt=""></p>
<h3 id="Map接口"><a href="#Map接口" class="headerlink" title="Map接口"></a>Map接口</h3><img src="/images/Map-Impl.png" style="zoom:67%;" />
<p>Map接口里面的Map.Entry</p>
<p>map接口</p>
<p>以上便是集合框架最重要的接口和实现(不包括并发集合,并发集合将在并发中分析)了,我们接下来分析将会围绕抽象实现和具体集合类而展开</p>
<h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://docs.oracle.com/javase/tutorial/collections/" target="_blank" rel="noopener">https://docs.oracle.com/javase/tutorial/collections/</a></p>
]]></content>
<categories>
<category>JDK源码</category>
<category>Java集合框架</category>
</categories>
<tags>
<tag>java.util.*</tag>
<tag>java collection framework</tag>
</tags>
</entry>
<entry>
<title>CRUD Boy和API Caller的怪象</title>
<url>/2021/01/01/Think-CRUDBoy-APICaller/</url>
<content><![CDATA[<p>CRUD,API Caller,Copy Paste 在业界被认为很低级工作,和low的技能(更多是自黑)。Spring作者Rod Johnson曾用一个比喻来说明问题,多瘤程序员: 学会一门技术但是留下来很多伤疤。经常认为和带着这样想法工作会降低个人生产力和对工作技术的敏感度。</p>
<h1 id="CRUD-Boy"><a href="#CRUD-Boy" class="headerlink" title="CRUD Boy"></a>CRUD Boy</h1><p> CRUD指的是对存储层的增删改查和业务层的逻辑计算。毕竟业务逻辑就是存储和计算。低级之处在于程序开发仅仅是对数据库数据的事务脚本操作,但是业务系统设计,在小型项目中CRUD可以Hold住复杂度,但是当业务系统复杂起来时候,事务脚本将带来维护性和扩展性问题,此时系统的各种业务逻辑和组件将会变得非常复杂且无趣。解决这个办法在于<strong>良好的业务抽象</strong>和概念<strong>一致性的业务接口</strong>,此时CRUD将不再是事务脚本,而更类似于OOD,而随着业务演进,可能会拆分微服务,这时候如果没有从CRUD泥潭出来,新建的微服务还是会重复事务脚本的老路。而业界有更好的业务设计方法,是<strong>领域驱动设计</strong>,将业务设计和技术设计结合起来,可以借鉴其思想,有句话说的比较好DDD is OOD done right.</p>
<p> 同时CRUD代码也不是没有技术含量的,CRUD代码也需要扩展性,维护性,可读性,文档注释,可测试性,不断重构达到整洁代码的水平,而这些任意一个工程实践,都会对既有团队带来编码习惯带来改变和编程水平的提高。所以CRUD没有技术含量,是更多把CRUD当做业务需求翻译机,产品说加你就加,而不是业务需求的解释器,用技术语言来设计业务。</p>
<p> </p>
<h1 id="API-Caller"><a href="#API-Caller" class="headerlink" title="API Caller"></a>API Caller</h1><p>API Caller是只会简单用类库和调第三方接口,没有完全理解调用方。这种透明性对业务开发进度有帮助,但是对于个人技术成长却是弊大于利。比较典型的例子是你用别人封装好的Redis接口查数据,会错以为自己会Redis,用厂商提供好的mq接口开发,发送几条消息,消费几条消息就认为自己用过mq,从而在实际工作中变成了只会调用API。在Java类库中,NIO代码冗余且复杂,学习NIO API本身就是对NIO的学习,但是写完就忘,下次还要重新学习,但是下次的学习或许没有从更深概念理解NIO,而是重新学了一遍NIO API使用代码,这样比较浪费时间。</p>
<p>对于高质量的程序,绝大部分是注重API设计质量的,这不仅关系到API使用,还有API的理解性上,好的API本身就会抽象最核心的概念给开发者,模块间通信也会精心设计API。在JAVA世界中,集合框架和并发包可以说是对API契约和设计的经典案例,任何学习API设计的都可以从此开始研究,光看集合提供的接口,就能够收获非常多的概念和抽象。同时高质量API的文档也能够加深对技术的理解。当然API的实现也很重要,但是重要程度不如API本身。关于这方面可以参考:<a href="https://xiaozhiliaoo.github.io/2020/11/09/JCF-HighLevel/" target="_blank" rel="noopener">集合接口</a></p>
<p>我们以Guava Cache来分析从API中能获得什么?</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//LoadingCache的父接口Cache也包含非常多的方法,这里不做探讨。</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">LoadingCache</span><<span class="title">K</span>, <span class="title">V</span>> <span class="keyword">extends</span> <span class="title">Cache</span><<span class="title">K</span>, <span class="title">V</span>>, <span class="title">Function</span><<span class="title">K</span>, <span class="title">V</span>> </span>{ </span><br><span class="line"> <span class="function">V <span class="title">get</span><span class="params">(K key)</span> <span class="keyword">throws</span> ExecutionException</span>;</span><br><span class="line"> <span class="function">V <span class="title">getUnchecked</span><span class="params">(K key)</span></span>;</span><br><span class="line"> <span class="function">ImmutableMap<K, V> <span class="title">getAll</span><span class="params">(Iterable<? extends K> keys)</span> <span class="keyword">throws</span> ExecutionException</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Loads a new value for key {<span class="doctag">@code</span> key}, possibly asynchronously. While the new value is loading</span></span><br><span class="line"><span class="comment"> * the previous value (if any) will continue to be returned by {<span class="doctag">@code</span> get(key)} unless it is</span></span><br><span class="line"><span class="comment"> * evicted. If the new value is loaded successfully it will replace the previous value in the</span></span><br><span class="line"><span class="comment"> * cache; if an exception is thrown while refreshing the previous value will remain, <i>and the</span></span><br><span class="line"><span class="comment"> * exception will be logged (using {<span class="doctag">@link</span> java.util.logging.Logger}) and swallowed</i>.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p>Caches loaded by a {<span class="doctag">@link</span> CacheLoader} will call {<span class="doctag">@link</span> CacheLoader#reload} if the cache</span></span><br><span class="line"><span class="comment"> * currently contains a value for {<span class="doctag">@code</span> key}, and {<span class="doctag">@link</span> CacheLoader#load} otherwise. Loading is</span></span><br><span class="line"><span class="comment"> * asynchronous only if {<span class="doctag">@link</span> CacheLoader#reload} was overridden with an asynchronous</span></span><br><span class="line"><span class="comment"> * implementation.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p>Returns without doing anything if another thread is currently loading the value for {<span class="doctag">@code</span></span></span><br><span class="line"><span class="comment"> * key}. If the cache loader associated with this cache performs refresh asynchronously then this</span></span><br><span class="line"><span class="comment"> * method may return before refresh completes.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@since</span> 11.0</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">refresh</span><span class="params">(K key)</span></span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a view of the entries stored in this cache as a thread-safe map. Modifications made to</span></span><br><span class="line"><span class="comment"> * the map directly affect the cache.</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <p>Iterators from the returned map are at least <i>weakly consistent</i>: they are safe for</span></span><br><span class="line"><span class="comment"> * concurrent use, but if the cache is modified (including by eviction) after the iterator is</span></span><br><span class="line"><span class="comment"> * created, it is undefined which of the changes (if any) will be reflected in that iterator.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="function">ConcurrentMap<K, V> <span class="title">asMap</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>先看<strong>get</strong>方法,抛出了ExecutionException异常,这个异常定义在并发包java.util.concurrent下,所以可以猜测get时候会不会和并发,多线程执行有关.否则不可能无缘无故抛出这么个异常。事实证明猜测是对的,Guava对于<a href="https://github.com/google/guava/wiki/CachesExplained#interruption" target="_blank" rel="noopener">Interruption</a>的处理很多设计决策。</p>
<p><strong>getUnchecked</strong>同样是获取v方法,没有抛出任何异常,方法名是获取非受检异常,可以看出获取key的时候,一定会报错,但是提供了更加灵活的异常处理机制,而这些知识,就需要对受检异常和非受检异常有清晰的认识才能设计出这样的API,否则是不会想到这一层的。</p>
<p><strong>getAll</strong>这个接口设计很有意思,传参是Iterable,足够看到其通用和扩展性,但是返回确是不可变的Map,看到这里,是不是觉得比较有趣呢?可以质疑为什么不用List接口呢?当然使用的时候传入Key List是可以的,但是如果你不理解Iterable的接口,你这段代码很有可能需要百度demo才能写出来,下次遇到同样的问题还是没有任何进步,成为了API Caller。</p>
<p><strong>refresh</strong>从方法签名看不出什么,但是API文档注释非常详细,足够了解了。</p>
<p><strong>asMap</strong> 是缓存的视图,但是修改缓存视图会导致底层缓存被修改,并且用的是并发的Map接口,此时几乎可以得出结论,缓存大概率会并发读写的,所以benchmark时候,并发读写能力一定是一个点。此时你对ConcurrentMap操作时候就需要清晰地了解ConcurrentMap的特性,并发修改时候遍历等问题。如果你希望业务层缓存只能用来读,而缓存层做缓存更新的话,你可以将asMap包装成不可变的Map. 当转换成Map时候,疑问在于关于Cache的契约是否就会被打破了?比如get时候load数据。</p>
<p>可以看到,还没有看LoadingCache的实现,我们就可以很多,看完核心接口,在辅以文档,可以说对Cache Design和Decision有最基本的认识了,缓存和高性能有着千丝万缕的关系,需要深入到边边角角,既能从高层知道如何设计一个Cache,也能从底层知道如何实现一个Cache,否则在工程中可能因为一个参数配置就会导致性能问题。虽然以上方法在使用起来非常简单,但是合理的理解其设计和抽象对使用产生很大帮助,对不同API也能触类旁通,也可以提高自己设计API的水平,从此脱离API Caller的窘境,成为一名API Designer. </p>
<p>API Caller还有一个非常典型的例子是线程池的使用。API Caller还有特点不喜欢看API文档,甚至不知道哪里看API文档。</p>
<p>个人比较喜欢的学习技术方法是:无论如何先看一遍官方文档,学有余力则看一遍API文档,很感兴趣则可以入手源码。</p>
<h1 id="Copy-Paste"><a href="#Copy-Paste" class="headerlink" title="Copy Paste"></a>Copy Paste</h1><p>粘贴复制本身其实没有什么问题,可以提供编程效率,但是由于复制带来的<strong>代码重复</strong>问题较为严重。因为这是时空级别的重复,虽然重复的概念很简单,但是衍生带来的,维护性,可读性,耦合性,内聚性问题,牵一发而不知道影响面,会极大降低代码仓库质量和Bug数量。如果说技术债最严重的问题,我觉得是重复代码问题。通过良好的抽象和封装,以及子函数,状态聚合,行为聚合等编程手段,会减少重复问题。</p>
<h1 id="技术方案与实现的不一致性"><a href="#技术方案与实现的不一致性" class="headerlink" title="技术方案与实现的不一致性"></a>技术方案与实现的不一致性</h1><p>技术方案更偏向于架构,而实现更偏向于代码。有些技术方案涉及到编程(比如redis使用),有些则无需(比如nginx负载均衡和容器化)这两者在某些程度并不是一致的。有些时候技术方案提出者并不是实现者,即使是,也有可能出现方案很牛逼,但是编码能力有限会导致的实现不好的现象。这点有一个例子,比如架构上引入缓存作为一个高层次的组件,但是缓存具体选型和实现上,则会出现分歧,用ConcurrentHashMap还是Guava Cache呢?这两者对于代码实现的复杂度不同。在实现的时候,又会面临如何封装,代码包组织,如何抽象的编程等非常细节问题,如果使用了Guava Cache,则会不会沦为API Caller的窘境呢?</p>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>crud boy,api caller,copy paste在开发业务时候会带来巨大便利,但是使用和理解不好也会造成非常多技术债和坑,这对个人成长帮助有限,会带来<strong>我不断在学习</strong>的假象,实际难逃轮回,凡所有相,皆是虚妄,若见诸相非相,即见如来。多花些时间研究API(包括优质和劣质)是有帮助的,要对业内“<strong>忘记了,百度下就能知道了</strong>”如此言论保持怀疑,他会使你真正成为API Caller的。你我都在路上!</p>
]]></content>
<categories>
<category>杂谈</category>
</categories>
<tags>
<tag>代码设计杂谈</tag>
</tags>
</entry>
<entry>
<title>ThreadLocal设计,实现,使用注意</title>
<url>/2020/11/15/ThreadLocal-Design-And-Implementation/</url>
<content><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p>线程局部变量是避免多线程读取共享变量造成竞争的一种机制,每个线程只能看到自己的私有变量,这就避免了锁竞争问题。在Java中,使用ThreadLocal可以实现该机制。</p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><p>在Java的ThreadLocal中,一个线程拥有多个ThreadLocal,每个ThreadLocal的变量存储在包级可见的内部静态类ThreadLocalMap中,ThreadLocalMap的Key是用WeakReference包装的ThreadLocal,Value则是强引用普通变量,每个ThreadLocal及其变量以KV形式存储在ThreadLocalMap中,而ThreadLocalMap并没有实现Map接口,而是自己实现了类似Map的功能。当前线程不在活跃的时候,垃圾收集器回自动回收ThreadLocal。即使内部细节非常多,但是ThreadLocal暴露给客户端的API确是非常简单,核心方法仅有initialValue,set,get,remove方法,这是经过多次改进后的设计。下图是结构图:</p>
<p>单一线程:</p>
<img src="/images/ThreadLocalMap.png" style="zoom:75%;" />
<p>多线程:</p>
<p><img src="/images/ThreadLocalMultiThread.png" alt=""></p>
<p>从图中得出结论:</p>
<p>多个线程使用同一个ThreadLocal时候,每个线程会在内部创建一个自己的ThreadLocalMap. Thread:ThreadLocal:ThreadLocalMap=多:一:多</p>
<p>一个线程使用多个ThreadLocal时候,一个线程创建了多个 ThreadLocalMap. Thread:ThreadLocal:ThreadLocalMap=一:多:一</p>
<p>所以ThreadLocalMap数量和线程数有关。ThreadLocal是和一个领域或者业务有关。</p>
<p>下图是类图:</p>
<p><img src="/images/ThreadLocal.png" alt=""></p>
<h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1><h1 id="API演进"><a href="#API演进" class="headerlink" title="API演进"></a>API演进</h1><h1 id="实战"><a href="#实战" class="headerlink" title="实战"></a>实战</h1><h1 id="使用注意"><a href="#使用注意" class="headerlink" title="使用注意"></a>使用注意</h1><p>1 由于每个线程的可以有多个ThreadLocal,每个ThreadLocal是唯一的,所以定义ThreadLocal时候需要定义成static final,并且初始化一个值。</p>
<p>2 当已经给ThreadLocal设置值后,最好不需要时候主动remove,防止线程变量泄漏。</p>
<p>3 当有父子线程需要共享传递值的时候,需要使用ThreadLocal的子类InheritableThreadLocal.</p>
<p>4 当使用线程池更需要注意由于线程的可复用性,所以可能导致复用的线程拥有之前任务所传递的ThreadLocal局部变量,所以要在任务结束之后finallyremove该Worker的局部变量。</p>
<p>5 内存泄漏和变量泄漏问题。</p>
]]></content>
<categories>
<category>JDK源码</category>
<category>Java核心</category>
</categories>
<tags>
<tag>java.lang</tag>
</tags>
</entry>
<entry>
<title>FutureTask设计与实现</title>
<url>/2020/11/11/FutureTask-Design-And-Implementation/</url>
<content><![CDATA[<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p>FutureTask是Future和Runnable的实现,ThreadPoolExecutor在执行任务的时候,执行的是FutureTask. 传统Runnable接口实现的任务只有执行方法run,并没有任务取消,执行超时等功能,并且Runnable并没有提供任务状态的抽象,其实每个任务都是有状态的。所以FutureTask其内部将任务执行过程分为一系列状态,从而使得任务有了生命周期。在JDK中,经典的实现除了FutureTask外,还有ScheduledFutureTask. </p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><p><img src="/images/FutureTask.png" alt=""></p>
<p>我们可以看到它对一个普通任务支持了生命周期的方法. 从而使得任务执行有了过程的概念,而不是Runnable这样只能运行或者被中断的状态,也使得客户端更加灵活的控制任务执行。</p>
<h1 id="API"><a href="#API" class="headerlink" title="API"></a>API</h1><p>FutureTask的API全部来自父接口,自己只定义了构造函数,</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//任务执行方法,继承自RunnableFuture的run,RunnableFuture又继承在Runnable</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="comment">//run之后,获取run的结果,可能任务执行被中断,或者执行异常</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span></span><br><span class="line"><span class="function"></span></span><br><span class="line"><span class="function"><span class="comment">//带超时的获取run结果,可能抛出超时异常 </span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span> <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException</span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="comment">//取消任务</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">cancel</span><span class="params">(<span class="keyword">boolean</span> mayInterruptIfRunning)</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="comment">//任务是否被取消 </span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isCancelled</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="comment">//任务是否完成</span></span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isDone</span><span class="params">()</span></span></span><br><span class="line"><span class="function"> </span></span><br><span class="line"><span class="function"><span class="comment">//钩子方法</span></span></span><br><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">done</span><span class="params">()</span> </span>{ }</span><br></pre></td></tr></table></figure>
<h1 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h1><h2 id="创建"><a href="#创建" class="headerlink" title="创建"></a>创建</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过Callable创建FutureTask,并且任务状态设置为NEW</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">FutureTask</span><span class="params">(Callable<V> callable)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (callable == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="keyword">this</span>.callable = callable;</span><br><span class="line"> <span class="keyword">this</span>.state = NEW; <span class="comment">// ensure visibility of callable</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过Runnable创建FutureTask,并且任务状态设置为NEW</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">FutureTask</span><span class="params">(Runnable runnable, V result)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.callable = Executors.callable(runnable, result);</span><br><span class="line"> <span class="keyword">this</span>.state = NEW; <span class="comment">// ensure visibility of callable</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="等待节点WaitNode"><a href="#等待节点WaitNode" class="headerlink" title="等待节点WaitNode"></a>等待节点WaitNode</h2><p>等待节点是当有多个线程获取结果的时候,会进行排队,当有一个线程get到结果时候,其他线程将被唤醒,也将拿到结果。该等待节点的实现是Treiber Stack,Treiber 是发明者名字,它是非阻塞的同步栈,详情可参考Wikipedia. <a href="https://en.wikipedia.org/wiki/Treiber_stack" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/Treiber_stack</a></p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">WaitNode</span> </span>{</span><br><span class="line"> <span class="keyword">volatile</span> Thread thread;</span><br><span class="line"> <span class="keyword">volatile</span> WaitNode next;</span><br><span class="line"> WaitNode() { thread = Thread.currentThread(); }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>该类的实现是静态final类,意味着这是一个全局的类,和外部实例没有关系,并且不能被继承,</p>
<h2 id="实例变量"><a href="#实例变量" class="headerlink" title="实例变量"></a>实例变量</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">/** 运行的任务 */</span></span><br><span class="line"><span class="keyword">private</span> Callable<V> callable;</span><br><span class="line"><span class="comment">/** get返回的结果 */</span></span><br><span class="line"><span class="keyword">private</span> Object outcome; <span class="comment">// non-volatile, protected by state reads/writes</span></span><br><span class="line"><span class="comment">/** 运行Callable的线程 */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">volatile</span> Thread runner;</span><br><span class="line"><span class="comment">/** Treiber stack上的等待线程 */</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">volatile</span> WaitNode waiters;</span><br></pre></td></tr></table></figure>
<h2 id="任务状态"><a href="#任务状态" class="headerlink" title="任务状态"></a>任务状态</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">int</span> state; <span class="comment">//任务状态,每个API都会和状态相关</span></span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> NEW = <span class="number">0</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> COMPLETING = <span class="number">1</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> NORMAL = <span class="number">2</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> EXCEPTIONAL = <span class="number">3</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> CANCELLED = <span class="number">4</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> INTERRUPTING = <span class="number">5</span>;</span><br><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> INTERRUPTED = <span class="number">6</span>;</span><br></pre></td></tr></table></figure>
<p>任务的状态有7种,每种任务状态是递增且不可逆的。下面是状态流转图:</p>
<img src="/images/FutureTaskStatus.png" style="zoom:50%;" />
<p>任务起始状态是NEW,中间过程有COMPLETING和INTERRUPTING,终态有四种,也就是图的叶子节点。这些状态使得任务可以被控制。</p>
<h2 id="任务运行run"><a href="#任务运行run" class="headerlink" title="任务运行run"></a>任务运行run</h2><p>任务运行是实现run方法,也就是客户端自定义的任务。</p>
<p>run方法首先判断状态,如果任务状态不NEW,则直接退出,防止任务重复执行,然后进入真正任务执行,调用Callable的call方法,</p>
<p>call结束,任务执行完成,将ran置为ture,正常情况调用set,如果运行中发生异常,调用setException,</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//判断状态是不是NEW</span></span><br><span class="line"> <span class="keyword">if</span> (state != NEW ||</span><br><span class="line"> !RUNNER.compareAndSet(<span class="keyword">this</span>, <span class="keyword">null</span>, Thread.currentThread()))</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Callable<V> c = callable;</span><br><span class="line"> <span class="keyword">if</span> (c != <span class="keyword">null</span> && state == NEW) {</span><br><span class="line"> V result;</span><br><span class="line"> <span class="keyword">boolean</span> ran;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="comment">//真正任务执行</span></span><br><span class="line"> result = c.call();</span><br><span class="line"> <span class="comment">//执行完成设置ran为true</span></span><br><span class="line"> ran = <span class="keyword">true</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (Throwable ex) {</span><br><span class="line"> <span class="comment">//任务执行发生异常</span></span><br><span class="line"> result = <span class="keyword">null</span>;</span><br><span class="line"> ran = <span class="keyword">false</span>;</span><br><span class="line"> <span class="comment">//修改任务执行状态为异常</span></span><br><span class="line"> setException(ex);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ran)</span><br><span class="line"> <span class="comment">//修改任务执行状态为正常结束</span></span><br><span class="line"> set(result);</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">// runner must be non-null until state is settled to</span></span><br><span class="line"> <span class="comment">// prevent concurrent calls to run()</span></span><br><span class="line"> runner = <span class="keyword">null</span>;</span><br><span class="line"> <span class="comment">// state must be re-read after nulling runner to prevent</span></span><br><span class="line"> <span class="comment">// leaked interrupts</span></span><br><span class="line"> <span class="keyword">int</span> s = state;</span><br><span class="line"> <span class="keyword">if</span> (s >= INTERRUPTING)</span><br><span class="line"> handlePossibleCancellationInterrupt(s);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果发生异常将任务状态设置为EXCEPTIONAL</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">setException</span><span class="params">(Throwable t)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (STATE.compareAndSet(<span class="keyword">this</span>, NEW, COMPLETING)) {</span><br><span class="line"> outcome = t;</span><br><span class="line"> STATE.setRelease(<span class="keyword">this</span>, EXCEPTIONAL); <span class="comment">// final state</span></span><br><span class="line"> finishCompletion();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>如果正常执行完成,将任务状态设置为NORMAL</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">set</span><span class="params">(V v)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (STATE.compareAndSet(<span class="keyword">this</span>, NEW, COMPLETING)) {</span><br><span class="line"> outcome = v;</span><br><span class="line"> STATE.setRelease(<span class="keyword">this</span>, NORMAL); <span class="comment">// final state</span></span><br><span class="line"> finishCompletion();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="获取任务结果get"><a href="#获取任务结果get" class="headerlink" title="获取任务结果get()"></a>获取任务结果get()</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>{</span><br><span class="line"> <span class="keyword">int</span> s = state;</span><br><span class="line"> <span class="keyword">if</span> (s <= COMPLETING)</span><br><span class="line"> s = awaitDone(<span class="keyword">false</span>, <span class="number">0L</span>);</span><br><span class="line"> <span class="keyword">return</span> report(s);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>从API可以看出,获取任务结果时候,任务可能被中断,或者发生执行异常。</p>
<h3 id="awaitDone-自旋等待结果"><a href="#awaitDone-自旋等待结果" class="headerlink" title="awaitDone 自旋等待结果"></a>awaitDone 自旋等待结果</h3><p>读这段代码时候,一定要想着会有多个线程来awaitDone,并且每一个线程都在自旋,等待状态变化。每个线程按照排队方式排列在waiters进行等待。</p>
<p>假设有四个线程同时获取结果,每一个运行1s后,才启动另一个线程,那么每个线程第一次进入awaitDone时候将会创建自己的WaitNode,然后第二次进入会发现queued=false,然后将第一次进入的创建WaitNode节点next指向waiters,如Thread1 -> waiters,</p>
<p>第三次进入时候,因为所有的分支条件只满足最后一个,调用LockSupport.park(this),此时该线程因为一直没有获取结果而进行wait,此时线程状态变成waiting。依次类推,第二个线程进入,第三个线程进入,第四个线程进入,将会形成以下结构:</p>
<img src="/images/FutureTaskStack.png" style="zoom:80%;" />
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//timed false说明没有超时时间限制</span></span><br><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">int</span> <span class="title">awaitDone</span><span class="params">(<span class="keyword">boolean</span> timed, <span class="keyword">long</span> nanos)</span> <span class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> <span class="keyword">long</span> startTime = <span class="number">0L</span>; <span class="comment">// Special value 0L means not yet parked</span></span><br><span class="line"> WaitNode q = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">boolean</span> queued = <span class="keyword">false</span>;</span><br><span class="line"> <span class="comment">//当任务执行时候,一直在自旋等待状态变化,为了不断获取任务执行过程中的状态。</span></span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="keyword">int</span> s = state;</span><br><span class="line"> <span class="keyword">if</span> (s > COMPLETING) {</span><br><span class="line"> <span class="keyword">if</span> (q != <span class="keyword">null</span>)</span><br><span class="line"> <span class="comment">//大于COMPLETING的其他状态,直接返回状态,该状态主要改变会在run方法中改变</span></span><br><span class="line"> q.thread = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (s == COMPLETING)</span><br><span class="line"> Thread.yield();</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (Thread.interrupted()) {</span><br><span class="line"> <span class="comment">//线程被中断时候,移除等待节点上的线程,并且告诉客户端发生了中断,</span></span><br><span class="line"> removeWaiter(q);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> InterruptedException();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//第一次进入时候,WaitNode为空,创建新的等待节点。</span></span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (q == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (timed && nanos <= <span class="number">0L</span>)</span><br><span class="line"> <span class="keyword">return</span> s;</span><br><span class="line"> q = <span class="keyword">new</span> WaitNode();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (!queued)</span><br><span class="line"> <span class="comment">//如果</span></span><br><span class="line"> queued = WAITERS.weakCompareAndSet(<span class="keyword">this</span>, q.next = waiters, q);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (timed) {</span><br><span class="line"> <span class="comment">//如果有超时实现限制,则会不断和最终时间进行比较,超过最终时间,状态返回NEW,并且在外层抛出</span></span><br><span class="line"> <span class="comment">//TimeoutException</span></span><br><span class="line"> <span class="keyword">final</span> <span class="keyword">long</span> parkNanos;</span><br><span class="line"> <span class="keyword">if</span> (startTime == <span class="number">0L</span>) { <span class="comment">// first time</span></span><br><span class="line"> startTime = System.nanoTime();</span><br><span class="line"> <span class="keyword">if</span> (startTime == <span class="number">0L</span>)</span><br><span class="line"> startTime = <span class="number">1L</span>;</span><br><span class="line"> parkNanos = nanos;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">long</span> elapsed = System.nanoTime() - startTime;</span><br><span class="line"> <span class="keyword">if</span> (elapsed >= nanos) {</span><br><span class="line"> removeWaiter(q);</span><br><span class="line"> <span class="keyword">return</span> state;</span><br><span class="line"> }</span><br><span class="line"> parkNanos = nanos - elapsed;</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">// nanoTime may be slow; recheck before parking</span></span><br><span class="line"> <span class="keyword">if</span> (state < COMPLETING)</span><br><span class="line"> <span class="comment">//park当前线程</span></span><br><span class="line"> LockSupport.parkNanos(<span class="keyword">this</span>, parkNanos);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="comment">//所有排队的线程均会被park住.</span></span><br><span class="line"> LockSupport.park(<span class="keyword">this</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="finishCompletion-完成任务"><a href="#finishCompletion-完成任务" class="headerlink" title="finishCompletion 完成任务"></a>finishCompletion 完成任务</h3><p>当有任务完成时候,会将Tribie Stack等待的线程全部unpark,并且释放每个WaitNode的线程.</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">finishCompletion</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">// assert state > COMPLETING;</span></span><br><span class="line"> <span class="keyword">for</span> (WaitNode q; (q = waiters) != <span class="keyword">null</span>;) {</span><br><span class="line"> <span class="keyword">if</span> (WAITERS.weakCompareAndSet(<span class="keyword">this</span>, q, <span class="keyword">null</span>)) {</span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> Thread t = q.thread;</span><br><span class="line"> <span class="keyword">if</span> (t != <span class="keyword">null</span>) {</span><br><span class="line"> q.thread = <span class="keyword">null</span>;</span><br><span class="line"> LockSupport.unpark(t);</span><br><span class="line"> }</span><br><span class="line"> WaitNode next = q.next;</span><br><span class="line"> <span class="keyword">if</span> (next == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> q.next = <span class="keyword">null</span>; <span class="comment">// unlink to help gc</span></span><br><span class="line"> q = next;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> done();</span><br><span class="line"></span><br><span class="line"> callable = <span class="keyword">null</span>; <span class="comment">// to reduce footprint</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="meta">@SuppressWarnings</span>(<span class="string">"unchecked"</span>)</span><br><span class="line"><span class="function"><span class="keyword">private</span> V <span class="title">report</span><span class="params">(<span class="keyword">int</span> s)</span> <span class="keyword">throws</span> ExecutionException </span>{</span><br><span class="line"> Object x = outcome;</span><br><span class="line"> <span class="keyword">if</span> (s == NORMAL)</span><br><span class="line"> <span class="keyword">return</span> (V)x;</span><br><span class="line"> <span class="keyword">if</span> (s >= CANCELLED)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> CancellationException();</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ExecutionException((Throwable)x);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="带超时的get"><a href="#带超时的get" class="headerlink" title="带超时的get()"></a>带超时的get()</h2><p>这块和get()其实差不多,只是会进入get的不同for(;;)分支,当超过指定时间没有返回结果时候,将会抛出TimeoutException异常。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException </span>{</span><br><span class="line"> <span class="keyword">if</span> (unit == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="keyword">int</span> s = state;</span><br><span class="line"> <span class="keyword">if</span> (s <= COMPLETING &&</span><br><span class="line"> (s = awaitDone(<span class="keyword">true</span>, unit.toNanos(timeout))) <= COMPLETING)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> TimeoutException();</span><br><span class="line"> <span class="keyword">return</span> report(s);</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="取消任务cancel"><a href="#取消任务cancel" class="headerlink" title="取消任务cancel"></a>取消任务cancel</h2><p>任务取消成功返回true,取消失败返回false,可以从条件判断中得知,当状态为NEW,且被原子更新为INTERRUPTING或CANCELLED,</p>
<p>才能取消任务。当可以中断时候,任务通过中断实现的,中断之后将任务状态设置为INTERRUPTING,当不可以中断,任务取消其实并没有做什么,只是将任务状态修改为或CANCELLED,当任务状态发生变化时候,一直自旋等待线程会在get方法中获得状态变化,从而执行相关分析,最后执行finishCompletion.</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">cancel</span><span class="params">(<span class="keyword">boolean</span> mayInterruptIfRunning)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!(state == NEW && STATE.compareAndSet</span><br><span class="line"> (<span class="keyword">this</span>, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">try</span> { <span class="comment">// in case call to interrupt throws exception</span></span><br><span class="line"> <span class="keyword">if</span> (mayInterruptIfRunning) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> Thread t = runner;</span><br><span class="line"> <span class="keyword">if</span> (t != <span class="keyword">null</span>)</span><br><span class="line"> t.interrupt();</span><br><span class="line"> } <span class="keyword">finally</span> { <span class="comment">// final state</span></span><br><span class="line"> STATE.setRelease(<span class="keyword">this</span>, INTERRUPTED);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> finishCompletion();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="是否取消isCancelled"><a href="#是否取消isCancelled" class="headerlink" title="是否取消isCancelled"></a>是否取消isCancelled</h2><p>根据状态判断,因为状态是递增的。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isCancelled</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> state >= CANCELLED;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="是否完成isDone"><a href="#是否完成isDone" class="headerlink" title="是否完成isDone"></a>是否完成isDone</h2><p>同样根据状态判断。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isDone</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> state != NEW;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h1 id="实战案例"><a href="#实战案例" class="headerlink" title="实战案例"></a>实战案例</h1>]]></content>
<categories>
<category>JDK源码</category>
<category>Java并发框架</category>
</categories>
<tags>
<tag>java.util.concurrent</tag>
</tags>
</entry>
<entry>
<title>Java集合框架(2)-抽象实现骨架</title>
<url>/2020/11/09/JCF-AbstractInterfaceImpl/</url>
<content><![CDATA[<h1 id="概述"><a href="#概述" class="headerlink" title="概述"></a>概述</h1><p><strong>接口定义类型,抽象类实现骨架</strong>。抽象类不支持的实现方法便是细节。这种技巧在JCF中是标配。一来替客户端提供如何实现一个接口的最直接的参考。二来帮助客户端以此实现功能更强的接口。如Guava的集合也是参考这种模式。</p>
<h1 id="抽象实现"><a href="#抽象实现" class="headerlink" title="抽象实现"></a>抽象实现</h1><p>抽象类的最重要分析是留下了哪些抽象方法,而留下的抽象方法是真正实现类的差异,而抽象类中的普通方法使用抽象方法来实现,而抽象方法实现由实现类实现,并且抽象类没有任何字段,所以也能从侧面体现留下的抽象方法的价值。可以认为抽象实现是模板模式的一种应用。</p>
<h2 id="AbstractCollection"><a href="#AbstractCollection" class="headerlink" title="AbstractCollection"></a>AbstractCollection</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//这是AbstractCollection最核心的两个抽象方法,其余方法实现均是调用这两者</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> Iterator<E> <span class="title">iterator</span><span class="params">()</span></span>;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<h3 id="isEmpty"><a href="#isEmpty" class="headerlink" title="isEmpty"></a>isEmpty</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//非常简单,size()=0</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> size() == <span class="number">0</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="contains"><a href="#contains" class="headerlink" title="contains"></a>contains</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过遍历迭代器来查找元素,元素为空,找出Collection中第一个为空的元素,元素不为空,</span></span><br><span class="line"><span class="comment">//找出第一个在集合中的元素,对象需要实现equals方法</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Object o)</span> </span>{</span><br><span class="line"> Iterator<E> it = iterator();</span><br><span class="line"> <span class="keyword">if</span> (o==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext())</span><br><span class="line"> <span class="keyword">if</span> (it.next()==<span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext())</span><br><span class="line"> <span class="keyword">if</span> (o.equals(it.next())) <span class="comment">//对象equals方法很重要</span></span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="add"><a href="#add" class="headerlink" title="add"></a>add</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//抛出异常,因为子类可以实现可变或者不可变集合</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">add</span><span class="params">(E e)</span> </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="remove"><a href="#remove" class="headerlink" title="remove"></a>remove</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过迭代器删除,equals方法很重要</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">remove</span><span class="params">(Object o)</span> </span>{</span><br><span class="line"> Iterator<E> it = iterator();</span><br><span class="line"> <span class="keyword">if</span> (o==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext()) {</span><br><span class="line"> <span class="keyword">if</span> (it.next()==<span class="keyword">null</span>) {</span><br><span class="line"> it.remove();</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext()) {</span><br><span class="line"> <span class="keyword">if</span> (o.equals(it.next())) {</span><br><span class="line"> it.remove();</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="containsAll"><a href="#containsAll" class="headerlink" title="containsAll"></a>containsAll</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//时间复杂度为O(n^2)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">containsAll</span><span class="params">(Collection<?> c)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (Object e : c)</span><br><span class="line"> <span class="keyword">if</span> (!contains(e))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="addAll"><a href="#addAll" class="headerlink" title="addAll"></a>addAll</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//modified来判断集合是否改变</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addAll</span><span class="params">(Collection<? extends E> c)</span> </span>{</span><br><span class="line"> <span class="keyword">boolean</span> modified = <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">for</span> (E e : c)</span><br><span class="line"> <span class="keyword">if</span> (add(e))</span><br><span class="line"> modified = <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">return</span> modified;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="removeAll"><a href="#removeAll" class="headerlink" title="removeAll"></a>removeAll</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//通过迭代器删除</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">removeAll</span><span class="params">(Collection<?> c)</span> </span>{</span><br><span class="line"> Objects.requireNonNull(c);</span><br><span class="line"> <span class="keyword">boolean</span> modified = <span class="keyword">false</span>;</span><br><span class="line"> Iterator<?> it = iterator();</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext()) {</span><br><span class="line"> <span class="keyword">if</span> (c.contains(it.next())) {</span><br><span class="line"> it.remove();</span><br><span class="line"> modified = <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> modified;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="clear"><a href="#clear" class="headerlink" title="clear"></a>clear</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//遍历迭代器,删除元素</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</span><br><span class="line"> Iterator<E> it = iterator();</span><br><span class="line"> <span class="keyword">while</span> (it.hasNext()) {</span><br><span class="line"> it.next();</span><br><span class="line"> it.remove();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>我们可以看到抽象方法在实现普通方法时候是基本每个方法都会调用。</p>
<h2 id="AbstractList"><a href="#AbstractList" class="headerlink" title="AbstractList"></a>AbstractList</h2><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//AbstractList抽象方法有两个,1是新定义的get 2是继承父类的size,而父类AbstractCollection中的抽象方法只实现了一个iterator(),因为对于List来说,iterator行为是确认的。但是get行为需要子类实现。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> E <span class="title">get</span><span class="params">(<span class="keyword">int</span> index)</span></span>;</span><br></pre></td></tr></table></figure>
<p>在AbstractList实现中,定义了Itr, ListItr两个迭代器,以及用于实现内部视图的SubList和RandomAccessSubList.</p>
<h3 id="iterator"><a href="#iterator" class="headerlink" title="iterator"></a>iterator</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> Iterator<E> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Itr();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="Itr"><a href="#Itr" class="headerlink" title="Itr"></a>Itr</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">Itr</span> <span class="keyword">implements</span> <span class="title">Iterator</span><<span class="title">E</span>> </span>{</span><br><span class="line"> <span class="comment">/** 游标位置,指向当前元素**/</span></span><br><span class="line"> <span class="keyword">int</span> cursor = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">/**调用next后之前的元素,-1说明刚被删除了*/</span></span><br><span class="line"> <span class="keyword">int</span> lastRet = -<span class="number">1</span>;</span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> *期望修复次数是不是等于实际修改次数,用户判断遍历时候是否被修改,如果不同则会抛出ConcurrentModificationException</span></span><br><span class="line"><span class="comment"> * 因为这些集合不是在线程安全的,所以并发修改会报错。</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">int</span> expectedModCount = modCount;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> cursor != size();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> E <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> checkForComodification();<span class="comment">//检查是否被修改</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">int</span> i = cursor; <span class="comment">//当前位置的cursor存储起来</span></span><br><span class="line"> E next = get(i);<span class="comment">//抽象方法get获取元素</span></span><br><span class="line"> lastRet = i;<span class="comment">//更新上一个元素位置</span></span><br><span class="line"> cursor = i + <span class="number">1</span>;<span class="comment">//cursor下移一位</span></span><br><span class="line"> <span class="keyword">return</span> next;<span class="comment">//返回当前元素</span></span><br><span class="line"> } <span class="keyword">catch</span> (IndexOutOfBoundsException e) {</span><br><span class="line"> checkForComodification();</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//删除某个元素</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (lastRet < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException();</span><br><span class="line"> checkForComodification();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> AbstractList.<span class="keyword">this</span>.remove(lastRet);<span class="comment">//调用删除方法</span></span><br><span class="line"> <span class="keyword">if</span> (lastRet < cursor) <span class="comment">//</span></span><br><span class="line"> cursor--;</span><br><span class="line"> lastRet = -<span class="number">1</span>;<span class="comment">//lastRet设置为-1</span></span><br><span class="line"> expectedModCount = modCount;<span class="comment">//修改次数等于期望修改次数</span></span><br><span class="line"> } <span class="keyword">catch</span> (IndexOutOfBoundsException e) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">final</span> <span class="keyword">void</span> <span class="title">checkForComodification</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (modCount != expectedModCount)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="ListItr"><a href="#ListItr" class="headerlink" title="ListItr"></a>ListItr</h3><p>ListItr实现了ListIterator接口,ListIterator和Iterator不同之处在于Iterator只支持向后遍历,但是ListIterator同时支持向后和向前遍历。也支持任意位置开始的遍历。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ListIterator</span><<span class="title">E</span>> <span class="keyword">extends</span> <span class="title">Iterator</span><<span class="title">E</span>> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function">E <span class="title">next</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">hasPrevious</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function">E <span class="title">previous</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">nextIndex</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">previousIndex</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">set</span><span class="params">(E e)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">add</span><span class="params">(E e)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">ListItr</span> <span class="keyword">extends</span> <span class="title">Itr</span> <span class="keyword">implements</span> <span class="title">ListIterator</span><<span class="title">E</span>> </span>{</span><br><span class="line"> ListItr(<span class="keyword">int</span> index) {</span><br><span class="line"> cursor = index;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasPrevious</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> cursor != <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> E <span class="title">previous</span><span class="params">()</span> </span>{</span><br><span class="line"> checkForComodification();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">int</span> i = cursor - <span class="number">1</span>;<span class="comment">//前一个元素索引</span></span><br><span class="line"> E previous = get(i);<span class="comment">//获取前一个元素</span></span><br><span class="line"> lastRet = cursor = i;<span class="comment">//设置lastRet = cursor等于前一个元素索引</span></span><br><span class="line"> <span class="keyword">return</span> previous;</span><br><span class="line"> } <span class="keyword">catch</span> (IndexOutOfBoundsException e) {</span><br><span class="line"> checkForComodification();</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NoSuchElementException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">nextIndex</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> cursor;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">previousIndex</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> cursor-<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">set</span><span class="params">(E e)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (lastRet < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalStateException();</span><br><span class="line"> checkForComodification();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> AbstractList.<span class="keyword">this</span>.set(lastRet, e);</span><br><span class="line"> expectedModCount = modCount;</span><br><span class="line"> } <span class="keyword">catch</span> (IndexOutOfBoundsException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">add</span><span class="params">(E e)</span> </span>{</span><br><span class="line"> checkForComodification();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">int</span> i = cursor;</span><br><span class="line"> AbstractList.<span class="keyword">this</span>.add(i, e);</span><br><span class="line"> lastRet = -<span class="number">1</span>;</span><br><span class="line"> cursor = i + <span class="number">1</span>;</span><br><span class="line"> expectedModCount = modCount;</span><br><span class="line"> } <span class="keyword">catch</span> (IndexOutOfBoundsException ex) {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> ConcurrentModificationException();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="SubList"><a href="#SubList" class="headerlink" title="SubList"></a>SubList</h3><h3 id="RandomAccessSubList"><a href="#RandomAccessSubList" class="headerlink" title="RandomAccessSubList"></a>RandomAccessSubList</h3><h2 id="AbstractSequentialList"><a href="#AbstractSequentialList" class="headerlink" title="AbstractSequentialList"></a>AbstractSequentialList</h2><p>AbstractSequentialList新加创建List迭代器的抽象方法listIterator。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> ListIterator<E> <span class="title">listIterator</span><span class="params">(<span class="keyword">int</span> index)</span></span>;</span><br></pre></td></tr></table></figure>
<h2 id="AbstractSet"><a href="#AbstractSet" class="headerlink" title="AbstractSet"></a>AbstractSet</h2><p>AbstractSet没有新加任何抽象方法,由于继承了AbstractCollection,所以它的实现是基于iterator和size的。</p>
<h2 id="AbstractMap"><a href="#AbstractMap" class="headerlink" title="AbstractMap"></a>AbstractMap</h2><p>AbstractMap中的抽象方法只有entrySet,可以推断其他方法均是基于该方法实现的。因为键值对的唯一性,所以使用Set存储每一个Entry,虽然Entry好像是数据类,但是本质是有行为的类。每一个Entry代表了一个键值对,我们只能修改value,获取kv,但是不能修改key,这是Entry接口带来的契约,也是设计Entry的点,如果key可以被更新,那么这个map行为将变得不可预期。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> Set<Entry<K,V>> entrySet();</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//我们注意到Entry对KV的抽象,</span></span><br><span class="line"><span class="class"><span class="keyword">interface</span> <span class="title">Entry</span><<span class="title">K</span>, <span class="title">V</span>> </span>{</span><br><span class="line"> <span class="function">K <span class="title">getKey</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function">V <span class="title">getValue</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function">V <span class="title">setValue</span><span class="params">(V value)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object o)</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>AbstractMap中提供了两个Map.Entry的实现,一个可变的SimpleEntry,一个不可变的SimpleImmutableEntry.SimpleEntry的实现非常简单,没有任何难以理解的地方,我们来看下:</p>
<h3 id="SimpleEntry"><a href="#SimpleEntry" class="headerlink" title="SimpleEntry"></a>SimpleEntry</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SimpleEntry</span><<span class="title">K</span>,<span class="title">V</span>> <span class="keyword">implements</span> <span class="title">Entry</span><<span class="title">K</span>,<span class="title">V</span>>, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span></span>{</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"serial"</span>) <span class="comment">// Conditionally serializable</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> K key;</span><br><span class="line"> <span class="meta">@SuppressWarnings</span>(<span class="string">"serial"</span>) <span class="comment">// Conditionally serializable</span></span><br><span class="line"> <span class="keyword">private</span> V value;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">SimpleEntry</span><span class="params">(K key, V value)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.key = key;</span><br><span class="line"> <span class="keyword">this</span>.value = value;</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">SimpleEntry</span><span class="params">(Entry<? extends K, ? extends V> entry)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.key = entry.getKey();</span><br><span class="line"> <span class="keyword">this</span>.value = entry.getValue();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> K <span class="title">getKey</span><span class="params">()</span> </span>{ <span class="keyword">return</span> key;}</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> V <span class="title">getValue</span><span class="params">()</span> </span>{<span class="keyword">return</span> value; }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> V <span class="title">setValue</span><span class="params">(V value)</span> </span>{</span><br><span class="line"> V oldValue = <span class="keyword">this</span>.value;</span><br><span class="line"> <span class="keyword">this</span>.value = value;</span><br><span class="line"> <span class="keyword">return</span> oldValue;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">equals</span><span class="params">(Object o)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (!(o <span class="keyword">instanceof</span> Map.Entry))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> Map.Entry<?,?> e = (Map.Entry<?,?>)o;</span><br><span class="line"> <span class="keyword">return</span> eq(key, e.getKey()) && eq(value, e.getValue());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">hashCode</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> (key == <span class="keyword">null</span> ? <span class="number">0</span> : key.hashCode()) ^</span><br><span class="line"> (value == <span class="keyword">null</span> ? <span class="number">0</span> : value.hashCode());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">toString</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> key + <span class="string">"="</span> + value;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="SimpleImmutableEntry"><a href="#SimpleImmutableEntry" class="headerlink" title="SimpleImmutableEntry"></a>SimpleImmutableEntry</h3><p>和SimpleEntry不同的地方在于setValue方法抛出UnsupportedOperationException异常。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">setValue</span><span class="params">(V value)</span> </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="查询方法实现"><a href="#查询方法实现" class="headerlink" title="查询方法实现"></a>查询方法实现</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//查询操作</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> entrySet().size();<span class="comment">//调用抽象方法实现,set().size()</span></span><br><span class="line">}</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> size() == <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//时间复杂度O(N)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">containsKey</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> <span class="comment">//取出Set的迭代器进行key的查找,</span></span><br><span class="line"> Iterator<Map.Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"> <span class="keyword">if</span> (key==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (e.getKey()==<span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//时间复杂度O(N)</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">containsValue</span><span class="params">(Object value)</span> </span>{</span><br><span class="line"> Iterator<Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"> <span class="keyword">if</span> (value==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (e.getValue()==<span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (value.equals(e.getValue()))</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//这里的get方法实现复杂度是O(N),因为需要遍历整个Entry Set迭代器,这只是</span></span><br><span class="line"><span class="comment">//一种实现方法,如果客户端有更加高效的实现方式,则可以覆写该方法,如HashMap</span></span><br><span class="line"><span class="comment">//的高品质实现,同时因为Map只是定义了接口,并不是实现,Abstract只是定义了</span></span><br><span class="line"><span class="comment">//一种简单的实现,帮助客户端减少实现难度。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> Iterator<Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"> <span class="keyword">if</span> (key==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (e.getKey()==<span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">return</span> e.getValue();</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line"> <span class="keyword">return</span> e.getValue();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h3 id="修改操作方法"><a href="#修改操作方法" class="headerlink" title="修改操作方法"></a>修改操作方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//put方法在这里没有实现,也没有办法实现,正如add方法在AbstractCollection/List/Set中无法实现一样</span></span><br><span class="line"><span class="comment">//因为你不知道放入的数据结构,真正的数据结构定义是在实现类中,如HashMap,TreeMap这里面,</span></span><br><span class="line"><span class="comment">//正是因为抽象类的实现没有引入成员变量,所以放入时候才不会指定特定的存储细节,这也是</span></span><br><span class="line"><span class="comment">//集合框架获得灵活性的重要机制,如果在抽象类中引入了成员变量作为存储结构,那么子类的实现将会</span></span><br><span class="line"><span class="comment">//被束缚在抽象类,此时抽象类将不再抽象,而是一种实现了。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">put</span><span class="params">(K key, V value)</span> </span>{</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> UnsupportedOperationException();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">putAll</span><span class="params">(Map<? extends K, ? extends V> m)</span> </span>{</span><br><span class="line"> <span class="keyword">for</span> (Map.Entry<? extends K, ? extends V> e : m.entrySet())</span><br><span class="line"> put(e.getKey(), e.getValue());</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="comment">//entrySet是抽象方法</span></span><br><span class="line"> entrySet().clear();</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">//删除一个key,其实遍历entrySet,找到key对应的Entry,然后调用迭代器remove方法</span></span><br><span class="line"><span class="comment">//删除该元素</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">remove</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> Iterator<Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"> Entry<K,V> correctEntry = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (key==<span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">while</span> (correctEntry==<span class="keyword">null</span> && i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (e.getKey()==<span class="keyword">null</span>)</span><br><span class="line"> correctEntry = e;</span><br><span class="line"> }</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> <span class="keyword">while</span> (correctEntry==<span class="keyword">null</span> && i.hasNext()) {</span><br><span class="line"> Entry<K,V> e = i.next();</span><br><span class="line"> <span class="keyword">if</span> (key.equals(e.getKey()))</span><br><span class="line"> correctEntry = e;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> V oldValue = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">if</span> (correctEntry !=<span class="keyword">null</span>) {</span><br><span class="line"> oldValue = correctEntry.getValue();</span><br><span class="line"> i.remove();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> oldValue;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h3 id="视图方法"><a href="#视图方法" class="headerlink" title="视图方法"></a>视图方法</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">transient</span> Set<K> keySet;</span><br><span class="line"><span class="keyword">transient</span> Collection<V> values;</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//key的视图是set,因为key不能重复,每个Map只有一个视图,每个视图通过entrySet引用了</span></span><br><span class="line"><span class="comment">//真正Map的元素,可以看出视图实现了AbstractSet.第一次调用时候,keySet视图为空,创建视图。</span></span><br><span class="line"><span class="comment">//第二次调用时候,使用第一次的视图。</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Set<K> <span class="title">keySet</span><span class="params">()</span> </span>{</span><br><span class="line"> Set<K> ks = keySet;</span><br><span class="line"> <span class="keyword">if</span> (ks == <span class="keyword">null</span>) {</span><br><span class="line"> ks = <span class="keyword">new</span> AbstractSet<K>() {</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<K> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Iterator<K>() {</span><br><span class="line"> <span class="keyword">private</span> Iterator<Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i.hasNext();</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//next是key</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> K <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i.next().getKey();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> i.remove();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.size();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.isEmpty();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</span><br><span class="line"> AbstractMap.<span class="keyword">this</span>.clear();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Object k)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.containsKey(k);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> keySet = ks;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> ks;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//因为value可以有重复的,所以使用Collection存储</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Collection<V> <span class="title">values</span><span class="params">()</span> </span>{</span><br><span class="line"> Collection<V> vals = values;</span><br><span class="line"> <span class="keyword">if</span> (vals == <span class="keyword">null</span>) {</span><br><span class="line"> vals = <span class="keyword">new</span> AbstractCollection<V>() {</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Iterator<V> <span class="title">iterator</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Iterator<V>() {</span><br><span class="line"> <span class="keyword">private</span> Iterator<Entry<K,V>> i = entrySet().iterator();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">hasNext</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i.hasNext();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> V <span class="title">next</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> i.next().getValue();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">remove</span><span class="params">()</span> </span>{</span><br><span class="line"> i.remove();</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">size</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.size();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isEmpty</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.isEmpty();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">clear</span><span class="params">()</span> </span>{</span><br><span class="line"> AbstractMap.<span class="keyword">this</span>.clear();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">contains</span><span class="params">(Object v)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> AbstractMap.<span class="keyword">this</span>.containsValue(v);</span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> values = vals;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> vals;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category>JDK源码</category>
<category>Java集合框架</category>
</categories>
<tags>
<tag>java.util.*</tag>
<tag>java collection framework</tag>
</tags>
</entry>
<entry>
<title>SQL-DML练习</title>
<url>/2021/01/31/db-sql-practice/</url>
<content><![CDATA[<ol>
<li><p>找出所有教师名字</p>
<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="keyword">name</span> <span class="keyword">from</span> instructor;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="2">
<li><p>找出所有教师系名</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select dept_name from instructor;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="3">
<li><p>找出所有不重复的系名</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select distinct dept_name from instructor;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="4">
<li><p>找出CS系并且工资超过7000的教师名字</p>
<figure class="highlight sql"><table><tr><td class="code"><pre><span class="line"><span class="keyword">select</span> <span class="keyword">name</span> <span class="keyword">from</span> instructor <span class="keyword">where</span> dept_name=<span class="string">'CS'</span> <span class="keyword">and</span> salary><span class="number">7000</span>;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="5">
<li><p>找出所有教师名字,以及他们所在系的建筑名字</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name,instructor.dept_name,building from instructor,department where instructor.dept_name=department.dept_name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="6">
<li><p>找出CS系的教师名和课程ID</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name,course_id from instructor,teaches where instructor.ID = teaches.ID and instructor.dept_name='CS';</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="7">
<li><p>找出教师的名字和他们所教课的ID</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name,course_id from instructor natural join teaches;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="8">
<li><p>找出教师名字和他们所教课的名字</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name,title from instructor natural join teaches,course where teaches.course_id=course.course_id;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="9">
<li><p>找出 “工资至少比Biology系某一个教师工资要高” 的所有教师名字</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select distinct T.name from instructor as T, instructor as S where T.salary > S.salary and S.dept_name='Biology';</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name from instructor where salary > some(select salary from instructor where dept_name='Biology');</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="10">
<li><p>找出按字母排序在Biology的所有老师</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name from instructor where dept_name='Biology' order by name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="11">
<li><p>找出工资降序,如果工资相同姓名升序的教师</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name from instructor order by salary desc,name asc;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="12">
<li><p>找出工资在9000到10000的教师</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name from instructor where salary between 9000 and 10000;</span><br><span class="line">select name from instructor where salary >= 9000 and salary <= 10000;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="13">
<li><p>找出Biology系授课的所有教师名字和他们所教授的课程</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name,course_id from instructor, teaches where instructor.ID=teaches.ID and dept_name='Biology';</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="14">
<li><p>找出2009年秋季和2010年春季的所有的课程</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">(select course_id from section where semester='Fall' and year=2009) union (select course_id from section where semester='Spring' and year=2010) ;</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line"> </span><br></pre></td></tr></table></figure>
</li>
<li><p>找出2009年秋季和2010年春季的同时开课的课程</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select distinct course_id from section where semester='Spring' and year=2009 and course_id in(select course_id from section where semester='Spring' and year=2010);</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">select course_id from section as S where semester=<span class="string">'Fall'</span> and year=<span class="number">2009</span> <span class="function">and <span class="title">exists</span><span class="params">(select * from section as T where semester=<span class="string">'Spring'</span> and year=<span class="number">2010</span> and S.course_id=T.course_id)</span></span>;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="16">
<li><p>找出在2009年秋季开课和不在2010年春季开课的课程</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select distinct course_id from section where semester='Spring' and year=2009 and course_id not in(select course_id from section where semester='Spring' and year=2010);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="17">
<li><p>找出CS系教师平均工资</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select avg(salary) from instructor where dept_name='CS';</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="18">
<li><p>找出2010春季讲授课程的教师总数</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select count(distinct ID) from teaches where semester='Spring' and year=2010;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="19">
<li><p>找出每个系的平均工资</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select dept_name,avg(salary) from instructor group by dept_name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="20">
<li><p>找出所有老师的平均工资</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select avg(salary) from instructor;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="21">
<li><p>找出每个系在2010年春季讲授一门课程的教师人数</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> dept_name, COUNT(DISTINCT ID)</span><br><span class="line">FROM</span><br><span class="line"> instructor</span><br><span class="line"> NATURAL JOIN</span><br><span class="line"> teaches</span><br><span class="line">WHERE</span><br><span class="line"> semester = 'Spring' AND year = 2010</span><br><span class="line">GROUP BY dept_name;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="22">
<li><p>找出教师平均工资超过42000美元的系</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> dept_name, AVG(salary)</span><br><span class="line">FROM</span><br><span class="line"> instructor</span><br><span class="line">GROUP BY dept_name</span><br><span class="line">HAVING AVG(salary) > 42000;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="23">
<li><p>找出2009年讲授的每个课程段,如果该课程段至少两名学生选课,找出选修该课程段的所有学生总学分的平均值</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> course_id, semester, year, sec_id, AVG(tot_cred)</span><br><span class="line">FROM</span><br><span class="line"> takes</span><br><span class="line"> NATURAL JOIN</span><br><span class="line"> student</span><br><span class="line">WHERE</span><br><span class="line"> year = 2009</span><br><span class="line">GROUP BY course_id , semester , year , sec_id</span><br><span class="line">HAVING COUNT(ID) >= 2;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="24">
<li><p>找出既不叫Bob也不叫Ali的教师名字</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select distinct name from instructor where name not in('Bob','Ali')</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="25">
<li><p>找出不同的学生总数,选修ID为10101教师所教授的课程段</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">SELECT </span><br><span class="line"> COUNT(DISTINCT ID)</span><br><span class="line">FROM</span><br><span class="line"> takes</span><br><span class="line">WHERE</span><br><span class="line"> (course_id , sec_id, year) IN (SELECT </span><br><span class="line"> course_id, sec_id, year</span><br><span class="line"> FROM</span><br><span class="line"> teaches</span><br><span class="line"> WHERE</span><br><span class="line"> teaches.ID = 10101);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="26">
<li><p>找出 “工资比Biology系所有教师工资要高” 的所有教师名字</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select name from instructor where salary > all(select salary from instructor where dept_name='Biology');</span><br></pre></td></tr></table></figure>
</li>
<li><p>找出平均工资大于所有系平均工资的系</p>
<figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">select dept_name from instructor group by dept_name having avg(salary) >= all(select avg(salary) from instructor group by dept_name);</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ol start="28">
<li><p>找出选修了Biology系所开设的所有课程的学生</p>
</li>
<li><p>找出所有在2009年最多开设一次的课程</p>
</li>
<li><p>找出所有在2009年最少开设两次的课程</p>
</li>
<li><p>找出系平均工资超过42000美元的那些系中的教师平均工资</p>
</li>
<li><p>所有系工资总额最大系</p>
</li>
<li><p>所有系和他们拥有的教师数</p>
</li>
<li><p>删除工作在Watson大楼系工作的教师</p>
</li>
<li><p>删除平均工资低于大学平均工资的教师</p>
</li>
<li><p>让CS系修满144学分的学生成为CS系的老师,并且其平均工资为8000</p>
</li>
<li><p>工资低于1000教师工资增加5%</p>
</li>
<li><p>工资低于平均数的教师工资增加5%</p>
</li>
<li><p>工资超过1000教师涨5%,其余增长8%</p>
</li>
<li><p>一个学生在某门课成绩既不是F,也不是空,认为修完了该课程</p>
</li>
<li><p>找出所有课程一门也没选修的学生</p>
</li>
<li><p>找出CS系所有学生以及他们在2009年春季选修的所有课程</p>
</li>
</ol>
<p>其他联系平台</p>
<p><a href="https://www.nowcoder.com/ta/sql" target="_blank" rel="noopener">https://www.nowcoder.com/ta/sql</a></p>
]]></content>
<categories>
<category>数据库</category>
<category>SQL</category>
</categories>
<tags>
<tag>SQL</tag>
</tags>
</entry>
<entry>
<title>分布式事务解决方案</title>
<url>/2022/01/01/distributed-transaction/</url>
<content><![CDATA[<h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>分布式事务划分为两个角度,1是存储层,也即数据库角度的分布式事务,多实现于分布式数据库事务 2是业务层,偏向于服务化系统以及业务系统的分布式事务。</p>
<h1 id="存储层"><a href="#存储层" class="headerlink" title="存储层"></a>存储层</h1><p><a href="https://static.googleusercontent.com/media/research.google.com/zh-CN//archive/spanner-osdi2012.pdf" target="_blank" rel="noopener">spanner</a>,<a href="https://en.wikipedia.org/wiki/X/Open_XA" target="_blank" rel="noopener">XA</a>(<a href="https://en.wikipedia.org/wiki/Two-phase_commit_protocol" target="_blank" rel="noopener">2pc</a>),,<a href="https://en.wikipedia.org/wiki/Three-phase_commit_protocol" target="_blank" rel="noopener">3pc</a>,<a href="https://storage.googleapis.com/pub-tools-public-publication-data/pdf/36726.pdf" target="_blank" rel="noopener">percolator</a>(2pc),<a href="http://cs.yale.edu/homes/thomson/publications/calvin-sigmod12.pdf" target="_blank" rel="noopener">calvin</a>,<a href="https://omid.incubator.apache.org/" target="_blank" rel="noopener">apache omid</a></p>
<table>
<thead>
<tr>
<th>模型</th>
<th>数据模型</th>
<th>并发控制方案</th>
<th>隔离级别支持</th>
<th>限制</th>
</tr>
</thead>
<tbody><tr>
<td>XA</td>
<td>不限</td>
<td>两阶段锁(悲观)</td>
<td>所有隔离级别</td>
<td>加读锁导致性能下降</td>
</tr>
<tr>
<td>Percolator</td>
<td>Key-Value</td>
<td>加锁(悲观) & MVCC</td>
<td>SI</td>
<td></td>
</tr>
<tr>
<td>Omid</td>
<td>Key-Value</td>
<td>冲突检测(乐观) & MVCC</td>
<td>SI</td>
<td></td>
</tr>
<tr>
<td>Calvin</td>
<td>不限</td>
<td>确定性数据库</td>
<td>Serializable</td>
<td>仅适用于One-Shot事务</td>
</tr>
</tbody></table>
<h1 id="业务层"><a href="#业务层" class="headerlink" title="业务层"></a>业务层</h1><p>解决思路有:XA(异构系统),TCC,Saga,基于本地消息的分布式事务,基于事务消息的分布式事务</p>
<p>具体的产品有:seata, hmily, byetcc, easytransaction,XA-JTA(atomikos,bitronix,narayana) ,JOTM, BTM, MSDTC</p>
<h2 id="同构与异构系统"><a href="#同构与异构系统" class="headerlink" title="同构与异构系统"></a>同构与异构系统</h2><p>同构:MySQL Cluster NDB,VoltDB</p>
<p>异构:MySQL和MQ,MySQL和Redis</p>
]]></content>
<categories>
<category>分布式系统</category>
</categories>
<tags>
<tag>分布式事务</tag>
</tags>
</entry>
<entry>
<title>ThreadPoolExecutor设计与实现</title>
<url>/2020/11/10/ThreadPoolExecutor-API-explain/</url>
<content><![CDATA[<p> 线程池是Java并发包中的重要部分,也是高并发程序必不可少的类库,但是线程池技术本身比较复杂,不同语言对其实现提供的抽象也不一样,所以本文以Java线程池为例,分析它的设计与实现,以及它所带我们的抽象。</p>
<h1 id="序言"><a href="#序言" class="headerlink" title="序言"></a>序言</h1><p>我对线程池的认识经历了以下三个阶段</p>
<p>1 会使用Executors的API,觉得很cool,很简单。</p>
<p>2 到配置线程池参数,理解线程池参数,池化资源复用,减少上下文切换,参数关系构成了线程池的执行过程。</p>
<p>3 任务,任务提交,任务执行的抽象理解,从ThreadPoolExecutor到ScheduledThreadPoolExecutor到ForkJoinPool,CompletableFuture的理解。</p>
<p>我现在的理解是:Java并发提供了三个核心抽象概念(<code>任务,任务提交和取消,任务执行</code>),具体来说:</p>
<p>1 <strong>任务</strong> 任务的抽象从Runnable,Callable,FutureTask,到ForkJoinTask 子类RecursiveTask,RecursiveAction,以及CompletableFuture中的Completion对ForkJoinTask 的继承,对AsynchronousCompletionTask的实现。</p>
<p>2 <strong>任务提交和取消</strong> 从ExecutorService到ExecutorCompletionService,实现submit,invoke方法,核心子类:AbstractExecutorService作为骨架实现 </p>
<p>3 <strong>任务执行</strong> 从Executor到核心子类ThreadPoolExecutor(核心方法execute),ForkjoinPool(因为重写了提交机制,所以核心方法submit和execute),ScheduledThreadPoolExecutor也是种执行机制。纯接口包含了命令模式,模板模式,状态机模式等等。这就意味着你可以自定义提交和执行机制。体现了多种策略和实现分别,非常漂亮。</p>
<p>传统的<strong>new Thread(new Runnable).start()</strong> 将任务,任务提交,任务执行耦合起来,也没有提供任务取消的机制,显得那么得不可用,这篇博文主要以分析ThreadPoolExecutor为主,但是站在更高的抽象层次去看,会理解更深。</p>
<h1 id="结构"><a href="#结构" class="headerlink" title="结构"></a>结构</h1><h2 id="任务结构"><a href="#任务结构" class="headerlink" title="任务结构"></a>任务结构</h2><p><img src="/images/JUC-Task-Diagram.png" alt="任务结构"></p>
<p>每个任务都有其抽象的含义,接下来我们将分析每一个接口的类型。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//代表了任务执行没有结果</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//代表了一个任务执行有结果</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Callable</span><<span class="title">V</span>> </span>{</span><br><span class="line"> <span class="function">V <span class="title">call</span><span class="params">()</span> <span class="keyword">throws</span> Exception</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//任务不仅仅被执行,还可以取消,完成,返回结果,Future对任务的抽象比Runnable更加全面,要知道通过原生Thread API</span></span><br><span class="line"><span class="comment">//去取消一个任务是件复杂的事情</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Future</span><<span class="title">V</span>> </span>{</span><br><span class="line"> <span class="comment">//任务可以被中断取消,任务取消能力在Runnable不行的</span></span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">cancel</span><span class="params">(<span class="keyword">boolean</span> mayInterruptIfRunning)</span></span>;</span><br><span class="line"> <span class="comment">//任务是否已经取消</span></span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isCancelled</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="comment">//任务是否完成</span></span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isDone</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="comment">//任务返回结果,获取可能中断,也可能执行异常</span></span><br><span class="line"> <span class="function">V <span class="title">get</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException</span>;</span><br><span class="line"> <span class="comment">//在指定时间内返回结果</span></span><br><span class="line"> <span class="function">V <span class="title">get</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//接口多继承,仅仅是将Runnable和Future的能力结合起来,是一个mixin接口,但是还是强调了run的能力</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">RunnableFuture</span><<span class="title">V</span>> <span class="keyword">extends</span> <span class="title">Runnable</span>, <span class="title">Future</span><<span class="title">V</span>> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">run</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//真正的任务实现是FutureTask,FutureTask的构造对Callable和Runnable进行包装,使得任务成为FutureTask</span></span><br><span class="line"><span class="comment">// ThreadPoolExecutor里面的实际任务是FutureTask</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FutureTask</span><<span class="title">V</span>> <span class="keyword">implements</span> <span class="title">RunnableFuture</span><<span class="title">V</span>> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">FutureTask</span><span class="params">(Callable<V> callable)</span> </span>{<span class="comment">//忽略}</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">FutureTask</span><span class="params">(Runnable runnable, V result)</span> </span>{<span class="comment">//忽略}</span></span><br><span class="line"> <span class="comment">//FutureTask源码在另外博客中会写,这里着重分析结构</span></span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//ForkJoinTask也是一种Future类型任务,其内部提供了AdaptedRunnable,AdaptedCallable的适配类,</span></span><br><span class="line"><span class="comment">//将任务适配成ForkJoinTask</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">ForkJoinTask</span><<span class="title">V</span>> <span class="keyword">implements</span> <span class="title">Future</span><<span class="title">V</span>>, <span class="title">Serializable</span> </span>{}</span><br></pre></td></tr></table></figure>
<p>从上面可以看出,在JUC中,对于任务的抽象其实和任务的执行策略有关系,ThreadPoolExecutor执行的是FutureTask任务,而ScheduledThreadPoolExecutor执行的是ScheduledFutureTask,ForkJoinPool执行的是ForkJoinTask任务,这是多么清晰且统一的设计啊!</p>
<h2 id="任务提交和执行结构"><a href="#任务提交和执行结构" class="headerlink" title="任务提交和执行结构"></a>任务提交和执行结构</h2><img src="/images/Executor-Class-Diagram.png" alt="任务提交"/>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//顶级接口,定义了任务执行,每一个任务是一个Runnable</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Executor</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">execute</span><span class="params">(Runnable command)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>但是仅仅有执行还不行,还要管理任务的取消和生命周期,所以提供了ExecutorService接口,如果说Executor定义了任务执行,</p>
<p>那么ExecutorService提供提交定义了任务的提交和取消,提供了更加完整的任务生命周期的概念,注意到在这层抽象上,我们其实并不知道具体任务是怎么执行的(并行?串行?定期),怎么被提交的,以及怎么返回结果的,真正的实现是具体的实现类。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//Executor提供执行机制,ExecutorService提供提交,取消,完成,等待完成,批量执行任务机制,其中最核心的抽象的提交机制。</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ExecutorService</span> <span class="keyword">extends</span> <span class="title">Executor</span> </span>{</span><br><span class="line"> <span class="comment">//结束</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">shutdown</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="comment">//里面结束,返回没有执行完的任务</span></span><br><span class="line"> <span class="function">List<Runnable> <span class="title">shutdownNow</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isShutdown</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">isTerminated</span><span class="params">()</span></span>;</span><br><span class="line"> <span class="function"><span class="keyword">boolean</span> <span class="title">awaitTermination</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span> <span class="keyword">throws</span> InterruptedException</span>;</span><br><span class="line"> <span class="comment">//提交一个Callable,返回一个加强版的任务,可以获得结果,可以取消,可以判断时候完成</span></span><br><span class="line"> <T> <span class="function">Future<T> <span class="title">submit</span><span class="params">(Callable<T> task)</span></span>;</span><br><span class="line"> <T> <span class="function">Future<T> <span class="title">submit</span><span class="params">(Runnable task, T result)</span></span>;</span><br><span class="line"> Future<?> submit(Runnable task);</span><br><span class="line"> <span class="comment">//提交一批任务,返回所有的完成结果</span></span><br><span class="line"> <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)</span><br><span class="line"> <span class="keyword">throws</span> InterruptedException;</span><br><span class="line"> <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,</span><br><span class="line"> <span class="keyword">long</span> timeout, TimeUnit unit)</span><br><span class="line"> <span class="keyword">throws</span> InterruptedException;</span><br><span class="line"> <span class="comment">//返回任意一个结果</span></span><br><span class="line"> <T> <span class="function">T <span class="title">invokeAny</span><span class="params">(Collection<? extends Callable<T>> tasks)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException, ExecutionException</span>;</span><br><span class="line"> <T> <span class="function">T <span class="title">invokeAny</span><span class="params">(Collection<? extends Callable<T>> tasks,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException</span>;</span><br><span class="line"> <span class="comment">//继承了Executor的execute方法</span></span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">execute</span><span class="params">(Runnable command)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>可以看出,在抽象层,通过一系列接口来完成“任务,任务执行,任务提交和取消”等机制,而接下来章节将分析一种提交和执行机制,线程池,也就是ThreadPoolExecutor.</p>
<h1 id="设计与实现"><a href="#设计与实现" class="headerlink" title="设计与实现"></a>设计与实现</h1><h2 id="ThrealPoolExecutor整体结构"><a href="#ThrealPoolExecutor整体结构" class="headerlink" title="ThrealPoolExecutor整体结构"></a>ThrealPoolExecutor整体结构</h2><img src="/images/ThreadPoolExecutor.png" style="zoom:70%;" />
<h2 id="AbstractExecutorService实现"><a href="#AbstractExecutorService实现" class="headerlink" title="AbstractExecutorService实现"></a>AbstractExecutorService实现</h2><p>AbstractExecutorService仅仅为任务提交提供了骨架的实现,并没有为任务执行和取消提供实现,这也是面向接口设计的一个常用技巧,该类并没有实现Executor的execute方法,因为执行机制属于子类,我们其实可以提供默认实现。但是这样抽象类存在的价值将不是很大。</p>
<p>我们来看一下他的提交机制有哪些?</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//将任务包装成RunnableFuture,实际子类是FutureTask,然后子类(其实就是ThreadPoolExecutor)实现execute执行任务,最后返回执行后的任务</span></span><br><span class="line"><span class="keyword">public</span> Future<?> submit(Runnable task) {</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture<Void> ftask = newTaskFor(task, <span class="keyword">null</span>);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//提交一个FutureTask,子类执行任务</span></span><br><span class="line"><span class="keyword">public</span> <T> <span class="function">Future<T> <span class="title">submit</span><span class="params">(Runnable task, T result)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture<T> ftask = newTaskFor(task, result);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <T> <span class="function">Future<T> <span class="title">submit</span><span class="params">(Callable<T> task)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (task == <span class="keyword">null</span>) <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> RunnableFuture<T> ftask = newTaskFor(task);</span><br><span class="line"> execute(ftask);</span><br><span class="line"> <span class="keyword">return</span> ftask;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//提交一组任务,并且返回所有的任务返回值</span></span><br><span class="line"><span class="keyword">public</span> <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)</span><br><span class="line"> <span class="keyword">throws</span> InterruptedException {</span><br><span class="line"> <span class="keyword">if</span> (tasks == <span class="keyword">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line"> <span class="comment">//存放任务返回值的列表</span></span><br><span class="line"> ArrayList<Future<T>> futures = <span class="keyword">new</span> ArrayList<Future<T>>(tasks.size());</span><br><span class="line"> <span class="keyword">boolean</span> done = <span class="keyword">false</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">for</span> (Callable<T> t : tasks) {</span><br><span class="line"> RunnableFuture<T> f = newTaskFor(t);</span><br><span class="line"> futures.add(f);</span><br><span class="line"> execute(f);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>, size = futures.size(); i < size; i++) {</span><br><span class="line"> Future<T> f = futures.get(i);</span><br><span class="line"> <span class="keyword">if</span> (!f.isDone()) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> f.get();</span><br><span class="line"> } <span class="keyword">catch</span> (CancellationException ignore) {</span><br><span class="line"> } <span class="keyword">catch</span> (ExecutionException ignore) {</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="comment">//任务全部执行完成成功,返回futures</span></span><br><span class="line"> done = <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">return</span> futures;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="comment">//如果没有完成,那么取消所有任务</span></span><br><span class="line"> <span class="keyword">if</span> (!done)</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>, size = futures.size(); i < size; i++)</span><br><span class="line"> futures.get(i).cancel(<span class="keyword">true</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h2 id="FutureTask实现"><a href="#FutureTask实现" class="headerlink" title="FutureTask实现"></a>FutureTask实现</h2><h3 id="任务执行"><a href="#任务执行" class="headerlink" title="任务执行"></a>任务执行</h3><p>该方法实现RunnableFuture,而RunnableFuture接口继承Runnable的run方法,所有本质是任务执行时候的方法。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{}</span><br></pre></td></tr></table></figure>
<h3 id="获取任务结果"><a href="#获取任务结果" class="headerlink" title="获取任务结果"></a>获取任务结果</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">()</span> <span class="keyword">throws</span> InterruptedException, ExecutionException </span>{}</span><br></pre></td></tr></table></figure>
<h3 id="获取有限时间任务结果"><a href="#获取有限时间任务结果" class="headerlink" title="获取有限时间任务结果"></a>获取有限时间任务结果</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> V <span class="title">get</span><span class="params">(<span class="keyword">long</span> timeout, TimeUnit unit)</span></span></span><br><span class="line"><span class="function"> <span class="keyword">throws</span> InterruptedException, ExecutionException, TimeoutException </span>{}</span><br></pre></td></tr></table></figure>
<h3 id="任务取消"><a href="#任务取消" class="headerlink" title="任务取消"></a>任务取消</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">cancel</span><span class="params">(<span class="keyword">boolean</span> mayInterruptIfRunning)</span> </span>{}</span><br></pre></td></tr></table></figure>