-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
2076 lines (1556 loc) · 385 KB
/
index.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge" >
<link rel="dns-prefetch" href="http://yoursite.com">
<title>Hexo</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:locale" content="en_US">
<meta property="article:author" content="John Doe">
<meta name="twitter:card" content="summary">
<link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
<link rel="icon" href="/favicon.png">
<link rel="stylesheet" type="text/css" href="/./main.0cf68a.css">
<style type="text/css">
#container.show {
background: linear-gradient(200deg,#a0cfe4,#e8c37e);
}
</style>
<meta name="generator" content="Hexo 4.2.0"></head>
<body>
<div id="container" q-class="show:isCtnShow">
<canvas id="anm-canvas" class="anm-canvas"></canvas>
<div class="left-col" q-class="show:isShow">
<div class="overlay" style="background: #4d4d4d"></div>
<div class="intrude-less">
<header id="header" class="inner">
<a href="/" class="profilepic">
<img src="" class="js-avatar">
</a>
<hgroup>
<h1 class="header-author"><a href="/">John Doe</a></h1>
</hgroup>
<nav class="header-menu">
<ul>
<li><a href="/">主页</a></li>
<li><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
<nav class="header-smart-menu">
<a q-on="click: openSlider(e, 'innerArchive')" href="javascript:void(0)">所有文章</a>
<a q-on="click: openSlider(e, 'friends')" href="javascript:void(0)">友链</a>
<a q-on="click: openSlider(e, 'aboutme')" href="javascript:void(0)">关于我</a>
</nav>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="#" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="#" title="weibo"><i class="icon-weibo"></i></a>
<a class="rss" target="_blank" href="#" title="rss"><i class="icon-rss"></i></a>
<a class="zhihu" target="_blank" href="#" title="zhihu"><i class="icon-zhihu"></i></a>
</div>
</nav>
</header>
</div>
</div>
<div class="mid-col" q-class="show:isShow,hide:isShow|isFalse">
<nav id="mobile-nav">
<div class="overlay js-overlay" style="background: #4d4d4d"></div>
<div class="btnctn js-mobile-btnctn">
<div class="slider-trigger list" q-on="click: openSlider(e)"><i class="icon icon-sort"></i></div>
</div>
<div class="intrude-less">
<header id="header" class="inner">
<div class="profilepic">
<img src="" class="js-avatar">
</div>
<hgroup>
<h1 class="header-author js-header-author">John Doe</h1>
</hgroup>
<nav class="header-nav">
<div class="social">
<a class="github" target="_blank" href="#" title="github"><i class="icon-github"></i></a>
<a class="weibo" target="_blank" href="#" title="weibo"><i class="icon-weibo"></i></a>
<a class="rss" target="_blank" href="#" title="rss"><i class="icon-rss"></i></a>
<a class="zhihu" target="_blank" href="#" title="zhihu"><i class="icon-zhihu"></i></a>
</div>
</nav>
<nav class="header-menu js-header-menu">
<ul style="width: 50%">
<li style="width: 50%"><a href="/">主页</a></li>
<li style="width: 50%"><a href="/tags/%E9%9A%8F%E7%AC%94/">随笔</a></li>
</ul>
</nav>
</header>
</div>
<div class="mobile-mask" style="display:none" q-show="isShow"></div>
</nav>
<div id="wrapper" class="body-wrap">
<div class="menu-l">
<div class="canvas-wrap">
<canvas data-colors="#eaeaea" data-sectionHeight="100" data-contentId="js-content" id="myCanvas1" class="anm-canvas"></canvas>
</div>
<div id="js-content" class="content-ll">
<article id="post-github" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/04/08/github/">github</a>
</h1>
<a href="/2020/04/08/github/" class="archive-article-date">
<time datetime="2020-04-08T06:23:23.580Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-04-08</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="in"><a href="#in" class="headerlink" title="in"></a>in</h1><p>xxx关键词 in:name 或 description 缩小搜索范围</p>
<p>例如搜索 秒杀项目seckill</p>
<p>seckill in:name,readme,description 代表名字,readme ,描述有seckill关键字</p>
<h1 id="star-fork"><a href="#star-fork" class="headerlink" title="star/fork"></a>star/fork</h1><p>查点赞大于5000的SpringBoot项目</p>
<p>SpringBoot stars:>=5000</p>
<p>查fork大于5000的SpringBoot项目</p>
<p>SpringBoot forks:>=5000</p>
<p>查starts 100到200之间,80到100之间的SpringBoot 项目</p>
<p>SpringBoot stars:100..200 forks 80..100</p>
<h1 id="awesome"><a href="#awesome" class="headerlink" title="awesome"></a>awesome</h1><p>加强搜索,</p>
<p>awesome 关键字</p>
<p>例 awesome redis ,查出redis系列相关东西</p>
<h1 id="L"><a href="#L" class="headerlink" title="#L"></a>#L</h1><p>代表高亮显示第几行</p>
<p>例</p>
<p>github 网址 <a href="https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java" target="_blank" rel="noopener">https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java</a></p>
<p>发给别人的网址是<a href="https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java#L8" target="_blank" rel="noopener">https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java#L8</a></p>
<p>高亮显示第八行</p>
<p><a href="https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java#L8-L15" target="_blank" rel="noopener">https://github.com/JeffLi1993/springboot-learning-example/blob/master/chapter-2-spring-boot-config/src/main/java/demo/springboot/ConfigApplication.java#L8-L15</a></p>
<p>高亮显示弟8到15行</p>
<h1 id="t"><a href="#t" class="headerlink" title="t"></a>t</h1><p>进入项目后点击 t ,变成项目内搜索</p>
<h1 id="location-,language"><a href="#location-,language" class="headerlink" title="location ,language"></a>location ,language</h1><p> 搜索某个语言,某个地方的人</p>
<p>例 location:guangzhou language:java</p>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/04/08/github/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Linux" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/04/07/Linux/">Linux</a>
</h1>
<a href="/2020/04/07/Linux/" class="archive-article-date">
<time datetime="2020-04-07T15:43:33.847Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-04-07</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="Top命令"><a href="#Top命令" class="headerlink" title="Top命令"></a>Top命令</h1><img src="/Users/jiangcheng/blog/source/_posts/Linux/top.png" alt="top" style="zoom:50%;" />
<p>查看进程相关信息</p>
<h5 id="注意Load-Avg"><a href="#注意Load-Avg" class="headerlink" title="注意Load Avg"></a>注意Load Avg</h5><p>这是系统的负载均衡,三个数字分别是 系统1分钟,5分钟,15分钟的平均负载值,如果三个数相加除以3乘以100%高于60%,代表系统压力重</p>
<p>uptime命令行也可以查Load Avg</p>
<h1 id="CPU"><a href="#CPU" class="headerlink" title="CPU"></a>CPU</h1><h5 id="vmstat"><a href="#vmstat" class="headerlink" title="vmstat"></a>vmstat</h5><p>查看全部cpu</p>
<h5 id="字段解释"><a href="#字段解释" class="headerlink" title="字段解释"></a>字段解释</h5><p>procs</p>
<p> :r 运行和等待cpu时间片进程数,原则上1核cpu运行队列不要超过2,整个系统的运行队列不能超过总核数的2倍,否则代表系统压力过大</p>
<p> :b: 等待资源的进程数,比如正在等待磁盘I/O 网络I/O等</p>
<p>cpu</p>
<p> :us 用户进程消耗CPU百分比</p>
<p> :sy 内核进程消耗的CPU时间百分比</p>
<h5 id="pidstat"><a href="#pidstat" class="headerlink" title="pidstat"></a>pidstat</h5><p>每个进程使用cpu的用量分解信息</p>
<p>pidstat -u 1 -p 进程编号</p>
<h1 id="内存"><a href="#内存" class="headerlink" title="内存"></a>内存</h1><h5 id="free"><a href="#free" class="headerlink" title="free"></a>free</h5><p>查看总的内存</p>
<h5 id="pidstat-p-进程号-r-采样间隔时间"><a href="#pidstat-p-进程号-r-采样间隔时间" class="headerlink" title="pidstat-p 进程号 -r 采样间隔时间"></a>pidstat-p 进程号 -r 采样间隔时间</h5><p>查看额外的 </p>
<h1 id="磁盘"><a href="#磁盘" class="headerlink" title="磁盘"></a>磁盘</h1><p>df-h 查看磁盘剩余空间</p>
<h1 id="磁盘IO"><a href="#磁盘IO" class="headerlink" title="磁盘IO"></a>磁盘IO</h1><p>iostat 磁盘 io性能评估</p>
<h1 id="网络IO"><a href="#网络IO" class="headerlink" title="网络IO"></a>网络IO</h1><p>Ifstat</p>
<h1 id="如果CPU占用过高,怎么分析和解决"><a href="#如果CPU占用过高,怎么分析和解决" class="headerlink" title="如果CPU占用过高,怎么分析和解决"></a>如果CPU占用过高,怎么分析和解决</h1><p>1 先用top命令查出cpu占比最高</p>
<p>2 ps -ef或 jps进一步定位</p>
<p>3 定位到具体线程或代码</p>
<p> ps -mp 进程 -o THREAD,tid,time;</p>
<p>4 将需要的线程ID转换为16进制 格式 (小写英文格式) (可以用计算机把ID转换为16进制)</p>
<p>5 jstack 进程ID | grep tid(16进制的线程IO小写英文) -A60 (输出前60行信息)</p>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/04/07/Linux/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-Mysql" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/02/20/Mysql/">Mysql</a>
</h1>
<a href="/2020/02/20/Mysql/" class="archive-article-date">
<time datetime="2020-02-20T02:25:22.329Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-02-20</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="数据库模块划分"><a href="#数据库模块划分" class="headerlink" title="数据库模块划分"></a>数据库模块划分</h1><p>存储管理 缓存机制 SQL解析 日志管理 权限划分 容灾机制 索引管理 锁管理</p>
<h1 id="索引"><a href="#索引" class="headerlink" title="索引"></a>索引</h1><p>为什么要使用索引 快速查找</p>
<p>什么样信息可以做索引 主键 唯一键,普通键等</p>
<h3 id="索引结构"><a href="#索引结构" class="headerlink" title="索引结构"></a>索引结构</h3><h4 id="二叉查找树"><a href="#二叉查找树" class="headerlink" title="二叉查找树"></a>二叉查找树</h4><p>为什么底层数据结构不用二叉查找树。 </p>
<p> 因为当进行全表扫描的时候,树的深度很深,会进行多次IO 开销很大,</p>
<h4 id="B树"><a href="#B树" class="headerlink" title="B树"></a>B树</h4><img src="/Users/jiangcheng/Library/Application Support/typora-user-images/截屏2020-03-08下午10.00.43.png" alt="截屏2020-03-08下午10.00.43" style="zoom:50%;" />
<p>根节点至少有两个孩子</p>
<p>树中每个节点最多含有m个孩子(m>=2)</p>
<p>除根节点和叶节点外,其他每个节点至少有ceil(m/2)个孩子</p>
<p>所有叶子节点在同一层</p>
<p>假设每个非终端结点中包含有n个关键字信息,其中</p>
<p>a Ki(i=1….n)为关键字,且关键字安顺序升序排序 K(i-1)<Ki</p>
<p>b 关键字的个数n必须满足:[ceil(m/2)-1]<=n<=m-1</p>
<p>c 非叶子节点指针:P[1],P[2],…P[M]; 其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1],K[i])的子树</p>
<h4 id="B-树"><a href="#B-树" class="headerlink" title="B+ 树"></a>B+ 树</h4><p></p>
<p>非叶子结点的子树指针与关键字个数相同</p>
<p>非叶子结点的子树指针p[i],指向关键字值[k[i],k[i+1]]的子树</p>
<p>非叶子结点仅用来索引,数据都保存在叶子节点中</p>
<p>所有叶子节点均有一个链指针指向下一个叶子节点</p>
<p>B+树比B树更适合做存储索引原因</p>
<p>B+树磁盘读写代价更低</p>
<p>B+树查询效率更稳定</p>
<p>B+树更有利于对数据库扫描</p>
<h4 id="Hash索引"><a href="#Hash索引" class="headerlink" title="Hash索引"></a>Hash索引</h4><p>优点 查询效率高</p>
<p>缺点 仅仅满足 “=”,“IN”,不能范围查询</p>
<p>无法用来避免数据排序操作</p>
<p>不能利用部分索引查询</p>
<p>不能避免表扫描</p>
<p>大量Hash值相等的情况 不一定比B树高</p>
<h1 id="相关面试题"><a href="#相关面试题" class="headerlink" title="相关面试题"></a>相关面试题</h1><h4 id="数据库乐观锁悲观锁具体是什么,写一个典型的乐观锁SQL语句,有什么需要注意的问题?"><a href="#数据库乐观锁悲观锁具体是什么,写一个典型的乐观锁SQL语句,有什么需要注意的问题?" class="headerlink" title="数据库乐观锁悲观锁具体是什么,写一个典型的乐观锁SQL语句,有什么需要注意的问题?"></a>数据库乐观锁悲观锁具体是什么,写一个典型的乐观锁SQL语句,有什么需要注意的问题?</h4><h4 id="数据库隔离级别,什么是脏读,幻读,怎么造成的?"><a href="#数据库隔离级别,什么是脏读,幻读,怎么造成的?" class="headerlink" title="数据库隔离级别,什么是脏读,幻读,怎么造成的?"></a>数据库隔离级别,什么是脏读,幻读,怎么造成的?</h4><p><strong>select @@tx_isolation</strong> 查看事务隔离级别</p>
<p>set session transaction isolation level xxxxx 更改隔离级别</p>
<p>隔离级别 </p>
<table>
<thead>
<tr>
<th>事务隔离级别</th>
<th>更新丢失</th>
<th>脏读</th>
<th>不可重复读</th>
<th>幻读</th>
</tr>
</thead>
<tbody><tr>
<td>未提交读read uncommitted</td>
<td>避免</td>
<td>发生</td>
<td>发生</td>
<td>发生</td>
</tr>
<tr>
<td>已提交读read committed</td>
<td>避免</td>
<td>避免</td>
<td>发生</td>
<td>发生</td>
</tr>
<tr>
<td>可重复读REPEATABLE READ</td>
<td>避免</td>
<td>避免</td>
<td>避免</td>
<td>发生</td>
</tr>
<tr>
<td>串行化SERIALIZABLE</td>
<td>避免</td>
<td>避免</td>
<td>避免</td>
<td>避免</td>
</tr>
</tbody></table>
<p><strong>脏读</strong>:当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。</p>
<p><strong>不可重复读</strong>:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复</p>
<p><strong>幻读</strong>:指当事务不是独立执行时发生的一种现象,例如 第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好像发生了幻觉一样。</p>
<h4 id="InnoDB可重复读隔离级别下如何避免幻读"><a href="#InnoDB可重复读隔离级别下如何避免幻读" class="headerlink" title="InnoDB可重复读隔离级别下如何避免幻读"></a>InnoDB可重复读隔离级别下如何避免幻读</h4><p>表象: 快照读</p>
<p>内在: </p>
<h4 id="mysql的引擎"><a href="#mysql的引擎" class="headerlink" title="mysql的引擎"></a>mysql的引擎</h4><p><strong>MyISAM存储引擎</strong> 不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表</p>
<p><strong>InnoDB存储引擎</strong> 该存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比MyISAM引擎,写的处理效率会差一些,并且会占用更多的磁盘空间以保留数据和索引。<br>InnoDB存储引擎的特点:支持自动增长列,支持外键约束</p>
<p><strong>MEMORY存储引擎</strong> </p>
<p>Memory存储引擎使用存在于内存中的内容来创建表。每个memory表只实际对应一个磁盘文件,格式是.frm。memory类型的表访问非常的快,因为它的数据是放在内存中的,并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失掉。</p>
<p><strong>MERGE存储引擎</strong></p>
<p>Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。</p>
<h4 id="Innodb和myisam的区别"><a href="#Innodb和myisam的区别" class="headerlink" title="Innodb和myisam的区别"></a>Innodb和myisam的区别</h4><p><img src="/Users/jiangcheng/Desktop/java/%E5%B0%8F%E7%BA%B8%E4%BA%BA2019%E7%A7%8B%E6%8B%9B%E5%87%86%E5%A4%87%E8%B5%84%E6%96%99/%E5%B0%8F%E7%BA%B8%E4%BA%BA2019%E7%A7%8B%E6%8B%9B%E5%87%86%E5%A4%87/MySQL/images/4.JPG" alt="4"></p>
<h4 id="为什么MyISAM-查询要比-InnoDB-要快"><a href="#为什么MyISAM-查询要比-InnoDB-要快" class="headerlink" title="为什么MyISAM 查询要比 InnoDB 要快"></a>为什么MyISAM 查询要比 InnoDB 要快</h4><p>INNODB在做SELECT的时候,要维护的东西比MYISAM引擎多很多;</p>
<p> 1)数据块,INNODB要缓存,MYISAM只缓存索引块, 这中间还有换进换出的减少;<br> 2)innodb寻址要映射到块,再到行,MYISAM 记录的直接是文件的OFFSET,定位比INNODB要快<br> 3)INNODB还需要维护MVCC一致;虽然你的场景没有,但他还是需要去检查和维护</p>
<p>MVCC ( Multi-Version Concurrency Control )多版本并发控制</p>
<p>InnoDB:<strong>通过为每一行记录添加两个额外的隐藏的值来实现MVCC</strong>,这两个值一个记录这行数据<strong>何时被创建</strong>,另外一个记录这行<strong>数据何时过期(或者被删除)。</strong>但是InnoDB并不存储这些事件发生时的实际时间,相反它只存储这些事件发生时的系统版本号。这是一个随着事务的创建而不断增长的数字。每个事务在事务开始时会记录它自己的系统版本号。每个查询必须去检查每行数据的版本号与事务的版本号是否相同。让我们来看看当隔离级别是REPEATABLE READ时这种策略是如何应用到特定的操作的:</p>
<h5 id="应用场景选择"><a href="#应用场景选择" class="headerlink" title="应用场景选择"></a>应用场景选择</h5><ul>
<li>MyISAM管理<strong>非事务表</strong>。它提供<strong>高速存储和检索</strong>,以及<strong>全文搜索能力</strong>。如果应用中需要执行<strong>==大量的SELECT查询和频繁全表count,没有事务==</strong>,那么MyISAM是更好的选择。</li>
<li>InnoDB用于事务处理应用程序,具有众多特性,包括<strong>ACID事务支持</strong>。如果应用中需要<strong>==执行大量的INSERT或UPDATE操作,可靠性要求高==,则应该使用InnoDB</strong>,这样可以提高多用户<strong>并发操作的性能</strong>。</li>
</ul>
<h4 id="索引底层原理-B-为什么不用B"><a href="#索引底层原理-B-为什么不用B" class="headerlink" title="索引底层原理 B+为什么不用B-"></a>索引底层原理 B+为什么不用B-</h4><ol>
<li>单一节点存储更多的元素,使得查询的IO次数更少。</li>
<li>所有查询都要查找到叶子节点,查询性能稳定。</li>
<li>所有叶子节点形成有序链表,便于范围查询。(底部有链表)</li>
<li>B+树还有一个最大的好处,<strong>方便扫库</strong>,<strong>B树必须用中序遍历的方法按序扫库,而B+树直接从叶子结点挨个扫一遍就完了</strong>,<strong>B+树支持range-query非常方便</strong>,而B树不支持。这是==数据库选用B+树的最主要原因==。</li>
</ol>
<h4 id="mysql调优"><a href="#mysql调优" class="headerlink" title="mysql调优"></a>mysql调优</h4><h4 id="join-和-in-怎么选择?有什么区别?"><a href="#join-和-in-怎么选择?有什么区别?" class="headerlink" title="join 和 in 怎么选择?有什么区别?"></a>join 和 in 怎么选择?有什么区别?</h4><h4 id="union-和-union-all-有什么区别?怎么选择?"><a href="#union-和-union-all-有什么区别?怎么选择?" class="headerlink" title="union 和 union all 有什么区别?怎么选择?"></a>union 和 union all 有什么区别?怎么选择?</h4><h4 id="如何定位优化-sql-慢查询?"><a href="#如何定位优化-sql-慢查询?" class="headerlink" title="如何定位优化 sql 慢查询?"></a>如何定位优化 sql 慢查询?</h4><p>1 根据慢日志定位慢查询sql</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">show</span> <span class="keyword">VARIABLES</span> <span class="keyword">LIKE</span> <span class="string">'%quer%'</span></span><br></pre></td></tr></table></figure>
<p></p>
<p>查看慢查询的条数</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">show</span> <span class="keyword">status</span> <span class="keyword">like</span> <span class="string">'%slow_queries%'</span>;</span><br></pre></td></tr></table></figure>
<p>2 使用explain 工具分析sql</p>
<p> Explain 关键字 </p>
<ul>
<li>type 查询类型 出现all 和index 就要优化</li>
<li>extra 出现 Using filesort 使用了外部索引排序 Using temporary 使用了临时表常见于order by和group by 要优化</li>
</ul>
<p>3 修改sql或者让sql走索引</p>
<h4 id="跨库分页的实现?"><a href="#跨库分页的实现?" class="headerlink" title="跨库分页的实现?"></a>跨库分页的实现?</h4><h4 id="分库分表有哪些策略?怎么保证-id-唯一?"><a href="#分库分表有哪些策略?怎么保证-id-唯一?" class="headerlink" title="分库分表有哪些策略?怎么保证 id 唯一?"></a>分库分表有哪些策略?怎么保证 id 唯一?</h4><h4 id="主键选随机-id、uuid-还是自增-id?为什么?主键有序无序对数据库的影响?"><a href="#主键选随机-id、uuid-还是自增-id?为什么?主键有序无序对数据库的影响?" class="headerlink" title="主键选随机 id、uuid 还是自增 id?为什么?主键有序无序对数据库的影响?"></a>主键选随机 id、uuid 还是自增 id?为什么?主键有序无序对数据库的影响?</h4><h4 id="主从复制的过程?复制原理?怎么保证强一致性?"><a href="#主从复制的过程?复制原理?怎么保证强一致性?" class="headerlink" title="主从复制的过程?复制原理?怎么保证强一致性?"></a>主从复制的过程?复制原理?怎么保证强一致性?</h4><h4 id="为什么要用B-树而不用HashTable?B-树的优缺点?"><a href="#为什么要用B-树而不用HashTable?B-树的优缺点?" class="headerlink" title="为什么要用B+树而不用HashTable?B+树的优缺点?"></a>为什么要用B+树而不用HashTable?B+树的优缺点?</h4><h4 id="事务的特性(ACID),详细说明各个特性的含义"><a href="#事务的特性(ACID),详细说明各个特性的含义" class="headerlink" title="事务的特性(ACID),详细说明各个特性的含义"></a>事务的特性(ACID),详细说明各个特性的含义</h4><p>原子性:是指事务包含的所有操作要么全部成功,要么全部失败回滚。失败回滚的操作事务,将不能对事物有任何影响</p>
<p>一致性:是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态,满足完整性约束。</p>
<ol>
<li><strong>一致读</strong> 事务读取数据只能从一个状态中读取,不能从2个或者2个以上状态读取。也就是T(n)只能从C(n-1),C(n-2)… C(1)中的一个状态读取数据,不能一部分数据读取自C(n-1),而另一部分数据读取自C(n-2)。</li>
<li><strong>一致写</strong> 事务执行的数据变更只能基于上一个一致的状态,且只能体现在一个状态中。T(n)的变更结果只能基于C(n-1),C(n-2), …C(1)状态,且只能体现在C(n)状态中。也就是说,一个状态只能有一个事务变更数据,不允许有2个或者2个以上事务在一个状态中变更数据。至于具体一致写基于哪个状态,需要判断T(n)事务是否和T(n-1),T(n-2),…T(1)有依赖关系。</li>
</ol>
<p>隔离性:隔离性是指当多个用户并发访问数据库时,比如同时访问一张表,数据库每一个用户开启的事务,不能被其他事务所做的操作干扰,多个并发事务之间,应当相互隔离。<br>例如同时有T1和T2两个并发事务,从T1角度来看,T2要不在T1执行之前就已经结束,要么在T1执行完成后才开始。将多个事务隔离开,每个事务都不能访问到其他事务操作过程中的状态。(一个事务执行,不能引响别的事务执行)</p>
<p>持久性:是指事务的操作,一旦提交,对于数据库中数据的改变是永久性的,即使数据库发生故障也不能丢失已提交事务所完成的改变。</p>
<h4 id="聚簇索引和非聚簇索引的区别"><a href="#聚簇索引和非聚簇索引的区别" class="headerlink" title="聚簇索引和非聚簇索引的区别"></a>聚簇索引和非聚簇索引的区别</h4><h4 id="B树和B-树的区别"><a href="#B树和B-树的区别" class="headerlink" title="B树和B+树的区别"></a>B树和B+树的区别</h4><h4 id="密集索引和稀疏索引的区别"><a href="#密集索引和稀疏索引的区别" class="headerlink" title="密集索引和稀疏索引的区别"></a>密集索引和稀疏索引的区别</h4><p>innodb用密集索引 表和数据存储在一起ibd</p>
<p>myisam 用稀疏索引 表和数据分开存储 数据保存在myd文件中 索引在myi</p>
<p>所以myisam读取更快,数据单独存放在指定文件</p>
<h4 id="索引最左匹配原则"><a href="#索引最左匹配原则" class="headerlink" title="索引最左匹配原则"></a>索引最左匹配原则</h4><p>1 mysql 会一直向右匹配,直到遇到范围查询 (>,<,between,like)就停止匹配 ,比如a=3 and b=4 and c>5 and d=6 如果建立索引(a,b,c,d)顺序,则d用不到索引,如果建立(a,b,d,c) 则a,b,d顺序可以随意调整</p>
<p>2 =和in可以乱序,比如a=3 and b=4 and c=5 建立索引(a,b,c)可以在任意顺序,mysql查询优化器会帮你优化索引可以识别的形式</p>
<h4 id="索引是建立越多越好吗"><a href="#索引是建立越多越好吗" class="headerlink" title="索引是建立越多越好吗"></a>索引是建立越多越好吗</h4><p>数据量小的表不需要索引 ,建立会增加额外的索引开销</p>
<p>数据变更需要维护索引,因为更多索引意味着更多维护成本</p>
<p>更多索引意味着也需要更多空间</p>
<h4 id="索引的优势劣势"><a href="#索引的优势劣势" class="headerlink" title="索引的优势劣势"></a>索引的优势劣势</h4><p>优点:创建索引可以大大提高系统的性能:<br> 第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。<br> 第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。<br> 第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。<br> 第四,在使用分组和排序 子句进行<a href="https://www.baidu.com/s?wd=%E6%95%B0%E6%8D%AE%E6%A3%80%E7%B4%A2&tn=SE_PcZhidaonwhc_ngpagmjz&rsv_dl=gh_pc_zhidao" target="_blank" rel="noopener">数据检索</a>时,同样可以显著减少查询中分组和排序的时间。<br> 第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。 </p>
<p>缺点:</p>
<p> 第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。<br> 第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。<br> 第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。 </p>
<h4 id="锁的分类"><a href="#锁的分类" class="headerlink" title="锁的分类"></a>锁的分类</h4><p>按锁的粒度划分 :</p>
<ul>
<li>表级锁</li>
<li>行级锁</li>
<li>页级锁(BDB引擎)</li>
</ul>
<p>按锁级别划分:</p>
<ul>
<li>共享锁 </li>
<li>排他锁</li>
</ul>
<p>按加锁方式划分 </p>
<ul>
<li>自动锁(Myisam在insert delete) </li>
<li>显示锁(lock share mode)</li>
</ul>
<p>按操作划分 </p>
<ul>
<li>DML锁 (对数据操作)</li>
<li>DDL锁(对表结构操作)</li>
</ul>
<p>按使用方式划分 </p>
<ul>
<li><p>乐观锁(认为数据不会造成冲突,不会使用数据库的锁机制,实现要使用时间戳,或者基于数据版本) </p>
</li>
<li><p>悲观锁(对数据,对外界事务处理,持有悲观状态,加锁,如全程排他锁控制,效率低)</p>
</li>
</ul>
<p>读写锁,行锁,表锁。</p>
<p>读锁(共享锁):针对同一份数据,多个读操作之间同时进行 不会有任何的影响</p>
<p>写锁(排它锁):当前操作没有完成的时候,他会阻断其他的写锁和读锁。</p>
<p>表锁(偏读)</p>
<p>行锁(偏写)</p>
<h4 id="MyISAM与InnoDB关于锁方面的区别什么"><a href="#MyISAM与InnoDB关于锁方面的区别什么" class="headerlink" title="MyISAM与InnoDB关于锁方面的区别什么"></a>MyISAM与InnoDB关于锁方面的区别什么</h4><p>MyISAM默认是表级锁,不支持行级锁 当进行select 自动加上表级别的读锁,进行更新的时候加上表级别的写锁。读锁也叫共享锁</p>
<p>InnoDB默认是行级锁,也支持表级锁</p>
<ul>
<li>注意innoDb 没用索引的时候是表级锁,用索引之后是行级锁</li>
</ul>
<table>
<thead>
<tr>
<th></th>
<th>排他锁 (写锁)</th>
<th>共享锁 (读锁)</th>
</tr>
</thead>
<tbody><tr>
<td>排他锁</td>
<td>冲突</td>
<td>冲突</td>
</tr>
<tr>
<td>共享锁</td>
<td>冲突</td>
<td>兼容</td>
</tr>
</tbody></table>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/02/20/Mysql/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-java容器和基础知识" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/02/20/java%E5%AE%B9%E5%99%A8%E5%92%8C%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/">java容器和基础知识</a>
</h1>
<a href="/2020/02/20/java%E5%AE%B9%E5%99%A8%E5%92%8C%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/" class="archive-article-date">
<time datetime="2020-02-20T02:25:22.329Z" itemprop="datePublished"><i class="icon-calendar icon"></i>2020-02-20</time>
</a>
</header>
<div class="article-entry" itemprop="articleBody">
<h1 id="java要传接口也不是具体的类,要面向对象"><a href="#java要传接口也不是具体的类,要面向对象" class="headerlink" title="java要传接口也不是具体的类,要面向对象"></a>java要传接口也不是具体的类,要面向对象</h1><h1 id="java基础知识"><a href="#java基础知识" class="headerlink" title="java基础知识"></a>java基础知识</h1><h5 id="volatile关键字的作用和原理"><a href="#volatile关键字的作用和原理" class="headerlink" title="volatile关键字的作用和原理"></a>volatile关键字的作用和原理</h5><ol>
<li>保持内存可见性</li>
<li>防止指令重排序。</li>
<li>不保证原子性</li>
</ol>
<ul>
<li>如何保持内存可见性</li>
</ul>
<p>每次读取前必须先从主内存刷新最新的值</p>
<p>每次写入后必须立即同步回主内存当中。</p>
<ul>
<li>如何解决不保证原子性问题<ol>
<li>加sync</li>
<li>使用juc下的AtomicInteger</li>
</ol>
</li>
</ul>
<p><strong>volatile关键字修饰的变量看到的随时是自己的最新值</strong>。</p>
<p>防止指令重排 </p>
<h5 id="加入Memory-Barrier内存栅栏作用"><a href="#加入Memory-Barrier内存栅栏作用" class="headerlink" title="加入Memory Barrier内存栅栏作用"></a>加入Memory Barrier内存栅栏作用</h5><ol>
<li>保证特点操作执行顺序</li>
<li>保证某些变量的内存可见性</li>
</ol>
<h5 id="类和对象区别"><a href="#类和对象区别" class="headerlink" title="类和对象区别"></a>类和对象区别</h5><p>类是对象的抽象,对象是类的具体实例。</p>
<p>类是抽象的,不占用内存,而对象是具体的,占有内存空间。</p>
<h5 id="说一下hashcode"><a href="#说一下hashcode" class="headerlink" title="说一下hashcode"></a>说一下hashcode</h5><p>独一无二代表一个对象,可以通过这个哈希编码找个这个对象</p>
<h5 id="重载和重写的区别"><a href="#重载和重写的区别" class="headerlink" title="重载和重写的区别"></a>重载和重写的区别</h5><p>重写:子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以<strong>在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下,</strong> 对方法体进行修改或重写,这就是重写。但要注意<strong>子类函数的访问修饰权限不能少于父类的</strong></p>
<p>重载</p>
<p>在一个类中,同名的方法如果有不同的参数列表(<strong>参数类型不同、参数个数不同甚至是参数顺序不同</strong>)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但<strong>不能通过返回类型是否相同来判断重载</strong></p>
<h5 id="amp-amp-与-amp-,-与-的区别"><a href="#amp-amp-与-amp-,-与-的区别" class="headerlink" title="&&与&,||与|的区别"></a>&&与&,||与|的区别</h5><p>&& 逻辑与,有短路特性 只要第一个条件不满足,后面就不判断</p>
<p>|| 逻辑或,有短路特性 只要第一个条件满足,后面就不判断</p>
<p>& 可以当运算符号 当1&1=1 也可以当判断条件,要对所有的条件都进行判断。</p>
<p>| 可以当运算符合 1|0=1 也可以当判断条件,要对所有的条件都进行判断。</p>
<h5 id="为什么重写了equals还是重写hashcode"><a href="#为什么重写了equals还是重写hashcode" class="headerlink" title="为什么重写了equals还是重写hashcode"></a>为什么重写了equals还是重写hashcode</h5><p>hashcode返回对象的内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样</p>
<p>String类的hashCode:根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串内容相同,返回的哈希码也相同。</p>
<p>首先,hashmap的key的值是不能相同的,如果新建两个对象,则他们的hashcode是不同的</p>
<p>如</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">T a = <span class="keyword">new</span> T(<span class="number">1</span>);</span><br><span class="line">T b = <span class="keyword">new</span> T(<span class="number">1</span>);</span><br><span class="line"><span class="comment">//并且结果也为false</span></span><br><span class="line">a.equals(b)</span><br></pre></td></tr></table></figure>
<p>因此,这两个对象都可以put进去hashmap。</p>
<p>但是hashmap的性质是,当key的值相同的时候,后一面key会覆盖前面一个key。</p>
<p>但是b对象并没有覆盖a,所以要重写equals函数 令a.equals(b)==true;</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><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 obj)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span> == obj)</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 class="keyword">if</span> (!(obj <span class="keyword">instanceof</span> T)) {</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> T other = (T) obj;</span><br><span class="line"> Integer data1 = <span class="keyword">this</span>.getA();</span><br><span class="line"> Integer data2 = ((T) obj).getA();</span><br><span class="line"> <span class="keyword">if</span> (data1 == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">if</span> (data2 != <span class="keyword">null</span>) {</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 class="keyword">else</span> <span class="keyword">if</span> (!data1.equals(data2)){</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="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line"> }</span><br><span class="line"><span class="comment">//重写后a.equals(b)==true。</span></span><br></pre></td></tr></table></figure>
<p>但是hashmap在存储a和b对象的时候,它是存的两份的,在它看来,<code>这两个的key是不一样的,因为它们的哈希码就是不一样的</code>,尽管他们的值相同。Map中存了两个数值一样的key,这个问题很严重。所以要重写hashcode方法来返回,令相同值的key,返回相同的hashCode。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><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">boolean</span> PRIME = <span class="keyword">true</span>;</span><br><span class="line"> <span class="keyword">byte</span> result = <span class="number">1</span>;</span><br><span class="line"> Integer a = <span class="keyword">this</span>.getA();</span><br><span class="line"> <span class="keyword">int</span> result1 = result * <span class="number">59</span> + (a == <span class="keyword">null</span> ? <span class="number">43</span> : a.hashCode());</span><br><span class="line"> <span class="keyword">return</span> result1;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>重写hashCode后,相同key的值,会覆盖前一个key,这样就保证了key的唯一性</p>
<p>所以在重写equals方法的时候,一定要重写hashCode方法。</p>
<h5 id="为什么String是不可变的"><a href="#为什么String是不可变的" class="headerlink" title="为什么String是不可变的"></a>为什么String是不可变的</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><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">String</span></span></span><br><span class="line"><span class="class"> <span class="keyword">implements</span> <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Comparable</span><<span class="title">String</span>>, <span class="title">CharSequence</span> </span>{</span><br><span class="line"> <span class="comment">/** The value is used for character storage. */</span></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">char</span> value[];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ol>
<li>String 被 final 修饰,说明 String 类绝不可能被继承了,也就是说任何对 String 的操作方法,都不会被继承覆写;</li>
<li>String 中保存数据的是一个 char 的数组 value。我们发现 value 也是被 final 修饰的,也就是说 value 一旦被赋值,内存地址是绝对无法修改的,而且 value 的权限是 private 的,外部绝对访问不到,String 也没有开放出可以对 value 进行赋值的方法,所以说 value 一旦产生,内存地址就根本无法被修改。</li>
</ol>
<h5 id="string的equals-源码"><a href="#string的equals-源码" class="headerlink" title="string的equals 源码"></a>string的equals 源码</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><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 anObject)</span> </span>{</span><br><span class="line"> <span class="comment">// 判断内存地址是否相同</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span> == anObject) {</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="comment">// 待比较的对象是否是 String,如果不是 String,直接返回不相等</span></span><br><span class="line"> <span class="keyword">if</span> (anObject <span class="keyword">instanceof</span> String) {</span><br><span class="line"> String anotherString = (String)anObject;</span><br><span class="line"> <span class="keyword">int</span> n = value.length;</span><br><span class="line"> <span class="comment">// 两个字符串的长度是否相等,不等则直接返回不相等</span></span><br><span class="line"> <span class="keyword">if</span> (n == anotherString.value.length) {</span><br><span class="line"> <span class="keyword">char</span> v1[] = value;</span><br><span class="line"> <span class="keyword">char</span> v2[] = anotherString.value;</span><br><span class="line"> <span class="keyword">int</span> i = <span class="number">0</span>;</span><br><span class="line"> <span class="comment">// 依次比较每个字符是否相等,若有一个不等,直接返回不相等</span></span><br><span class="line"> <span class="keyword">while</span> (n-- != <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">if</span> (v1[i] != v2[i])</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line"> i++;</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><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>
<h5 id="为什么使用-Long-时,大家推荐多使用-valueOf-方法,少使用-parseLong-方法"><a href="#为什么使用-Long-时,大家推荐多使用-valueOf-方法,少使用-parseLong-方法" class="headerlink" title="为什么使用 Long 时,大家推荐多使用 valueOf 方法,少使用 parseLong 方法"></a>为什么使用 Long 时,大家推荐多使用 valueOf 方法,少使用 parseLong 方法</h5><p>因为 Long 本身有缓存机制,缓存了 -128 到 127 范围内的 Long,valueOf 方法会从缓存中去拿值,如果命中缓存,会减少资源的开销,parseLong 方法就没有这个机制。</p>
<h5 id="java8新特性"><a href="#java8新特性" class="headerlink" title="java8新特性"></a>java8新特性</h5><h6 id="Lambda表达式"><a href="#Lambda表达式" class="headerlink" title="Lambda表达式"></a>Lambda表达式</h6><p>Lambda操作符是-> </p>
<ul>
<li>操作符左侧 指定了 Lambda 表达式需要的所有参数</li>
<li>操作符右侧 指定了 Lambda 体,即 Lambda 表达式要执行 的功能。</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">Runnable runnable=<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"hello"</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">Runnable runnable= () -> System.out.println(<span class="string">"hello"</span>);</span><br><span class="line"></span><br><span class="line">TreeSet<String> treeSet=<span class="keyword">new</span> TreeSet<>(<span class="keyword">new</span> Comparator<String>() {</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">int</span> <span class="title">compare</span><span class="params">(String o1, String o2)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> Integer.compare(o1.length(),o2.length());</span><br><span class="line"> }</span><br><span class="line"> });</span><br><span class="line"><span class="comment">//等价于</span></span><br><span class="line">TreeSet<String> treeSet=<span class="keyword">new</span> TreeSet<>((o1, o2) -> Integer.compare(o1.length(),o2.length()));</span><br><span class="line"></span><br><span class="line">TreeSet<String> treeSet=<span class="keyword">new</span> TreeSet<>(Comparator.comparingInt(String::length));</span><br></pre></td></tr></table></figure>
<h6 id="final相关"><a href="#final相关" class="headerlink" title="final相关"></a>final相关</h6><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><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="keyword">int</span> num=<span class="number">0</span>;</span><br><span class="line"> Runnable runnable=<span class="keyword">new</span> Runnable() {</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">run</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(num); </span><br><span class="line"> }</span><br><span class="line"> };</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>jdk1.7之前,匿名内部类使用外部变量则外部变量必须变为final,即不可变化<br>在1.8之后,final可省略,但是实际上final还是存在的,在runable内部++num还是报错。</p>
<h6 id="函数式接口"><a href="#函数式接口" class="headerlink" title="函数式接口"></a>函数式接口</h6><ul>
<li><p>只包含一个抽象方法的接口,称为函数式接口。</p>
</li>
<li><p>可以通过 Lambda 表达式来创建该接口的对象。(若 Lambda<br>表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方<br>法上进行声明)。</p>
</li>
<li><p>可以在任意函数式接口上使用 @FunctionalInterface 注解,这样做可以检查它是否是一个函数式接口,同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。</p>
</li>
<li><p>之所以Lambda必须和函数式接口配合是因为,接口如果多个函数,则Lambda表达式无法确定实现的是哪个</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@FunctionalInterface</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyNumber</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">double</span> <span class="title">getValue</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@FunctionalInterface</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyNumber</span><<span class="title">T</span>> </span>{</span><br><span class="line"> <span class="function">T <span class="title">getValue</span><span class="params">(T t)</span></span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h6 id="Stream"><a href="#Stream" class="headerlink" title="Stream"></a>Stream</h6><p>是数据渠道,用于操作数据源(集合、数组等)所生成的元素序列。<br>“集合讲的是数据,流讲的是计算!”</p>
<p>Stream的创建</p>
<p>Java8 中的 Collection 接口被扩展,提供了 两个获取流的方法:</p>
<ul>
<li>default Stream<E> stream() : 返回一个顺序流</li>
<li>default Stream<E> parallelStream() : 返回一个并行流</li>
</ul>
<p>例1 把字符数组变成大写并输出</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</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"> String[] array = <span class="string">"Stream API supports functional-style operations"</span>.split(<span class="string">" "</span>);</span><br><span class="line"> Stream<String> stream = Arrays.stream(array);</span><br><span class="line"> stream.map(String::toUpperCase).forEach(System.out::println);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>例2 操作对象里面的属性</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>{</span><br><span class="line"></span><br><span class="line"> String name;</span><br><span class="line"> <span class="keyword">char</span> gender;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Person</span><span class="params">(String name, <span class="keyword">char</span> gender)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.gender = gender;</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> <span class="string">"Persion("</span> + name + <span class="string">", "</span> + gender + <span class="string">")"</span>;</span><br><span class="line"> }</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">Main</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"> String[] inputs = { <span class="string">"Bob,M"</span>, <span class="string">"Alice,F"</span>, <span class="string">"Time,M"</span>, <span class="string">"Lily,F"</span> };</span><br><span class="line"> Stream<String> names = Arrays.stream(inputs);</span><br><span class="line"> Stream<Person> persons = names.map((s) -> {</span><br><span class="line"> <span class="keyword">int</span> n = s.indexOf(<span class="string">','</span>);</span><br><span class="line"> String name = s.substring(<span class="number">0</span>, n);</span><br><span class="line"> <span class="keyword">char</span> gender = s.charAt(n + <span class="number">1</span>);</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> Person(name, gender);</span><br><span class="line"> });</span><br><span class="line"> persons.forEach(System.out::println);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>例3 用filter 过滤不满足条件的元素</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><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 class="keyword">throws</span> Exception </span>{</span><br><span class="line"> String[] array = { <span class="string">"Java "</span>, <span class="string">" Python "</span>, <span class="string">" "</span>, <span class="keyword">null</span>, <span class="string">"\n\n"</span>, <span class="string">" Ruby "</span> };</span><br><span class="line"> Stream<String> normalized = Arrays.stream(array).filter(s -> s != <span class="keyword">null</span> && !s.trim().isEmpty())</span><br><span class="line"> .map(s -> s.trim());</span><br><span class="line"> normalized.forEach(System.out::println);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>例4 将一个Stream的每个元素依次作用于BiFunction,并将结果合并,reduce是聚合方法并且可以立刻对Stream进行运算</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> r = Stream.of(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>, <span class="number">5</span>, <span class="number">6</span>, <span class="number">7</span>, <span class="number">8</span>, <span class="number">9</span>).reduce((acc, x) -> acc * x).get();</span><br><span class="line"> System.out.println(r);</span><br><span class="line"> System.out.println(<span class="number">1</span> * <span class="number">2</span> * <span class="number">3</span> * <span class="number">4</span> * <span class="number">5</span> * <span class="number">6</span> * <span class="number">7</span> * <span class="number">8</span> * <span class="number">9</span>);</span><br></pre></td></tr></table></figure>
<p>例5 List转map</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">Apple</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Integer id;</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> BigDecimal money;</span><br><span class="line"> <span class="keyword">private</span> Integer num;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">Apple</span><span class="params">(Integer id, String name, BigDecimal money, Integer num)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.id = id;</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.money = money;</span><br><span class="line"> <span class="keyword">this</span>.num = num;</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">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"></span><br><span class="line"> List<Apple> appleList = <span class="keyword">new</span> ArrayList<>();<span class="comment">//存放apple对象集合</span></span><br><span class="line"></span><br><span class="line"> Apple apple1 = <span class="keyword">new</span> Apple(<span class="number">1</span>,<span class="string">"苹果1"</span>,<span class="keyword">new</span> BigDecimal(<span class="string">"3.25"</span>),<span class="number">10</span>);</span><br><span class="line"> Apple apple12 = <span class="keyword">new</span> Apple(<span class="number">1</span>,<span class="string">"苹果2"</span>,<span class="keyword">new</span> BigDecimal(<span class="string">"1.35"</span>),<span class="number">20</span>);</span><br><span class="line"> Apple apple2 = <span class="keyword">new</span> Apple(<span class="number">2</span>,<span class="string">"香蕉"</span>,<span class="keyword">new</span> BigDecimal(<span class="string">"2.89"</span>),<span class="number">30</span>);</span><br><span class="line"> Apple apple3 = <span class="keyword">new</span> Apple(<span class="number">3</span>,<span class="string">"荔枝"</span>,<span class="keyword">new</span> BigDecimal(<span class="string">"9.99"</span>),<span class="number">40</span>);</span><br><span class="line"></span><br><span class="line"> appleList.add(apple1);</span><br><span class="line"> appleList.add(apple12);</span><br><span class="line"> appleList.add(apple2);</span><br><span class="line"> appleList.add(apple3);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//List 以ID分组 Map<Integer,List<Apple>></span></span><br><span class="line"> Map<Integer, List<Apple>> groupBy = appleList.stream().collect(Collectors.groupingBy(Apple::getId));</span><br><span class="line"> System.err.println(<span class="string">"groupBy:"</span>+groupBy);</span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * List -> Map</span></span><br><span class="line"><span class="comment"> * 需要注意的是:</span></span><br><span class="line"><span class="comment"> * toMap 如果集合对象有重复的key,会报错Duplicate key ....</span></span><br><span class="line"><span class="comment"> * apple1,apple12的id都为1。</span></span><br><span class="line"><span class="comment"> * 可以用 (k1,k2)->k1 来设置,如果有重复的key,则保留key1,舍弃key2</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> Map<Integer, Apple> appleMap = appleList.stream().collect(Collectors.toMap(Apple::getId, a -> a,(k1,k2)->k1));</span><br><span class="line"> System.out.println(appleMap);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="int和Integer有什么区别"><a href="#int和Integer有什么区别" class="headerlink" title="int和Integer有什么区别"></a>int和Integer有什么区别</h5><p>Integer是Int的包装类,Int是八种基本数据类型之一。</p>
<p>Integer变量必须实例化以后才可以使用,而Int变量不需要实例化。</p>
<p>Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象,而Int是直接存储数据值。</p>
<p>Integer的默认值是null,Int的默认值是0。</p>
<h5 id="比较的是什么"><a href="#比较的是什么" class="headerlink" title="==比较的是什么"></a>==比较的是什么</h5><ol>
<li>基本类型 == 基本类型:比较数值是否相等</li>
<li>基本类型 == 包装类型:比较数值是否相等</li>
<li>引用类型 == 引用类型:除了比较数值是否相等外,还要比较两个对象在内存中的地址是否相同</li>
</ol>
<h5 id="java支持的数据类型有哪些?什么是自动拆装箱?"><a href="#java支持的数据类型有哪些?什么是自动拆装箱?" class="headerlink" title="java支持的数据类型有哪些?什么是自动拆装箱?"></a>java支持的数据类型有哪些?什么是自动拆装箱?</h5><p>8种基本数据类型:</p>
<p>byte 8位 取值范围 -2^7 ~ 2^7 -1</p>
<p>short 16位 取值范围 -2^15 ~ 2^15 - 1</p>
<p>char 16位 取值范围 0 ~ 2 ^16 - 1</p>
<p>boolean 位数不明确 取值 true false</p>
<p>int 32位 取值范围 -2^31 ~ 2^31 - 1</p>
<p>long 64位 取值范围 -2^63 ~ 2^ 63 - 1</p>
<p>float 32位 取值范围 1.4e-45 ~ 3.40e38</p>
<p>double 64位 取值范围 4.9e-324 ~ 1.79e308</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//基本类型转换成包装类型,称为装箱</span></span><br><span class="line">Integer intObjct = <span class="keyword">new</span> Integer(<span class="number">2</span>); <span class="comment">//装箱</span></span><br><span class="line"><span class="comment">//Integer intObjct = 2 //自动装箱</span></span><br><span class="line"><span class="comment">//自动装箱,如果一个基本类型值出现在需要对象的环境中,会自动装箱</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//开箱</span></span><br><span class="line"><span class="keyword">int</span> a = <span class="number">3</span> + <span class="keyword">new</span> Integer(<span class="number">3</span>); <span class="comment">//加法需要的是数值,所以会自动开箱</span></span><br><span class="line"></span><br><span class="line">Integer b = <span class="number">3</span> + <span class="keyword">new</span> Integer(<span class="number">3</span>); <span class="comment">//自动开箱,再自动装箱</span></span><br><span class="line"></span><br><span class="line">Double x = <span class="number">3.0</span>;</span><br><span class="line"><span class="comment">//Double x = 3; //编译器不给过</span></span><br><span class="line"><span class="comment">//double y = 3; //而这个可以</span></span><br></pre></td></tr></table></figure>
<h5 id="请你讲讲一个十进制的数在内存中是怎么存的?"><a href="#请你讲讲一个十进制的数在内存中是怎么存的?" class="headerlink" title="请你讲讲一个十进制的数在内存中是怎么存的?"></a>请你讲讲一个十进制的数在内存中是怎么存的?</h5><p>以二进制补码形式存储,最高位是符号位,正数的补码是它的原码,负数的补码是它的反码加1,在求反码时符号位不变,符号位为1,其他位取反</p>
<h5 id="String-和-StringBuffer-,StringBuilder"><a href="#String-和-StringBuffer-,StringBuilder" class="headerlink" title="String 和 StringBuffer ,StringBuilder"></a>String 和 StringBuffer ,StringBuilder</h5><p>String是不可变的,是常量</p>
<p>StringBuffer 是变量 是线程安全的,速度比StringBuilder慢</p>
<p>StringBuilder是变量 速度比StringBuffer快,线程不安全</p>
<p>应用场景</p>
<p>操作少量数据用String,多线程操作字符串缓冲区下操作大量数据 StringBuffer,单线程操作字符串缓冲区下操作大量数据 StringBuilder。</p>
<h1 id="java容器"><a href="#java容器" class="headerlink" title="java容器"></a>java容器</h1><h2 id="List部分"><a href="#List部分" class="headerlink" title="List部分"></a>List部分</h2><h5 id="ArrayList是线程不安全吗?"><a href="#ArrayList是线程不安全吗?" class="headerlink" title="ArrayList是线程不安全吗?"></a>ArrayList是线程不安全吗?</h5><p>不安全,</p>
<ul>
<li>故障现象</li>
</ul>
<p> 多线程的时候会报 java.util.ConcurrentModificationException 错误</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">for</span>(<span class="keyword">int</span> i=<span class="number">1</span>;i<=<span class="number">30</span>;i++)</span><br><span class="line">{</span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> list.add(UUID.randomUUID().toString().substring(<span class="number">0</span>,<span class="number">8</span>));</span><br><span class="line"> System.out.println(list);</span><br><span class="line"> },String.valueOf(i)).start();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ul>
<li>导致原因</li>
</ul>
<p> 并发争抢修改,一个线程在写,另外一个线程过来抢夺,也想写入数据,导致数据不一致异常,并发修改异常</p>
<ul>
<li><p>解决方案</p>
<p>1 用Vector,但是Vector的add方法有synchronized,可以防止数据不一致,但是性能急剧下降,一般很少使用。</p>
<p>2 用Collections.synchronizedList(new ArrayList<>());</p>
</li>
</ul>
<p> 3 用copyOnWriteArrayList();</p>
<h5 id="Array数组和ArrayList列表的区别,应用场景"><a href="#Array数组和ArrayList列表的区别,应用场景" class="headerlink" title="Array数组和ArrayList列表的区别,应用场景"></a>Array数组和ArrayList列表的区别,应用场景</h5><p>Array 初始化大小后,大小是固定的,可以包含基本数据类型和对象,不能删除数组的元素</p>
<p>ArrayList 大小是动态变化的,只包含对象,可以用remove删除元素</p>
<p>在空间大小固定的时候,用Array,效率比ArrayList高</p>
<p>而要频繁增加元素,用ArrayList。 扩容会影响效率newCapacity=oldCapacity+(oldCapacity>>1)</p>
<h5 id="说一下-CopyOnWriteArrayLis和ArrayList-相比有哪些相同点和不同点?"><a href="#说一下-CopyOnWriteArrayLis和ArrayList-相比有哪些相同点和不同点?" class="headerlink" title="说一下 CopyOnWriteArrayLis和ArrayList 相比有哪些相同点和不同点?"></a>说一下 CopyOnWriteArrayLis和ArrayList 相比有哪些相同点和不同点?</h5><p>相同点:底层都是数组,数据结构是相同的</p>
<p>不同点:CopyOnWriteArrayLis 是线程安全的,在多线程环境下使用,无需加锁,可直接使用</p>
<h5 id="CopyOnWriteArrayList-通过哪些手段实现了线程安全?"><a href="#CopyOnWriteArrayList-通过哪些手段实现了线程安全?" class="headerlink" title="CopyOnWriteArrayList 通过哪些手段实现了线程安全?"></a>CopyOnWriteArrayList 通过哪些手段实现了线程安全?</h5><ol>
<li>数组容器被 volatile 关键字修饰,保证了数组内存地址被任意线程修改后,都会通知到其他线程;</li>
<li>对数组的所有修改操作,都进行了加锁,保证了同一时刻,只能有一个线程对数组进行修改,比如我在 add 时,就无法 remove</li>
<li>修改过程中对原数组进行了复制,是在新数组上进行修改的,修改过程中,不会对原数组产生任何影响。</li>
</ol>
<h5 id="在-add-方法中,对数组进行加锁后,不是已经是线程安全了么,为什么还需要对老数组进行拷贝?"><a href="#在-add-方法中,对数组进行加锁后,不是已经是线程安全了么,为什么还需要对老数组进行拷贝?" class="headerlink" title="在 add 方法中,对数组进行加锁后,不是已经是线程安全了么,为什么还需要对老数组进行拷贝?"></a>在 add 方法中,对数组进行加锁后,不是已经是线程安全了么,为什么还需要对老数组进行拷贝?</h5><p>的确,对数组进行加锁后,能够保证同一时刻,只有一个线程能对数组进行 add,在同单核 CPU 下的多线程环境下肯定没有问题,但我们现在的机器都是多核 CPU,如果我们不通过复制拷贝新建数组,修改原数组容器的内存地址的话,是无法触发 volatile 可见性效果的,那么其他 CPU 下的线程就无法感知数组原来已经被修改了,就会引发多核 CPU 下的线程安全问题。</p>
<p>假设我们不复制拷贝,而是在原来数组上直接修改值,数组的内存地址就不会变,而数组被 volatile 修饰时,必须当数组的内存地址变更时,才能及时的通知到其他线程,内存地址不变,仅仅是数组元素值发生变化时,是无法把数组元素值发生变动的事实,通知到其它线程的。</p>
<h5 id="对老数组进行拷贝,会有性能损耗,我们平时使用需要注意什么么?"><a href="#对老数组进行拷贝,会有性能损耗,我们平时使用需要注意什么么?" class="headerlink" title="对老数组进行拷贝,会有性能损耗,我们平时使用需要注意什么么?"></a>对老数组进行拷贝,会有性能损耗,我们平时使用需要注意什么么?</h5><p>主要是因为 for 循环里面使用 add 、remove 的方式是非常消耗性能,而 addAll、removeAll 方法底层做了优化,整个操作只会进行一次数组拷贝,由此可见,当批量操作的数据越多时,批量方法的高性能体现的越明显。因此平常使用应尽量用批量操作</p>
<h5 id="为什么-CopyOnWriteArrayList-迭代过程中,数组结构变动,不会抛出ConcurrentModificationException-了"><a href="#为什么-CopyOnWriteArrayList-迭代过程中,数组结构变动,不会抛出ConcurrentModificationException-了" class="headerlink" title="为什么 CopyOnWriteArrayList 迭代过程中,数组结构变动,不会抛出ConcurrentModificationException 了"></a>为什么 CopyOnWriteArrayList 迭代过程中,数组结构变动,不会抛出ConcurrentModificationException 了</h5><p>主要是因为 CopyOnWriteArrayList 每次操作时,都会产生新的数组,而迭代时,持有的仍然是老数组的引用,所以我们说的数组结构变动,是用新数组替换了老数组,老数组的结构并没有发生变化,所以不会抛出异常了。</p>
<h5 id="插入的数据正好在-List-的中间,请问两种-List-分别拷贝数组几次?为什么?"><a href="#插入的数据正好在-List-的中间,请问两种-List-分别拷贝数组几次?为什么?" class="headerlink" title="插入的数据正好在 List 的中间,请问两种 List 分别拷贝数组几次?为什么?"></a>插入的数据正好在 List 的中间,请问两种 List 分别拷贝数组几次?为什么?</h5><p>ArrayList 只需拷贝一次,假设插入的位置是 2,只需要把位置 2 (包含 2)后面的数据都往后移动一位即可,所以拷贝一次。</p>
<p>CopyOnWriteArrayList 拷贝两次,因为 CopyOnWriteArrayList 多了把老数组的数据拷贝到新数组上这一步,可能有的同学会想到这种方式:先把老数组拷贝到新数组,再把 2 后面的数据往后移动一位,这的确是一种拷贝的方式,但 CopyOnWriteArrayList 底层实现更加灵活,而是:把老数组 0 到 2 的数据拷贝到新数组上,预留出新数组 2 的位置,再把老数组 3~ 最后的数据拷贝到新数组上,这种拷贝方式可以减少我们拷贝的数据,虽然是两次拷贝,但拷贝的数据却仍然是老数组的大小,设计的非常巧妙。</p>
<h2 id="Map部分"><a href="#Map部分" class="headerlink" title="Map部分"></a>Map部分</h2><h5 id="说一下-Map-的-hash-算法"><a href="#说一下-Map-的-hash-算法" class="headerlink" title="说一下 Map 的 hash 算法"></a>说一下 Map 的 hash 算法</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(Object key)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> h;</span><br><span class="line"> <span class="keyword">return</span> (key == <span class="keyword">null</span>) ? <span class="number">0</span> : (h = key.hashCode()) ^ (h >>> <span class="number">16</span>);</span><br><span class="line">}</span><br><span class="line">key 在数组中的位置公式:tab[(n - <span class="number">1</span>) & hash]</span><br></pre></td></tr></table></figure>
<p> h ^ (h >>> 16) ,这么做的好处是使大多数场景下,算出来的 hash 值比较分散</p>
<p>hash 值算出来之后,要计算当前 key 在数组中的索引下标位置时,可以采用取模的方式,就是索引下标位置 = hash 值 % 数组大小,这样做的好处,就是可以保证计算出来的索引下标值可以均匀的分布在数组的各个索引位置上,但取模操作对于处理器的计算是比较慢的,数学上有个公式,当 b 是 2 的幂次方时,a % b = a &(b-1),所以此处索引位置的计算公式我们可以更换为: (n-1) & hash。</p>
<h5 id="为什么不用-key-数组大小,而是需要用-key-的-hash-值-数组大小。"><a href="#为什么不用-key-数组大小,而是需要用-key-的-hash-值-数组大小。" class="headerlink" title="为什么不用 key % 数组大小,而是需要用 key 的 hash 值 % 数组大小。"></a>为什么不用 key % 数组大小,而是需要用 key 的 hash 值 % 数组大小。</h5><p>如果 key 是数字,直接用 key % 数组大小是完全没有问题的,但我们的 key 还有可能是字符串,是复杂对象,这时候用 字符串或复杂对象 % 数组大小是不行的,所以需要先计算出 key 的 hash 值。</p>
<h5 id="计算-hash-值时,为什么需要右移-16-位?"><a href="#计算-hash-值时,为什么需要右移-16-位?" class="headerlink" title="计算 hash 值时,为什么需要右移 16 位?"></a>计算 hash 值时,为什么需要右移 16 位?</h5><p>hash 算法是 h ^ (h >>> 16),为了使计算出的 hash 值更分散,所以选择先将 h 无符号右移 16 位,然后再于 h 异或时,就能达到 h 的高 16 位和低 16 位都能参与计算,减少了碰撞的可能性。</p>
<h5 id="为什么把取模操作换成了-amp-操作?"><a href="#为什么把取模操作换成了-amp-操作?" class="headerlink" title="为什么把取模操作换成了 & 操作?"></a>为什么把取模操作换成了 & 操作?</h5><p>key.hashCode() 算出来的 hash 值还不是数组的索引下标,为了随机的计算出索引的下表位置,我们还会用 hash 值和数组大小进行取模,这样子计算出来的索引下标比较均匀分布。</p>
<p>取模操作处理器计算比较慢,处理器对 & 操作就比较擅长,换成了 & 操作,是有数学上证明的支撑,为了提高了处理器处理的速度。</p>
<h5 id="为什么提倡数组大小是-2-的幂次方?"><a href="#为什么提倡数组大小是-2-的幂次方?" class="headerlink" title="为什么提倡数组大小是 2 的幂次方?"></a>为什么提倡数组大小是 2 的幂次方?</h5><p>因为只有大小是 2 的幂次方时,才能使 hash 值 % n(数组大小) == (n-1) & hash 公式成立。</p>
<h5 id="你有什么办法解决-hash-冲突。"><a href="#你有什么办法解决-hash-冲突。" class="headerlink" title="你有什么办法解决 hash 冲突。"></a>你有什么办法解决 hash 冲突。</h5><ol>
<li>好的 hash 算法,细问的话复述一下上题的 hash 算法;</li>
<li>自动扩容,当数组大小快满的时候,采取自动扩容,可以减少 hash 冲突</li>
<li>hash 冲突发生时,采用链表来解决;</li>
<li>hash 冲突严重时,链表会自动转化成红黑树,提高遍历速度。</li>
</ol>
<h5 id="HashMap-是如何扩容的?"><a href="#HashMap-是如何扩容的?" class="headerlink" title="HashMap 是如何扩容的?"></a>HashMap 是如何扩容的?</h5><ul>
<li>put 时,发现数组为空,进行初始化扩容,默认扩容大小为 16;</li>
<li>put 成功后,发现现有数组大小大于扩容的门阀值时,进行扩容,扩容为老数组大小的 2 倍;</li>
<li>扩容的门阀是 threshold,每次扩容时 threshold 都会被重新计算,门阀值等于数组的大小 * 影响因子(0.75)。新数组初始化之后,需要将老数组的值拷贝到新数组上,链表和红黑树都有自己拷贝的方法。</li>
</ul>
<h5 id="hash-冲突时怎么办?"><a href="#hash-冲突时怎么办?" class="headerlink" title="hash 冲突时怎么办?"></a>hash 冲突时怎么办?</h5><p>hash 冲突指的是 key 值的 hashcode 计算相同,但 key 值不同的情况。</p>
<p>如果桶中元素原本只有一个或已经是链表了,新增元素直接追加到链表尾部</p>
<p>如果桶中元素已经是链表,并且链表个数大于等于 8 时,此时有两种情况</p>
<ul>
<li>如果此时数组大小小于 64,数组再次扩容,链表不会转化成红黑树;</li>
<li>如果数组大小大于 64 时,链表就会转化成红黑树。</li>
</ul>
<h5 id="为什么链表个数大于等于-8-时,链表要转化成红黑树了?"><a href="#为什么链表个数大于等于-8-时,链表要转化成红黑树了?" class="headerlink" title="为什么链表个数大于等于 8 时,链表要转化成红黑树了?"></a>为什么链表个数大于等于 8 时,链表要转化成红黑树了?</h5><p>当链表个数太多了,遍历可能比较耗时,转化成红黑树,可以使遍历的时间复杂度降低,但转化成红黑树,有空间和转化耗时的成本,我们通过泊松分布公式计算,正常情况下,链表个数出现 8 的概念不到千万分之一,所以说正常情况下,链表都不会转化成红黑树,这样设计的目的,是为了防止非正常情况下,比如 hash 算法出了问题时,导致链表个数轻易大于等于 8 时,仍然能够快速遍历。</p>
<h5 id="红黑树什么时候转变成链表。"><a href="#红黑树什么时候转变成链表。" class="headerlink" title="红黑树什么时候转变成链表。"></a>红黑树什么时候转变成链表。</h5><p>当节点的个数小于等于 6 时,红黑树会自动转化成链表,主要还是考虑红黑树的空间成本问题,当节点个数小于等于 6 时,遍历链表也很快,所以红黑树会重新变成链表。</p>
<h5 id="HashMap-在-put-时,如果数组中已经有了这个-key,我不想把-value-覆盖怎么办?取值时,如果得到的-value-是空时,想返回默认值怎么办?"><a href="#HashMap-在-put-时,如果数组中已经有了这个-key,我不想把-value-覆盖怎么办?取值时,如果得到的-value-是空时,想返回默认值怎么办?" class="headerlink" title="HashMap 在 put 时,如果数组中已经有了这个 key,我不想把 value 覆盖怎么办?取值时,如果得到的 value 是空时,想返回默认值怎么办?"></a>HashMap 在 put 时,如果数组中已经有了这个 key,我不想把 value 覆盖怎么办?取值时,如果得到的 value 是空时,想返回默认值怎么办?</h5><p>如果数组有了 key,但不想覆盖 value ,可以选择 putIfAbsent 方法,这个方法有个内置变量 onlyIfAbsent,内置是 true ,就不会覆盖,我们平时使用的 put 方法,内置 onlyIfAbsent 为 false,是允许覆盖的。</p>
<p>取值时,如果为空,想返回默认值,可以使用 getOrDefault 方法,方法第一参数为 key,第二个参数为你想返回的默认值,如 map.getOrDefault(“2”,“0”),当 map 中没有 key 为 2 的值时,会默认返回 0,而不是空。</p>
<h5 id="DTO-作为-Map-的-key-时,有无需要注意的点?"><a href="#DTO-作为-Map-的-key-时,有无需要注意的点?" class="headerlink" title="DTO 作为 Map 的 key 时,有无需要注意的点?"></a>DTO 作为 Map 的 key 时,有无需要注意的点?</h5><p>DTO 就是一个数据载体,可以看做拥有很多属性的 Java 类,我们可以对这些属性进行 get、set 操作。</p>
<p>看是什么类型的 Map,如果是 HashMap 的话,一定需要覆写 equals 和 hashCode 方法,因为在 get 和 put 的时候,需要通过 equals 方法进行相等的判断;如果是 TreeMap 的话,DTO 需要实现 Comparable 接口,因为 TreeMap 会使用 Comparable 接口进行判断 key 的大小;如果是 LinkedHashMap 的话,和 HashMap 一样的。</p>
<h5 id="LinkedHashMap-中的-LRU-是什么意思,是如何实现的。"><a href="#LinkedHashMap-中的-LRU-是什么意思,是如何实现的。" class="headerlink" title="LinkedHashMap 中的 LRU 是什么意思,是如何实现的。"></a>LinkedHashMap 中的 LRU 是什么意思,是如何实现的。</h5><p>LRU ,英文全称:Least recently used,中文叫做最近最少访问,在 LinkedHashMap 中,也叫做最少访问删除策略,我们可以通过 removeEldestEntry 方法设定一定的策略,使最少被访问的元素,在适当的时机被删除,原理是在 put 方法执行的最后,LinkedHashMap 会去检查这种策略,如果满足策略,就删除头节点。</p>
<p>保证头节点就是最少访问的元素的原理是:LinkedHashMap 在 get 的时候,都会把当前访问的节点,移动到链表的尾部,慢慢的,就会使头部的节点都是最少被访问的元素。</p>
<h5 id="为什么推荐-TreeMap-的元素最好都实现-Comparable-接口?但-key-是-String-的时候,我们却没有额外的工作呢?"><a href="#为什么推荐-TreeMap-的元素最好都实现-Comparable-接口?但-key-是-String-的时候,我们却没有额外的工作呢?" class="headerlink" title="为什么推荐 TreeMap 的元素最好都实现 Comparable 接口?但 key 是 String 的时候,我们却没有额外的工作呢?"></a>为什么推荐 TreeMap 的元素最好都实现 Comparable 接口?但 key 是 String 的时候,我们却没有额外的工作呢?</h5><p>因为 TreeMap 的底层就是通过排序来比较两个 key 的大小的,所以推荐 key 实现 Comparable 接口,是为了往你希望的排序顺序上发展, 而 String 本身已经实现了 Comparable 接口,所以使用 String 时,我们不需要额外的工作,不仅仅是 String ,其他包装类型也都实现了 Comparable 接口,如 Long、Double、Short 等等。</p>
<h5 id="ConcurrentHashMap-和-HashMap-的相同点和不同点"><a href="#ConcurrentHashMap-和-HashMap-的相同点和不同点" class="headerlink" title="ConcurrentHashMap 和 HashMap 的相同点和不同点"></a>ConcurrentHashMap 和 HashMap 的相同点和不同点</h5><p>相同点:底层结构是数组+ 链表 +红黑树,</p>
<p> 都实现了 Map 接口,继承了 AbstractMap 抽象类,所以两者的方法大多都是相似的,可以互相切换。</p>
<p>不同点: ConcurrentHashMap 是线程安全的,在多线程环境下,无需加锁,可直接使用;</p>
<p> 数据结构上,ConcurrentHashMap 多了转移节点,主要用于保证扩容时的线程安全。</p>
<h3 id="Set部分"><a href="#Set部分" class="headerlink" title="Set部分"></a>Set部分</h3><p>线程不安全,底层就是HashMap。</p>
<p><strong>那为什么可以 new HashSet<>().add(Data date),不是应该是put吗?</strong></p>
<p>因为它底层的put是 map.put(date,PRESENT)==null; PPRSENT是常量,是恒定的</p>
<h1 id="Java锁"><a href="#Java锁" class="headerlink" title="Java锁"></a>Java锁</h1><h5 id="说一下CAS"><a href="#说一下CAS" class="headerlink" title="说一下CAS"></a>说一下CAS</h5><p>CAS是一条CPU并发原语,执行是连续的,在执行过程不被打断,不会造成数据不一致</p>
<p>CAS核心类是unsafe类,在sum.misc中,unsafe可以根据内存偏移地址获取数据</p>
<p>如unsafe的getAndAddint方法</p>
<p></p>
<p>var1 是AtomicInteger 对象本身</p>
<p>var2 该对象引用地址</p>
<p>Var4 需要变动的数量</p>
<p>Var5 是用var1,var2 找出的主内存真是的值</p>
<p>用该对象与当前值var5相比,</p>
<p>若相同,更新var5+var4.并返回true</p>
<p>若不相同,继续取值然后比较,直到更新完成。</p>
<p>(如果一直不相等会死循环吗) 答:不会,因为配置了jvm参数,只能自旋一定次数</p>
<h5 id="CAS缺点"><a href="#CAS缺点" class="headerlink" title="CAS缺点"></a>CAS缺点</h5><ol>
<li>循环时间长,开销大</li>
<li>只能保证一个共享变量的原子操作</li>
<li>引出来ABA问题</li>
</ol>
<h5 id="原子类AtomicInteger-的ABA问题是什么"><a href="#原子类AtomicInteger-的ABA问题是什么" class="headerlink" title="原子类AtomicInteger 的ABA问题是什么"></a>原子类AtomicInteger 的ABA问题是什么</h5><p>CAS算法实现一个重要前提是需要取出内存中某时刻的数据并在当下时刻比较并替换,那么在这个时间差类会导致数据的变化。</p>
<p>比如一个线程1从内存位置V取出A,这时候另外一个线程2也从内存取出A,并且线程2把A换成B,然后线程2又将V位置数据变成A,这时候线程1进行CSA操作,发现内存仍然是A,然后线程1操作成功</p>
<p><strong>尽管线程1的CAS操作成功,但是不代表这个过程就是没问题的</strong></p>
<p><strong>解决方法是加时间戳</strong></p>
<h5 id="公平锁和非公平锁"><a href="#公平锁和非公平锁" class="headerlink" title="公平锁和非公平锁"></a>公平锁和非公平锁</h5><ul>
<li>公平锁 是指多个线程按照申请锁的顺序来获取锁</li>
<li>非公平锁 是指多个线程按照申请锁的顺序来获取锁不按照申请锁的顺序来获取锁,有可能后申请比先申请的线程优先获得锁,在高并发情况下,有可能造成优先级反转 例如Synchronize</li>
</ul>
<p>非公平锁吞吐量比公平锁大</p>
<h5 id="可重入锁-(递归锁)"><a href="#可重入锁-(递归锁)" class="headerlink" title="可重入锁 (递归锁)"></a>可重入锁 (递归锁)</h5><p><strong>指同一个线程外层函数获得锁后,内层递归函数仍然能获得该锁代码,在同一个线程在外层方法获得锁的时候,在进入内层方法会自动获得锁</strong></p>
<p>也就是 线程可以进入任何一个它已经拥有的锁所同步着的代码块</p>
<h5 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 自旋锁;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicReference;</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">Main</span> </span>{</span><br><span class="line"> <span class="comment">//原子引用线程</span></span><br><span class="line"> AtomicReference<Thread> atomicReference = <span class="keyword">new</span> AtomicReference<>();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">myLock</span><span class="params">()</span> </span>{</span><br><span class="line"> Thread thread = Thread.currentThread();</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" come in"</span>);</span><br><span class="line"> <span class="keyword">while</span> (!atomicReference.compareAndSet(<span class="keyword">null</span>, thread)) {</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><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">myUnlock</span><span class="params">()</span> </span>{</span><br><span class="line"> Thread thread = Thread.currentThread();</span><br><span class="line"> atomicReference.compareAndSet(thread, <span class="keyword">null</span>);</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">" invoke"</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">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> Main m = <span class="keyword">new</span> Main();</span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> m.myLock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> m.myUnlock();</span><br><span class="line"> },<span class="string">"A"</span>).start();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> m.myLock();</span><br><span class="line"> m.myUnlock();</span><br><span class="line"> },<span class="string">"B"</span>).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>运行过程,首先A拿到锁后,要等5秒才释放,此时B也想拿锁,但是在!atomicReference.compareAndSet(null, thread) ,此时期望值并不为null,而是为A,因此B一直自旋,最后等A释放锁,atomicReference.compareAndSet(thread, null),当前期望值为A,因此更新为null。</p>
<p>此时B才可以拿到锁。</p>
<h5 id="独占锁"><a href="#独占锁" class="headerlink" title="独占锁"></a>独占锁</h5><p>读-读能共存</p>
<p>读-写不能共存</p>
<p>写-写不能共存</p>
<p>写操作:原子+独占,整个过程必须是一个完整的统一体,中间不能被分隔</p>
<p><strong>要加读写锁</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 读写锁;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantReadWriteLock;</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">MyCache</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">volatile</span> Map<String, Object> map = <span class="keyword">new</span> HashMap<>();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> ReentrantReadWriteLock rwlock = <span class="keyword">new</span> ReentrantReadWriteLock();</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">put</span><span class="params">(String key, Object value)</span> </span>{</span><br><span class="line"></span><br><span class="line"> rwlock.writeLock().lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.println(Thread.currentThread().getName()</span><br><span class="line"> + <span class="string">"\t 正在写入:"</span> + key);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.MICROSECONDS.sleep(<span class="number">300</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> map.put(key, value);</span><br><span class="line"> System.out.println(Thread.currentThread().getName()</span><br><span class="line"> + <span class="string">"\t 写入完成:"</span> + key);</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> rwlock.writeLock().unlock();</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> Object <span class="title">get</span><span class="params">(String key)</span> </span>{</span><br><span class="line"> rwlock.readLock().lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> System.out.println(Thread.currentThread().getName()</span><br><span class="line"> + <span class="string">"\t 正在读取"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.MICROSECONDS.sleep(<span class="number">300</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) { e.printStackTrace(); }</span><br><span class="line"> Object object = map.get(key);</span><br><span class="line"> System.out.println(Thread.currentThread().getName()</span><br><span class="line"> + <span class="string">"\t 读取完成:"</span> + object);</span><br><span class="line"> }<span class="keyword">catch</span> (Exception e)</span><br><span class="line"> {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> rwlock.readLock().unlock();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> <span class="string">""</span>;</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">Main</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"> MyCache myCache = <span class="keyword">new</span> MyCache();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">5</span>; i++) {</span><br><span class="line"> <span class="keyword">final</span> <span class="keyword">int</span> tempInt=i;</span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> myCache.put(tempInt + <span class="string">""</span>, tempInt + <span class="string">""</span>);</span><br><span class="line"> }, String.valueOf(i)).start();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">5</span>; i++) {</span><br><span class="line"> <span class="keyword">final</span> <span class="keyword">int</span> tempInt=i;</span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> myCache.get(tempInt + <span class="string">""</span>);</span><br><span class="line"> }, String.valueOf(i)).start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h5><ul>
<li>让一些线程阻塞,知道另外一些线程完成一系列操作后才唤醒</li>
<li>主要有两个方法,await()组成线程 ,countDown,将计数器减一,当计数器值为0的时候,,因调用await方法被阻塞的线程被唤醒,继续执行</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> CountDownLatch;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CountDownLatch;</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">Main</span> </span>{</span><br><span class="line"></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 class="keyword">throws</span> InterruptedException </span>{</span><br><span class="line"> CountDownLatch countDownLatch = <span class="keyword">new</span> CountDownLatch(<span class="number">6</span>);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">6</span>; i++) {</span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t 上完自习离开教室"</span>);</span><br><span class="line"> countDownLatch.countDown();</span><br><span class="line"> },String.valueOf(i)).start();</span><br><span class="line"> }</span><br><span class="line"> countDownLatch.await();</span><br><span class="line"> System.out.println(Thread.currentThread().getName()</span><br><span class="line"> + <span class="string">"\t 班长最后关门走人"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h5><p>集体七颗龙珠可以召唤神龙,这个和CountDownLatch相反,这个是减法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> CyclicBarrier;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BrokenBarrierException;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.CyclicBarrier;</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">Main</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"> CyclicBarrier cyclicBarrier = <span class="keyword">new</span> CyclicBarrier(<span class="number">7</span>,</span><br><span class="line"> () -> System.out.println(<span class="string">"召唤神龙"</span>));</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">7</span>; i++) {</span><br><span class="line"> <span class="keyword">final</span> <span class="keyword">int</span> tempInt = i;</span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"收集到第"</span> + tempInt + <span class="string">"颗龙珠"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> cyclicBarrier.await();</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> } <span class="keyword">catch</span> (BrokenBarrierException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }, String.valueOf(i)).start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="Semaphore"><a href="#Semaphore" class="headerlink" title="Semaphore"></a>Semaphore</h5><p>一个是多个共享资源互斥使用,另一个用于并发线程数的控制。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> Semaphore;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Semaphore;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</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">Main</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"> Semaphore semaphore = <span class="keyword">new</span> Semaphore(<span class="number">3</span>);<span class="comment">//模拟三个停车位</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">6</span>; i++) {</span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> semaphore.acquire();</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t抢到车位"</span>);</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t停车三秒后离开车位"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> semaphore.release();</span><br><span class="line"> }</span><br><span class="line"> }, String.valueOf(i)).start();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="阻塞队列"><a href="#阻塞队列" class="headerlink" title="阻塞队列"></a>阻塞队列</h5><p>当阻塞队列是空时,从队列获取元素操作将会被阻塞</p>
<p>当阻塞队列是满时,从队列插入元素操作将会被阻塞</p>
<p>SynchronousQueue 不存储元素的阻塞队列,也即是单个元素的队列</p>
<h5 id="生产者和消费者"><a href="#生产者和消费者" class="headerlink" title="生产者和消费者"></a>生产者和消费者</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 生产者和消费者;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Condition;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.Lock;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.locks.ReentrantLock;</span><br><span class="line"></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">Main</span> </span>{</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="class"><span class="keyword">class</span> <span class="title">ShareData</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> number=<span class="number">0</span>;</span><br><span class="line"> <span class="keyword">private</span> Lock lock = <span class="keyword">new</span> ReentrantLock();</span><br><span class="line"> <span class="keyword">private</span> Condition condition = lock.newCondition();</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">increment</span><span class="params">()</span> </span>{</span><br><span class="line"> lock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> (number != <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//等待,不能生产</span></span><br><span class="line"> condition.await();</span><br><span class="line"> }</span><br><span class="line"> number++;</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + number);</span><br><span class="line"> <span class="comment">//通知唤醒</span></span><br><span class="line"> condition.signalAll();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> lock.unlock();</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">decrement</span><span class="params">()</span> </span>{</span><br><span class="line"> lock.lock();</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">while</span> (number == <span class="number">0</span>) {</span><br><span class="line"> <span class="comment">//等待,不能生产</span></span><br><span class="line"> condition.await();</span><br><span class="line"> }</span><br><span class="line"> number--;</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span> + number);</span><br><span class="line"> <span class="comment">//通知唤醒</span></span><br><span class="line"> condition.signalAll();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> lock.unlock();</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">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> ShareData shareData = <span class="keyword">new</span> ShareData();</span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">1</span>;i<=<span class="number">10</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> shareData.increment();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> },<span class="string">"AA"</span>).start();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">1</span>;i<=<span class="number">5</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> shareData.decrement();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> },<span class="string">"BB"</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(()->{</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i=<span class="number">1</span>;i<=<span class="number">5</span>;i++)</span><br><span class="line"> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> shareData.decrement();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> },<span class="string">"CC"</span>).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p>synchronized和lock区别</p>
<p>1原始构成</p>
<p> synchronized是jvm层面, lock是具体类,是api层面的锁</p>
<p>2使用方法</p>
<p> synchronized不需要用户去手动释放锁,当synchronized执行完后系统会自动让线程释放锁</p>
<p> ReentrantLock 则需要用户去手动释放锁,若没有主动释放会死锁,要用lock()和unlock()方法配合try/finally来完成</p>
<p>3等待是否可中断</p>
<p> synchronized不可中断,除非抛出异常或正常运行</p>
<p> ReentrantLock可中断 设置超时方法TimeUtil unit,或interrupt方法可中断</p>
<p>4 加锁是否公平</p>
<p> synchronized非公平锁</p>
<p> ReentrantLock 两者都可以,默认非公平锁 构造方法 true是公平锁,false是非公平锁</p>
<p>5 锁绑定多个条件Condition</p>
<p>synchronized没有</p>
<p>ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒</p>
<h5 id="阻塞队列的生产者和消费者模式"><a href="#阻塞队列的生产者和消费者模式" class="headerlink" title="阻塞队列的生产者和消费者模式"></a>阻塞队列的生产者和消费者模式</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 生产者和消费者;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ArrayBlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.BlockingQueue;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.atomic.AtomicInteger;</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">ProConsumer_BolckQueueDemo</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">MyResource</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> FLAG = <span class="keyword">true</span>;<span class="comment">//默认开启,进行生产+消费</span></span><br><span class="line"> <span class="keyword">private</span> AtomicInteger atomicInteger = <span class="keyword">new</span> AtomicInteger();</span><br><span class="line"></span><br><span class="line"> BlockingQueue<String> blockingQueue = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">MyResource</span><span class="params">(BlockingQueue<String> blockingQueue)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.blockingQueue = blockingQueue;</span><br><span class="line"> System.out.println(blockingQueue.getClass().getName());</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">myProd</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> String data = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">boolean</span> retValue;</span><br><span class="line"> <span class="keyword">while</span> (FLAG) {</span><br><span class="line"> data=atomicInteger.incrementAndGet() + <span class="string">""</span>;</span><br><span class="line"> retValue=blockingQueue.offer(data, <span class="number">2L</span>, TimeUnit.SECONDS);</span><br><span class="line"> <span class="keyword">if</span> (retValue) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t插入队列"</span> + data + <span class="string">"成功"</span>);</span><br><span class="line"> } <span class="keyword">else</span> {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t插入队列"</span> + data + <span class="string">"失败"</span>);</span><br><span class="line"> }</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">1</span>);</span><br><span class="line"> }</span><br><span class="line"> System.out.println(Thread.currentThread().getName()+<span class="string">"\t停止生产,表示FLAG=false"</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">myConsumer</span><span class="params">()</span> <span class="keyword">throws</span> Exception </span>{</span><br><span class="line"> String result = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">while</span> (FLAG) {</span><br><span class="line"> result=blockingQueue.poll(<span class="number">2L</span>, TimeUnit.SECONDS);</span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">null</span> == result || result.equalsIgnoreCase(<span class="string">""</span>)) {</span><br><span class="line"> FLAG = <span class="keyword">false</span>;</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t超过两秒没有取到,消费退出"</span>);</span><br><span class="line"> System.out.println();</span><br><span class="line"> System.out.println();</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> }</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t消费队列"</span> + result + <span class="string">"成功"</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">public</span> <span class="keyword">void</span> <span class="title">stop</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.FLAG = <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="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"> MyResource myResource = <span class="keyword">new</span> MyResource(<span class="keyword">new</span> ArrayBlockingQueue<>(<span class="number">10</span>));</span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> myResource.myProd();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }, <span class="string">"Prod"</span>).start();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(() -> {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> myResource.myConsumer();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> }, <span class="string">"Consumer"</span>).start();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">5</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"> System.out.println();</span><br><span class="line"> System.out.println();</span><br><span class="line"> System.out.println();</span><br><span class="line"></span><br><span class="line"> System.out.println(<span class="string">"五秒钟时间到,消费结束"</span>);</span><br><span class="line"> myResource.stop();</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>原理:控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过最大数量,则超出的线程排队等候,等其他线程执行完毕,再从队列中取出来执行任务。</p>
<p>优点</p>
<ul>
<li>降低资源消耗。通过重复利用已经创建的线程降低线程创建和销毁的损耗</li>
<li>提高响应速度。当任务到达时,任务可以不需要等线程创建,就可以直接使用</li>
<li>提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗资源,还会降低系统稳定性,使用线程池可以进行统一的分配,调优和监控</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 线程池;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ExecutorService;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.Executors;</span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.ThreadPoolExecutor;</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">class</span> <span class="title">Main</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"> ExecutorService threadPool1 = Executors.newFixedThreadPool(<span class="number">5</span>);<span class="comment">//一池5个处理线程</span></span><br><span class="line"> ExecutorService threadPool2= Executors.newSingleThreadExecutor();<span class="comment">//一池一个线程</span></span><br><span class="line"> ExecutorService threadPool3= Executors.newCachedThreadPool();<span class="comment">//池多个线程</span></span><br><span class="line"> <span class="comment">//模拟10个用户来办理业务,每个用户就是来自外部的处理线程</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">10</span>; i++) {</span><br><span class="line"> <span class="keyword">int</span> temp=i;</span><br><span class="line"> threadPool1.execute(()->{</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span>+temp+<span class="string">"办理业务"</span>);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> threadPool1.shutdown();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="介绍一下ThreadPoolExecutor"><a href="#介绍一下ThreadPoolExecutor" class="headerlink" title="介绍一下ThreadPoolExecutor"></a>介绍一下ThreadPoolExecutor</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> ExecutorService <span class="title">newFixedThreadPool</span><span class="params">(<span class="keyword">int</span> nThreads)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ThreadPoolExecutor(nThreads, nThreads,</span><br><span class="line"> <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line"> <span class="keyword">new</span> LinkedBlockingQueue<Runnable>());</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">static</span> ExecutorService <span class="title">newSingleThreadExecutor</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> FinalizableDelegatedExecutorService</span><br><span class="line"> (<span class="keyword">new</span> ThreadPoolExecutor(<span class="number">1</span>, <span class="number">1</span>,</span><br><span class="line"> <span class="number">0L</span>, TimeUnit.MILLISECONDS,</span><br><span class="line"> <span class="keyword">new</span> LinkedBlockingQueue<Runnable>()));</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">static</span> ExecutorService <span class="title">newCachedThreadPool</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> ThreadPoolExecutor(<span class="number">0</span>, Integer.MAX_VALUE,</span><br><span class="line"> <span class="number">60L</span>, TimeUnit.SECONDS,</span><br><span class="line"> <span class="keyword">new</span> SynchronousQueue<Runnable>());</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h5 id="线程池7大参数"><a href="#线程池7大参数" class="headerlink" title="线程池7大参数"></a>线程池7大参数</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">ThreadPoolExecutor</span><span class="params">(<span class="keyword">int</span> corePoolSize,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">int</span> maximumPoolSize,</span></span></span><br><span class="line"><span class="function"><span class="params"> <span class="keyword">long</span> keepAliveTime,</span></span></span><br><span class="line"><span class="function"><span class="params"> TimeUnit unit,</span></span></span><br><span class="line"><span class="function"><span class="params"> BlockingQueue<Runnable> workQueue,</span></span></span><br><span class="line"><span class="function"><span class="params"> ThreadFactory threadFactory,</span></span></span><br><span class="line"><span class="function"><span class="params"> RejectedExecutionHandler handler)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (corePoolSize < <span class="number">0</span> ||</span><br><span class="line"> maximumPoolSize <= <span class="number">0</span> ||</span><br><span class="line"> maximumPoolSize < corePoolSize ||</span><br><span class="line"> keepAliveTime < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException();</span><br><span class="line"> <span class="keyword">if</span> (workQueue == <span class="keyword">null</span> || threadFactory == <span class="keyword">null</span> || handler == <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>.acc = System.getSecurityManager() == <span class="keyword">null</span> ?</span><br><span class="line"> <span class="keyword">null</span> :</span><br><span class="line"> AccessController.getContext();</span><br><span class="line"> <span class="keyword">this</span>.corePoolSize = corePoolSize;</span><br><span class="line"> <span class="keyword">this</span>.maximumPoolSize = maximumPoolSize;</span><br><span class="line"> <span class="keyword">this</span>.workQueue = workQueue;</span><br><span class="line"> <span class="keyword">this</span>.keepAliveTime = unit.toNanos(keepAliveTime);</span><br><span class="line"> <span class="keyword">this</span>.threadFactory = threadFactory;</span><br><span class="line"> <span class="keyword">this</span>.handler = handler;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<p>corePoolSize :线程池中常驻核心线程数</p>
<p>maximumPoolSize:线程池能够最大容纳线程数</p>
<p>keepAliveTime:多余线程存活时间</p>
<p>unit : keepAliveTime的单位</p>
<p>workQueue 任务队列</p>
<p>threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,<strong>一般默认即可</strong></p>
<p>handler:拒绝策略,表示队列满了并且工作线程大于等于线程池的最大数目就拒绝再有线程进入</p>
<h5 id="线程池的4种拒绝策略"><a href="#线程池的4种拒绝策略" class="headerlink" title="线程池的4种拒绝策略"></a>线程池的4种拒绝策略</h5><p>AbortPolicy 直接抛出RejectExecutionException异常阻止系统正常运行</p>
<p>CallerRunsPolicy 调用者运行的一种调节机制,该策略不会抛弃任务,也不会抛出异常,而是将某些任务返回给main</p>
<p>DiscardOldestPolicy 抛弃队列中等待最久的任务,然后把当前任务加入队列舱室再次提交任务</p>
<p>DiscardPolicy 直接丢弃任务,不予任何处理也不抛出异常</p>
<h5 id="为什么线程池不能用Executors创建"><a href="#为什么线程池不能用Executors创建" class="headerlink" title="为什么线程池不能用Executors创建"></a>为什么线程池不能用Executors创建</h5><p>要用ThreadPoolExecutor创建,这样能更加明确线程池运行规则</p>
<p>理由如下</p>
<ul>
<li><p>FixedThreadPool和SingleThreadPool</p>
<p>允许的请求队列Integer.MAX_VALUE,可能会堆积大量请求,从而导致oom</p>
</li>
<li><p>CachedThreadPool和ScheduledThreadPool</p>
<p>允许创建线程数量为Integer.MAX_VALUE,可能会导致大量线程,从而oom</p>
</li>
</ul>
<h5 id="线程池代码"><a href="#线程池代码" class="headerlink" title="线程池代码"></a>线程池代码</h5><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 线程池;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.*;</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">MyThreadPoolDemo</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"> ExecutorService threadPool = <span class="keyword">new</span> ThreadPoolExecutor(<span class="number">2</span>, <span class="number">5</span>, <span class="number">1L</span>, TimeUnit.SECONDS,</span><br><span class="line"> <span class="keyword">new</span> LinkedBlockingDeque<Runnable>(<span class="number">3</span>),</span><br><span class="line"> Executors.defaultThreadFactory(),</span><br><span class="line"> <span class="keyword">new</span> ThreadPoolExecutor.DiscardPolicy());</span><br><span class="line"></span><br><span class="line"> <span class="comment">//模拟10个用户来办理业务,每个用户就是来自外部的处理线程</span></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i <= <span class="number">10</span>; i++) {</span><br><span class="line"> <span class="keyword">int</span> temp=i;</span><br><span class="line"> threadPool.execute(()->{</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t"</span>+temp+<span class="string">"办理业务"</span>);</span><br><span class="line"> });</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }<span class="keyword">finally</span> {</span><br><span class="line"> threadPool.shutdown();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<h5 id="怎么合理配置线程池"><a href="#怎么合理配置线程池" class="headerlink" title="怎么合理配置线程池"></a>怎么合理配置线程池</h5><p>两种情况</p>
<p>1 IO密集型</p>
<ul>
<li>大部分线程都阻塞,因此需要多配置线程数 CPU核数/(1-阻塞系数) 阻塞系数0.8~0.9,一般是0.9</li>
<li>另一种方法是直接CPU核数*2</li>
</ul>
<p>2 CPU密集型</p>
<p> 执行System.out.println(Runtime.getRuntime().availableProcessors()); 得出了当前CPU的核数</p>
<p> 然后 创建CPU核数+1个线程的线程池</p>
<h5 id="死锁的产生以及以及怎么解决死锁"><a href="#死锁的产生以及以及怎么解决死锁" class="headerlink" title="死锁的产生以及以及怎么解决死锁"></a>死锁的产生以及以及怎么解决死锁</h5><p>死锁是指两个或两个以上的进程在执行过程,因争夺资源而造成的一种互相等待的现象</p>
<p><strong>产生死锁</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> 死锁;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.concurrent.TimeUnit;</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">Main</span> </span>{</span><br><span class="line"> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">HoldLockThread</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> String lockA;</span><br><span class="line"> <span class="keyword">private</span> String lockB;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">HoldLockThread</span><span class="params">(String lockA, String lockB)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.lockA = lockA;</span><br><span class="line"> <span class="keyword">this</span>.lockB = lockB;</span><br><span class="line"> }</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> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">synchronized</span> (lockA) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t自己持有:"</span> + lockA + <span class="string">"\t"</span> + <span class="string">"尝试获得"</span> + lockB);</span><br><span class="line"> <span class="keyword">try</span>{</span><br><span class="line"> TimeUnit.SECONDS.sleep(<span class="number">3</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException e) {</span><br><span class="line"> e.printStackTrace();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">synchronized</span> (lockB) {</span><br><span class="line"> System.out.println(Thread.currentThread().getName() + <span class="string">"\t自己持有:"</span> + lockB + <span class="string">"\t"</span> + <span class="string">"尝试获得"</span> + lockA);</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">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>{</span><br><span class="line"> String lockA = <span class="string">"lockA"</span>;</span><br><span class="line"> String lockB = <span class="string">"lockB"</span>;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> HoldLockThread(lockA, lockB), <span class="string">"ThreadAAA"</span>).start();</span><br><span class="line"> <span class="keyword">new</span> Thread(<span class="keyword">new</span> HoldLockThread(lockB, lockA), <span class="string">"ThreadBBB"</span>).start();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<p><strong>分析</strong></p>
<p> 1 首先在idea终端 输入jps -l 查看当前运行的线程</p>
<p> 2 然后 输入 jstack XXXX(这个是要查看的线程的端口号) 查看线程详细信息<img src="/Users/jiangcheng/Library/Application Support/typora-user-images/截屏2020-03-30下午6.07.49.png" alt="截屏2020-03-30下午6.07.49" style="zoom:50%;" /></p>
</div>
<div class="article-info article-info-index">
<p class="article-more-link">
<a class="article-more-a" href="/2020/02/20/java%E5%AE%B9%E5%99%A8%E5%92%8C%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/">展开全文 >></a>
</p>
<div class="clearfix"></div>
</div>
</div>
</article>
<aside class="wrap-side-operation">
<div class="mod-side-operation">
<div class="jump-container" id="js-jump-container" style="display:none;">
<a href="javascript:void(0)" class="mod-side-operation__jump-to-top">
<i class="icon-font icon-back"></i>
</a>
<div id="js-jump-plan-container" class="jump-plan-container" style="top: -11px;">
<i class="icon-font icon-plane jump-plane"></i>
</div>
</div>
</div>
</aside>
<article id="post-集合相关" class="article article-type-post article-index" itemscope itemprop="blogPost">
<div class="article-inner">
<header class="article-header">
<h1 itemprop="name">
<a class="article-title" href="/2020/02/20/%E9%9B%86%E5%90%88%E7%9B%B8%E5%85%B3/">集合相关</a>
</h1>
<a href="/2020/02/20/%E9%9B%86%E5%90%88%E7%9B%B8%E5%85%B3/" class="archive-article-date">