-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
665 lines (319 loc) · 389 KB
/
search.xml
File metadata and controls
665 lines (319 loc) · 389 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
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
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>Java基础知识</title>
<link href="/2020/java-base/"/>
<url>/2020/java-base/</url>
<content type="html"><![CDATA[<h2 id="面向对象和面向过程的区别"><a href="#面向对象和面向过程的区别" class="headerlink" title="面向对象和面向过程的区别"></a>面向对象和面向过程的区别</h2><ul><li><strong>面向过程</strong> :<strong>面向过程性能比面向对象高。</strong> 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,<strong>面向过程没有面向对象易维护、易复用、易扩展。</strong> </li><li><strong>面向对象</strong> :<strong>面向对象易维护、易复用、易扩展。</strong> 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,<strong>面向对象性能比面向过程低</strong>。</li></ul><p>参见 issue : <a href="https://github.com/Snailclimb/JavaGuide/issues/431" target="_blank" rel="noopener">面向过程 :面向过程性能比面向对象高??</a></p><blockquote><p>这个并不是根本原因,面向过程也需要分配内存,计算内存偏移量,Java性能差的主要原因并不是因为它是面向对象语言,而是Java是半编译语言,最终的执行代码并不是可以直接被CPU执行的二进制机械码。</p><p>而面向过程语言大多都是直接编译成机械码在电脑上执行,并且其它一些面向过程的脚本语言性能也并不一定比Java好。</p></blockquote><h2 id="Java-语言有哪些特点"><a href="#Java-语言有哪些特点" class="headerlink" title="Java 语言有哪些特点?"></a>Java 语言有哪些特点?</h2><ol><li>简单易学;</li><li>面向对象(封装,继承,多态);</li><li>平台无关性( Java 虚拟机实现平台无关性);</li><li>可靠性;</li><li>安全性;</li><li>支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);</li><li>支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);</li><li>编译与解释并存;</li></ol><blockquote><p>修正(参见: <a href="https://github.com/Snailclimb/JavaGuide/issues/544" target="_blank" rel="noopener">issue#544</a>):C++11开始(2011年的时候),C++就引入了多线程库,在windows、linux、macos都可以使用<code>std::thread</code>和<code>std::async</code>来创建线程。参考链接:<a href="http://www.cplusplus.com/reference/thread/thread/?kw=thread" target="_blank" rel="noopener">http://www.cplusplus.com/reference/thread/thread/?kw=thread</a></p></blockquote><h2 id="关于-JVM-JDK-和-JRE-最详细通俗的解答"><a href="#关于-JVM-JDK-和-JRE-最详细通俗的解答" class="headerlink" title="关于 JVM JDK 和 JRE 最详细通俗的解答"></a>关于 JVM JDK 和 JRE 最详细通俗的解答</h2><h3 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h3><p>Java虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。</p><p><strong>什么是字节码?采用字节码的好处是什么?</strong></p><blockquote><p>在 Java 中,JVM可以理解的代码就叫做<code>字节码</code>(即扩展名为 <code>.class</code> 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java程序无须重新编译便可在多种不同操作系统的计算机上运行。</p></blockquote><p><strong>Java 程序从源代码到运行一般有下面3步:</strong></p><p><img src="Java%E7%A8%8B%E5%BA%8F%E8%BF%90%E8%A1%8C%E8%BF%87%E7%A8%8B.png" alt="Java程序运行过程"></p><p>我们需要格外注意的是 .class->机器码 这一步。在这一步 JVM 类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了 JIT 编译器,而JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言。</p><blockquote><p>HotSpot采用了惰性评估(Lazy Evaluation)的做法,根据二八定律,消耗大部分系统资源的只有那一小部分的代码(热点代码),而这也就是JIT所需要编译的部分。JVM会根据代码每次被执行的情况收集信息并相应地做出一些优化,因此执行的次数越多,它的速度就越快。JDK 9引入了一种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了JIT预热等各方面的开销。JDK支持分层编译和AOT协作使用。但是 ,AOT 编译器的编译质量是肯定比不上 JIT 编译器的。</p></blockquote><p><strong>总结:</strong></p><p>Java虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在。 </p><h3 id="JDK-和-JRE"><a href="#JDK-和-JRE" class="headerlink" title="JDK 和 JRE"></a>JDK 和 JRE</h3><p>JDK是Java Development Kit,它是功能齐全的Java SDK。它拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc和jdb)。它能够创建和编译程序。</p><p>JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java虚拟机(JVM),Java类库,java命令和其他的一些基础构件。但是,它不能用于创建新程序。</p><p>如果你只是为了运行一下 Java 程序的话,那么你只需要安装 JRE 就可以了。如果你需要进行一些 Java 编程方面的工作,那么你就需要安装JDK了。但是,这不是绝对的。有时,即使您不打算在计算机上进行任何Java开发,仍然需要安装JDK。例如,如果要使用JSP部署Web应用程序,那么从技术上讲,您只是在应用程序服务器中运行Java程序。那你为什么需要JDK呢?因为应用程序服务器会将 JSP 转换为 Java servlet,并且需要使用 JDK 来编译 servlet。</p><h2 id="Oracle-JDK-和-OpenJDK-的对比"><a href="#Oracle-JDK-和-OpenJDK-的对比" class="headerlink" title="Oracle JDK 和 OpenJDK 的对比"></a>Oracle JDK 和 OpenJDK 的对比</h2><p>可能在看这个问题之前很多人和我一样并没有接触和使用过 OpenJDK 。那么Oracle和OpenJDK之间是否存在重大差异?下面我通过收集到的一些资料,为你解答这个被很多人忽视的问题。</p><p>对于Java 7,没什么关键的地方。OpenJDK项目主要基于Sun捐赠的HotSpot源代码。此外,OpenJDK被选为Java 7的参考实现,由Oracle工程师维护。关于JVM,JDK,JRE和OpenJDK之间的区别,Oracle博客帖子在2012年有一个更详细的答案:</p><blockquote><p>问:OpenJDK存储库中的源代码与用于构建Oracle JDK的代码之间有什么区别?</p><p>答:非常接近 - 我们的Oracle JDK版本构建过程基于OpenJDK 7构建,只添加了几个部分,例如部署代码,其中包括Oracle的Java插件和Java WebStart的实现,以及一些封闭的源代码派对组件,如图形光栅化器,一些开源的第三方组件,如Rhino,以及一些零碎的东西,如附加文档或第三方字体。展望未来,我们的目的是开源Oracle JDK的所有部分,除了我们考虑商业功能的部分。</p></blockquote><p><strong>总结:</strong></p><ol><li>Oracle JDK大概每6个月发一次主要版本,而OpenJDK版本大概每三个月发布一次。但这不是固定的,我觉得了解这个没啥用处。详情参见:<a href="https://blogs.oracle.com/java-platform-group/update-and-faq-on-the-java-se-release-cadence。" target="_blank" rel="noopener">https://blogs.oracle.com/java-platform-group/update-and-faq-on-the-java-se-release-cadence。</a></li><li>OpenJDK 是一个参考模型并且是完全开源的,而Oracle JDK是OpenJDK的一个实现,并不是完全开源的;</li><li>Oracle JDK 比 OpenJDK 更稳定。OpenJDK和Oracle JDK的代码几乎相同,但Oracle JDK有更多的类和一些错误修复。因此,如果您想开发企业/商业软件,我建议您选择Oracle JDK,因为它经过了彻底的测试和稳定。某些情况下,有些人提到在使用OpenJDK 可能会遇到了许多应用程序崩溃的问题,但是,只需切换到Oracle JDK就可以解决问题;</li><li>在响应性和JVM性能方面,Oracle JDK与OpenJDK相比提供了更好的性能;</li><li>Oracle JDK不会为即将发布的版本提供长期支持,用户每次都必须通过更新到最新版本获得支持来获取最新版本;</li><li>Oracle JDK根据二进制代码许可协议获得许可,而OpenJDK根据GPL v2许可获得许可。</li></ol><h2 id="Java和C-的区别"><a href="#Java和C-的区别" class="headerlink" title="Java和C++的区别?"></a>Java和C++的区别?</h2><p>我知道很多人没学过 C++,但是面试官就是没事喜欢拿咱们 Java 和 C++ 比呀!没办法!!!就算没学过C++,也要记下来!</p><ul><li>都是面向对象的语言,都支持封装、继承和多态</li><li>Java 不提供指针来直接访问内存,程序内存更加安全</li><li>Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。</li><li>Java 有自动内存管理机制,不需要程序员手动释放无用内存</li><li><strong>在 C 语言中,字符串或字符数组最后都会有一个额外的字符‘\0’来表示结束。但是,Java 语言中没有结束符这一概念。</strong> 这是一个值得深度思考的问题,具体原因推荐看这篇文章: <a href="https://blog.csdn.net/sszgg2006/article/details/49148189" target="_blank" rel="noopener">https://blog.csdn.net/sszgg2006/article/details/49148189</a> 。</li></ul><h2 id="什么是-Java-程序的主类-应用程序和小程序的主类有何不同"><a href="#什么是-Java-程序的主类-应用程序和小程序的主类有何不同" class="headerlink" title="什么是 Java 程序的主类 应用程序和小程序的主类有何不同?"></a>什么是 Java 程序的主类 应用程序和小程序的主类有何不同?</h2><p>一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这个主类是指包含 main()方法的类。而在 Java 小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是 public 类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点。</p><h2 id="Java-应用程序与小程序之间有哪些差别"><a href="#Java-应用程序与小程序之间有哪些差别" class="headerlink" title="Java 应用程序与小程序之间有哪些差别?"></a>Java 应用程序与小程序之间有哪些差别?</h2><p>简单说应用程序是从主线程启动(也就是 <code>main()</code> 方法)。applet 小程序没有 <code>main()</code> 方法,主要是嵌在浏览器页面上运行(调用<code>init()</code>或者<code>run()</code>来启动),嵌入浏览器这点跟 flash 的小游戏类似。</p><h2 id="字符型常量和字符串常量的区别"><a href="#字符型常量和字符串常量的区别" class="headerlink" title="字符型常量和字符串常量的区别?"></a>字符型常量和字符串常量的区别?</h2><ol><li>形式上: 字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符</li><li>含义上: 字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)</li><li>占内存大小 字符常量只占2个字节; 字符串常量占若干个字节 (<strong>注意: char在Java中占两个字节</strong>)</li></ol><blockquote><p>java编程思想第四版:2.2.2节<br><img src="Java%E7%B1%BB%E5%9E%8B%E5%A4%A7%E5%B0%8F.jpg" alt="Java类型大小"></p></blockquote><h2 id="构造器-Constructor-是否可被-override"><a href="#构造器-Constructor-是否可被-override" class="headerlink" title="构造器 Constructor 是否可被 override?"></a>构造器 Constructor 是否可被 override?</h2><p>在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以 Constructor 也就不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。</p><h2 id="重载和重写的区别"><a href="#重载和重写的区别" class="headerlink" title="重载和重写的区别"></a>重载和重写的区别</h2><h4 id="重载"><a href="#重载" class="headerlink" title="重载"></a>重载</h4><p>发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同。</p><p>下面是《Java核心技术》对重载这个概念的介绍:</p><p><img src="Java%E9%87%8D%E8%BD%BD.jpg" alt="Java重载"> </p><h4 id="重写"><a href="#重写" class="headerlink" title="重写"></a>重写</h4><p> 重写是子类对父类的允许访问的方法的实现过程进行重新编写,发生在子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类。另外,如果父类方法访问修饰符为 private 则子类就不能重写该方法。<strong>也就是说方法提供的行为改变,而方法的外貌并没有改变。</strong> </p><h2 id="Java-面向对象编程三大特性-封装-继承-多态"><a href="#Java-面向对象编程三大特性-封装-继承-多态" class="headerlink" title="Java 面向对象编程三大特性: 封装 继承 多态"></a>Java 面向对象编程三大特性: 封装 继承 多态</h2><h3 id="封装"><a href="#封装" class="headerlink" title="封装"></a>封装</h3><p>封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。</p><h3 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h3><p>继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。</p><p><strong>关于继承如下 3 点请记住:</strong></p><ol><li>子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,<strong>只是拥有</strong>。</li><li>子类可以拥有自己属性和方法,即子类可以对父类进行扩展。</li><li>子类可以用自己的方式实现父类的方法。(以后介绍)。</li></ol><h3 id="多态"><a href="#多态" class="headerlink" title="多态"></a>多态</h3><p>所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。</p><p>在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。</p><h2 id="String-StringBuffer-和-StringBuilder-的区别是什么-String-为什么是不可变的"><a href="#String-StringBuffer-和-StringBuilder-的区别是什么-String-为什么是不可变的" class="headerlink" title="String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?"></a>String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?</h2><p><strong>可变性</strong></p><p>简单的来说:String 类中使用 final 关键字修饰字符数组来保存字符串,<code>private final char value[]</code>,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串<code>char[]value</code> 但是没有用 final 关键字修饰,所以这两种对象都是可变的。</p><p>StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以自行查阅源码。</p><p>AbstractStringBuilder.java</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></pre></td><td class="code"><pre><span class="line"><span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractStringBuilder</span> <span class="keyword">implements</span> <span class="title">Appendable</span>, <span class="title">CharSequence</span> </span>{</span><br><span class="line"> <span class="keyword">char</span>[] value;</span><br><span class="line"> <span class="keyword">int</span> count;</span><br><span class="line"> AbstractStringBuilder() {</span><br><span class="line"> }</span><br><span class="line"> AbstractStringBuilder(<span class="keyword">int</span> capacity) {</span><br><span class="line"> value = <span class="keyword">new</span> <span class="keyword">char</span>[capacity];</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p><strong>线程安全性</strong></p><p>String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。 </p><p><strong>性能</strong></p><p>每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。</p><p><strong>对于三者使用的总结:</strong> </p><ol><li>操作少量的数据: 适用String</li><li>单线程操作字符串缓冲区下操作大量数据: 适用StringBuilder</li><li>多线程操作字符串缓冲区下操作大量数据: 适用StringBuffer</li></ol><h2 id="自动装箱与拆箱"><a href="#自动装箱与拆箱" class="headerlink" title="自动装箱与拆箱"></a>自动装箱与拆箱</h2><ul><li><strong>装箱</strong>:将基本类型用它们对应的引用类型包装起来;</li><li><strong>拆箱</strong>:将包装类型转换为基本数据类型;</li></ul><h2 id="在一个静态方法内调用一个非静态成员为什么是非法的"><a href="#在一个静态方法内调用一个非静态成员为什么是非法的" class="headerlink" title="在一个静态方法内调用一个非静态成员为什么是非法的?"></a>在一个静态方法内调用一个非静态成员为什么是非法的?</h2><p>由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。</p><h2 id="在-Java-中定义一个不做事且没有参数的构造方法的作用"><a href="#在-Java-中定义一个不做事且没有参数的构造方法的作用" class="headerlink" title="在 Java 中定义一个不做事且没有参数的构造方法的作用"></a>在 Java 中定义一个不做事且没有参数的构造方法的作用</h2><p>Java 程序在执行子类的构造方法之前,如果没有用 <code>super()</code>来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 <code>super()</code>来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。 </p><h2 id="import-java和javax有什么区别?"><a href="#import-java和javax有什么区别?" class="headerlink" title="import java和javax有什么区别?"></a>import java和javax有什么区别?</h2><p>刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来使用。然而随着时间的推移,javax 逐渐地扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包确实太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。</p><p>所以,实际上java和javax没有区别。这都是一个名字。</p><h2 id="接口和抽象类的区别是什么?"><a href="#接口和抽象类的区别是什么?" class="headerlink" title="接口和抽象类的区别是什么?"></a>接口和抽象类的区别是什么?</h2><ol><li>接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法。</li><li>接口中除了static、final变量,不能有其他变量,而抽象类中则不一定。</li><li>一个类可以实现多个接口,但只能实现一个抽象类。接口自己本身可以通过extends关键字扩展多个接口。</li><li>接口方法默认修饰符是public,抽象方法可以有public、protected和default这些修饰符(抽象方法就是为了被重写所以不能使用private关键字修饰!)。 </li><li>从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。</li></ol><p>备注:在JDK8中,接口也可以定义静态方法,可以直接用接口名调用。实现类和实现是不可以调用的。如果同时实现两个接口,接口中定义了一样的默认方法,则必须重写,不然会报错。(详见issue:<a href="https://github.com/Snailclimb/JavaGuide/issues/146" target="_blank" rel="noopener">https://github.com/Snailclimb/JavaGuide/issues/146</a>)</p><h2 id="成员变量与局部变量的区别有哪些?"><a href="#成员变量与局部变量的区别有哪些?" class="headerlink" title="成员变量与局部变量的区别有哪些?"></a>成员变量与局部变量的区别有哪些?</h2><ol><li>从语法形式上看:成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰。</li><li>从变量在内存中的存储方式来看:如果成员变量是使用<code>static</code>修饰的,那么这个成员变量是属于类的,如果没有使用<code>static</code>修饰,这个成员变量是属于实例的。而对象存在于堆内存,局部变量则存在于栈内存。</li><li>从变量在内存中的生存时间上看:成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。</li><li>成员变量如果没有被赋初值:则会自动以类型的默认值而赋值(一种情况例外:被 final 修饰的成员变量也必须显式地赋值),而局部变量则不会自动赋值。</li></ol><h2 id="创建一个对象用什么运算符-对象实体与对象引用有何不同"><a href="#创建一个对象用什么运算符-对象实体与对象引用有何不同" class="headerlink" title="创建一个对象用什么运算符?对象实体与对象引用有何不同?"></a>创建一个对象用什么运算符?对象实体与对象引用有何不同?</h2><p>new运算符,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)。</p><h2 id="什么是方法的返回值-返回值在类的方法里的作用是什么"><a href="#什么是方法的返回值-返回值在类的方法里的作用是什么" class="headerlink" title="什么是方法的返回值?返回值在类的方法里的作用是什么?"></a>什么是方法的返回值?返回值在类的方法里的作用是什么?</h2><p>方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!</p><h2 id="一个类的构造方法的作用是什么-若一个类没有声明构造方法,该程序能正确执行吗-为什么"><a href="#一个类的构造方法的作用是什么-若一个类没有声明构造方法,该程序能正确执行吗-为什么" class="headerlink" title="一个类的构造方法的作用是什么? 若一个类没有声明构造方法,该程序能正确执行吗? 为什么?"></a>一个类的构造方法的作用是什么? 若一个类没有声明构造方法,该程序能正确执行吗? 为什么?</h2><p>主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。</p><h2 id="构造方法有哪些特性?"><a href="#构造方法有哪些特性?" class="headerlink" title="构造方法有哪些特性?"></a>构造方法有哪些特性?</h2><ol><li>名字与类名相同。</li><li>没有返回值,但不能用void声明构造函数。</li><li>生成类的对象时自动执行,无需调用。</li></ol><h2 id="静态方法和实例方法有何不同"><a href="#静态方法和实例方法有何不同" class="headerlink" title="静态方法和实例方法有何不同"></a>静态方法和实例方法有何不同</h2><ol><li><p>在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 </p></li><li><p>静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。</p></li></ol><h2 id="对象的相等与指向他们的引用相等-两者有什么不同"><a href="#对象的相等与指向他们的引用相等-两者有什么不同" class="headerlink" title="对象的相等与指向他们的引用相等,两者有什么不同?"></a>对象的相等与指向他们的引用相等,两者有什么不同?</h2><p>对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们指向的内存地址是否相等。</p><h2 id="在调用子类构造方法之前会先调用父类没有参数的构造方法-其目的是"><a href="#在调用子类构造方法之前会先调用父类没有参数的构造方法-其目的是" class="headerlink" title="在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?"></a>在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?</h2><p>帮助子类做初始化工作。</p><h2 id="与-equals-重要"><a href="#与-equals-重要" class="headerlink" title="== 与 equals(重要)"></a>== 与 equals(重要)</h2><p><strong>==</strong> : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。</p><p><strong>equals()</strong> : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:</p><ul><li>情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。</li><li>情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。</li></ul><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></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">test1</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 a = <span class="keyword">new</span> String(<span class="string">"ab"</span>); <span class="comment">// a 为一个引用</span></span><br><span class="line"> String b = <span class="keyword">new</span> String(<span class="string">"ab"</span>); <span class="comment">// b为另一个引用,对象的内容一样</span></span><br><span class="line"> String aa = <span class="string">"ab"</span>; <span class="comment">// 放在常量池中</span></span><br><span class="line"> String bb = <span class="string">"ab"</span>; <span class="comment">// 从常量池中查找</span></span><br><span class="line"> <span class="keyword">if</span> (aa == bb) <span class="comment">// true</span></span><br><span class="line"> System.out.println(<span class="string">"aa==bb"</span>);</span><br><span class="line"> <span class="keyword">if</span> (a == b) <span class="comment">// false,非同一对象</span></span><br><span class="line"> System.out.println(<span class="string">"a==b"</span>);</span><br><span class="line"> <span class="keyword">if</span> (a.equals(b)) <span class="comment">// true</span></span><br><span class="line"> System.out.println(<span class="string">"aEQb"</span>);</span><br><span class="line"> <span class="keyword">if</span> (<span class="number">42</span> == <span class="number">42.0</span>) { <span class="comment">// true</span></span><br><span class="line"> System.out.println(<span class="string">"true"</span>);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><strong>说明:</strong></p><ul><li>String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。</li><li>当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。</li></ul><h2 id="hashCode-与-equals-重要"><a href="#hashCode-与-equals-重要" class="headerlink" title="hashCode 与 equals (重要)"></a>hashCode 与 equals (重要)</h2><p>面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”</p><h3 id="hashCode()介绍"><a href="#hashCode()介绍" class="headerlink" title="hashCode()介绍"></a>hashCode()介绍</h3><p>hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。</p><p>散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)</p><h3 id="为什么要有-hashCode"><a href="#为什么要有-hashCode" class="headerlink" title="为什么要有 hashCode"></a>为什么要有 hashCode</h3><p><strong>我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:</strong> 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 <code>equals()</code>方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。</p><p>通过我们可以看出:<code>hashCode()</code> 的作用就是<strong>获取哈希码</strong>,也称为散列码;它实际上是返回一个int整数。这个<strong>哈希码的作用</strong>是确定该对象在哈希表中的索引位置。<strong><code>hashCode()</code>在散列表中才有用,在其它情况下没用</strong>。在散列表中hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。</p><h3 id="hashCode()与equals()的相关规定"><a href="#hashCode()与equals()的相关规定" class="headerlink" title="hashCode()与equals()的相关规定"></a>hashCode()与equals()的相关规定</h3><ol><li>如果两个对象相等,则hashcode一定也是相同的</li><li>两个对象相等,对两个对象分别调用equals方法都返回true</li><li>两个对象有相同的hashcode值,它们也不一定是相等的</li><li><strong>因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖</strong></li><li>hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)</li></ol><p>推荐阅读:<a href="https://www.cnblogs.com/skywang12345/p/3324958.html" target="_blank" rel="noopener">Java hashCode() 和 equals()的若干问题解答</a></p><h2 id="为什么Java中只有值传递?"><a href="#为什么Java中只有值传递?" class="headerlink" title="为什么Java中只有值传递?"></a>为什么Java中只有值传递?</h2><p> <a href="https://github.com/Snailclimb/JavaGuide/blob/master/docs/essential-content-for-interview/PreparingForInterview/%E5%BA%94%E5%B1%8A%E7%94%9F%E9%9D%A2%E8%AF%95%E6%9C%80%E7%88%B1%E9%97%AE%E7%9A%84%E5%87%A0%E9%81%93Java%E5%9F%BA%E7%A1%80%E9%97%AE%E9%A2%98.md#%E4%B8%80-%E4%B8%BA%E4%BB%80%E4%B9%88-java-%E4%B8%AD%E5%8F%AA%E6%9C%89%E5%80%BC%E4%BC%A0%E9%80%92" target="_blank" rel="noopener">为什么Java中只有值传递?</a></p><h2 id="简述线程、程序、进程的基本概念。以及他们之间关系是什么"><a href="#简述线程、程序、进程的基本概念。以及他们之间关系是什么" class="headerlink" title="简述线程、程序、进程的基本概念。以及他们之间关系是什么?"></a>简述线程、程序、进程的基本概念。以及他们之间关系是什么?</h2><p><strong>线程</strong>与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。 </p><p><strong>程序</strong>是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。</p><p><strong>进程</strong>是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。<br>线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。</p><h2 id="线程有哪些基本状态"><a href="#线程有哪些基本状态" class="headerlink" title="线程有哪些基本状态?"></a>线程有哪些基本状态?</h2><p>Java 线程在运行的生命周期中的指定时刻只可能处于下面6种不同状态的其中一个状态(图源《Java 并发编程艺术》4.1.4节)。</p><p><img src="Java%E7%BA%BF%E7%A8%8B%E7%9A%84%E7%8A%B6%E6%80%81.png" alt="Java线程的状态"></p><p>线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程状态变迁如下图所示(图源《Java 并发编程艺术》4.1.4节):</p><p><img src="Java%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E5%8F%98%E8%BF%81.png" alt="Java线程状态变迁"></p><p>由上图可以看出:</p><p>线程创建之后它将处于 <strong>NEW(新建)</strong> 状态,调用 <code>start()</code> 方法后开始运行,线程这时候处于 <strong>READY(可运行)</strong> 状态。可运行状态的线程获得了 cpu 时间片(timeslice)后就处于 <strong>RUNNING(运行)</strong> 状态。</p><blockquote><p>操作系统隐藏 Java虚拟机(JVM)中的 READY 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:<a href="https://howtodoinjava.com/" target="_blank" rel="noopener">HowToDoInJava</a>:<a href="https://howtodoinjava.com/java/multi-threading/java-thread-life-cycle-and-thread-states/" target="_blank" rel="noopener">Java Thread Life Cycle and Thread States</a>),所以 Java 系统一般将这两个状态统称为 <strong>RUNNABLE(运行中)</strong> 状态 。</p></blockquote><p><img src="RUNNABLE-VS-RUNNING.png.png" alt="RUNNABLE-VS-RUNNING"></p><p>当线程执行 <code>wait()</code>方法之后,线程进入 <strong>WAITING(等待)</strong>状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而 <strong>TIME_WAITING(超时等待)</strong> 状态相当于在等待状态的基础上增加了超时限制,比如通过 <code>sleep(long millis)</code>方法或 <code>wait(long millis)</code>方法可以将 Java 线程置于 TIMED WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到 <strong>BLOCKED(阻塞)</strong> 状态。线程在执行 Runnable 的<code>run()</code>方法之后将会进入到 <strong>TERMINATED(终止)</strong> 状态。</p><h2 id="关于-final-关键字的一些总结"><a href="#关于-final-关键字的一些总结" class="headerlink" title="关于 final 关键字的一些总结"></a>关于 final 关键字的一些总结</h2><p>final关键字主要用在三个地方:变量、方法、类。</p><ol><li>对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。</li><li>当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。</li><li>使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为final。</li></ol><h2 id="Java-中的异常处理"><a href="#Java-中的异常处理" class="headerlink" title="Java 中的异常处理"></a>Java 中的异常处理</h2><h3 id="Java异常类层次结构图"><a href="#Java异常类层次结构图" class="headerlink" title="Java异常类层次结构图"></a>Java异常类层次结构图</h3><p><img src="Exception.png" alt="Java异常类层次结构图"></p><p>在 Java 中,所有的异常都有一个共同的祖先java.lang包中的 <strong>Throwable类</strong>。Throwable: 有两个重要的子类:<strong>Exception(异常)</strong> 和 <strong>Error(错误)</strong> ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。</p><p><strong>Error(错误):是程序无法处理的错误</strong>,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。</p><p>这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。</p><p><strong>Exception(异常):是程序本身可以处理的异常</strong>。Exception 类有一个重要的子类 <strong>RuntimeException</strong>。RuntimeException 异常由Java虚拟机抛出。<strong>NullPointerException</strong>(要访问的变量没有引用任何对象时,抛出该异常)、<strong>ArithmeticException</strong>(算术运算异常,一个整数除以0时,抛出该异常)和 <strong>ArrayIndexOutOfBoundsException</strong> (下标越界异常)。</p><p><strong>注意:异常和错误的区别:异常能被程序本身处理,错误是无法处理。</strong></p><h3 id="Throwable类常用方法"><a href="#Throwable类常用方法" class="headerlink" title="Throwable类常用方法"></a>Throwable类常用方法</h3><ul><li><strong>public string getMessage()</strong>:返回异常发生时的简要描述</li><li><strong>public string toString()</strong>:返回异常发生时的详细信息</li><li><strong>public string getLocalizedMessage()</strong>:返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以生成本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同</li><li><strong>public void printStackTrace()</strong>:在控制台上打印Throwable对象封装的异常信息</li></ul><h3 id="异常处理总结"><a href="#异常处理总结" class="headerlink" title="异常处理总结"></a>异常处理总结</h3><ul><li><strong>try 块:</strong> 用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。</li><li><strong>catch 块:</strong> 用于处理try捕获到的异常。</li><li><strong>finally 块:</strong> 无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return<br>语句时,finally语句块将在方法返回之前被执行。</li></ul><p><strong>在以下4种特殊情况下,finally块不会被执行:</strong></p><ol><li>在finally语句块第一行发生了异常。 因为在其他行,finally块还是会得到执行</li><li>在前面的代码中用了System.exit(int)已退出程序。 exit是带参函数 ;若该语句在异常语句之后,finally会执行</li><li>程序所在的线程死亡。</li><li>关闭CPU。</li></ol><p>下面这部分内容来自issue:<a href="https://github.com/Snailclimb/JavaGuide/issues/190" target="_blank" rel="noopener">https://github.com/Snailclimb/JavaGuide/issues/190</a>。</p><p><strong>注意:</strong> 当try语句和finally语句中都有return语句时,在方法返回之前,finally语句的内容将被执行,并且finally语句的返回值将会覆盖原始的返回值。如下:</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="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">int</span> <span class="title">f</span><span class="params">(<span class="keyword">int</span> value)</span> </span>{</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">return</span> value * value;</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (value == <span class="number">2</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果调用 <code>f(2)</code>,返回值将是0,因为finally语句的返回值覆盖了try语句块的返回值。</p><h2 id="Java序列化中如果有些字段不想进行序列化,怎么办?"><a href="#Java序列化中如果有些字段不想进行序列化,怎么办?" class="headerlink" title="Java序列化中如果有些字段不想进行序列化,怎么办?"></a>Java序列化中如果有些字段不想进行序列化,怎么办?</h2><p>对于不想进行序列化的变量,使用transient关键字修饰。</p><p>transient关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。transient只能修饰变量,不能修饰类和方法。</p><h2 id="获取用键盘输入常用的两种方法"><a href="#获取用键盘输入常用的两种方法" class="headerlink" title="获取用键盘输入常用的两种方法"></a>获取用键盘输入常用的两种方法</h2><p>方法1:通过 Scanner</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">Scanner input = <span class="keyword">new</span> Scanner(System.in);</span><br><span class="line">String s = input.nextLine();</span><br><span class="line">input.close();</span><br></pre></td></tr></table></figure><p>方法2:通过 BufferedReader </p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">BufferedReader input = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> InputStreamReader(System.in)); </span><br><span class="line">String s = input.readLine();</span><br></pre></td></tr></table></figure><h2 id="Java-中-IO-流"><a href="#Java-中-IO-流" class="headerlink" title="Java 中 IO 流"></a>Java 中 IO 流</h2><h3 id="Java-中-IO-流分为几种"><a href="#Java-中-IO-流分为几种" class="headerlink" title="Java 中 IO 流分为几种?"></a>Java 中 IO 流分为几种?</h3><ul><li>按照流的流向分,可以分为输入流和输出流;</li><li>按照操作单元划分,可以划分为字节流和字符流;</li><li>按照流的角色划分为节点流和处理流。</li></ul><p>Java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。</p><ul><li>InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。</li><li>OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。</li></ul><p>按操作方式分类结构图:</p><p><img src="IO-%E6%93%8D%E4%BD%9C%E6%96%B9%E5%BC%8F%E5%88%86%E7%B1%BB.png" alt="IO-操作方式分类"></p><p>按操作对象分类结构图:</p><p><img src="IO-%E6%93%8D%E4%BD%9C%E5%AF%B9%E8%B1%A1%E5%88%86%E7%B1%BB.png" alt="IO-操作对象分类"></p><h3 id="既然有了字节流-为什么还要有字符流"><a href="#既然有了字节流-为什么还要有字符流" class="headerlink" title="既然有了字节流,为什么还要有字符流?"></a>既然有了字节流,为什么还要有字符流?</h3><p>问题本质想问:<strong>不管是文件读写还是网络发送接收,信息的最小存储单元都是字节,那为什么 I/O 流操作要分为字节流操作和字符流操作呢?</strong></p><p>回答:字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。</p><h3 id="BIO-NIO-AIO-有什么区别"><a href="#BIO-NIO-AIO-有什么区别" class="headerlink" title="BIO,NIO,AIO 有什么区别?"></a>BIO,NIO,AIO 有什么区别?</h3><ul><li><strong>BIO (Blocking I/O):</strong> 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。</li><li><strong>NIO (New I/O):</strong> NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 <code>Socket</code> 和 <code>ServerSocket</code> 相对应的 <code>SocketChannel</code> 和 <code>ServerSocketChannel</code> 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发</li><li><strong>AIO (Asynchronous I/O):</strong> AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。</li></ul><h2 id="常见关键字总结-static-final-this-super"><a href="#常见关键字总结-static-final-this-super" class="headerlink" title="常见关键字总结:static,final,this,super"></a>常见关键字总结:static,final,this,super</h2><p>详见笔主的这篇文章: <a href="https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Basis/final、static、this、super.md" target="_blank" rel="noopener">https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Basis/final、static、this、super.md</a></p><h2 id="Collections-工具类和-Arrays-工具类常见方法总结"><a href="#Collections-工具类和-Arrays-工具类常见方法总结" class="headerlink" title="Collections 工具类和 Arrays 工具类常见方法总结"></a>Collections 工具类和 Arrays 工具类常见方法总结</h2><p>详见笔主的这篇文章: <a href="https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Basis/Arrays,CollectionsCommonMethods.md" target="_blank" rel="noopener">https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Basis/Arrays,CollectionsCommonMethods.md</a></p><h3 id="深拷贝-vs-浅拷贝"><a href="#深拷贝-vs-浅拷贝" class="headerlink" title="深拷贝 vs 浅拷贝"></a>深拷贝 vs 浅拷贝</h3><ol><li><strong>浅拷贝</strong>:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。</li><li><strong>深拷贝</strong>:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。</li></ol><p><img src="java-deep-and-shallow-copy.jpg" alt="deep and shallow copy"></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></pre></td><td class="code"><pre><span class="line"><span class="comment">// 深拷贝</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">deepClone</span><span class="params">( Object obj)</span></span>{</span><br><span class="line"> Object cloneObj = <span class="keyword">null</span>;</span><br><span class="line"> ObjectOutputStream obs = <span class="keyword">null</span>;</span><br><span class="line"> ObjectInputStream ois = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ByteArrayOutputStream out = <span class="keyword">new</span> ByteArrayOutputStream();</span><br><span class="line"> obs = <span class="keyword">new</span> ObjectOutputStream(out);</span><br><span class="line"> obs.writeObject(obj);</span><br><span class="line"> ByteArrayInputStream ios = <span class="keyword">new</span> ByteArrayInputStream(out.toByteArray());</span><br><span class="line"> ois = <span class="keyword">new</span> ObjectInputStream(ios);</span><br><span class="line"> cloneObj = ois.readObject();</span><br><span class="line"> } <span class="keyword">catch</span> (Exception e) {</span><br><span class="line"> log.error(e);</span><br><span class="line"> } <span class="keyword">finally</span> {</span><br><span class="line"> <span class="keyword">if</span> (obs != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> obs.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> log.error(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (ois != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> ois.close();</span><br><span class="line"> } <span class="keyword">catch</span> (IOException e) {</span><br><span class="line"> log.error(e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> cloneObj;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p><a href="https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/Java基础知识.md" target="_blank" rel="noopener">Snailclimb - Java基础知识</a></p>]]></content>
<categories>
<category> Java </category>
<category> 基础 </category>
</categories>
<tags>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title>分析问题的7种思维方法</title>
<link href="/2019/7-ways-to-think-and-analysis-problem/"/>
<url>/2019/7-ways-to-think-and-analysis-problem/</url>
<content type="html"><![CDATA[<h2 id="6顶思考帽法"><a href="#6顶思考帽法" class="headerlink" title="6顶思考帽法"></a>6顶思考帽法</h2><p>人的思维是通过提问来引导的,一个人是积极还是消极,取决于他给自己提的问题。同样的下雨天,消极的人在统计因为下雨,给自己带来的损失,积极的人在问自己下雨我可以做哪些有意义的事情。</p><h2 id="SWOT分析法"><a href="#SWOT分析法" class="headerlink" title="SWOT分析法"></a>SWOT分析法</h2><p>四个英文单词的缩写,Strengths Weaknesses Opportunities Threats</p><p>用来确定企业自身的竞争优势、竞争劣势、机会和威胁,从而将公司的战略与公司内部资源、外部环境有机地结合起来的一种科学的分析方法。对于优势和弱势是内部环境的分析,机会和威胁是对于外部环境的分析。</p><p>这个模型可以用于多种方面,任何和商品,贸易,竞争有关系的都适用,而人也是一种商品。在工作中,这个模型同样可以帮助你理清现状,分析问题。</p><h2 id="麦肯锡7步分析法"><a href="#麦肯锡7步分析法" class="headerlink" title="麦肯锡7步分析法"></a>麦肯锡7步分析法</h2><p>善于解决问题的能力通常是缜密而系统化思维的产物,任何一个有才之士都能获得这种能力。有序的思维工作方式并不会扼杀灵感及创造力,反而会助长灵感及创造力的产生。咨询公司解决问题的方法,不仅对于解决企业问题非常有效,对于解决任何需要深入思考的复杂问题都值得借鉴。</p><ul><li><p>陈述问题</p></li><li><p>分析问题</p></li><li><p>去掉所有非关键问题</p></li><li><p>指定详细的工作计划</p></li><li><p>进行关键分析</p></li><li><p>综合调查结果构建论证</p></li><li><p>讲述来龙去脉</p></li></ul><h2 id="思维导图"><a href="#思维导图" class="headerlink" title="思维导图"></a>思维导图</h2><p>一种将放射性思考具体化的方法</p><h2 id="金字塔原理"><a href="#金字塔原理" class="headerlink" title="金字塔原理"></a>金字塔原理</h2><p>麦肯锡金字塔方法,任何事情都能归纳出一个中心点,而此中心论点可以有数个一级论据支撑,这些一级论据也可以被数个一级论据支撑,如此延伸如金字塔。</p><p>金字塔原理是一种重点突出、逻辑清晰、主次分明的逻辑思路、表达方式和规范动作。</p><p>金字塔的基本结构是:中心思想明确,结论先行,以上统下,归类分组,逻辑递进。先重要后次要,先全局后细节,先结论后原因,先结果后过程。</p><p>金字塔训练表达者:关注、挖掘受众的意图、需求、利益点、关注点、兴趣点和兴奋点,想清内容说什么、怎么说,掌握表达的标准结构、规范动作。</p><p>金字塔帮助达到沟通目的:重点突出,思路清晰,主次分明,让受众有兴趣、能理解、能接受、记得住。</p><p>搭建金字塔的具体做法是:自上而下表达,自下而上思考,纵向疑问回答/总结概括,横向归类分组/演绎归纳,序言讲故事,标题提炼思想精华。</p><h2 id="5w2h分析法"><a href="#5w2h分析法" class="headerlink" title="5w2h分析法"></a>5w2h分析法</h2><p>5W:</p><p>WHAT+WHY+WHEN+WHERE+WHO</p><p>2H:</p><p>HOW+HOW MUCH</p><p>创造力高的人,都具有善于提问题的能力,众所周知。提出一个好的问题,就意味着问题解决了一半。提问题的技巧高,可以发挥人的想象力。连续以几个“为什么”来自问,以追求其根本原因。</p><p>很多问题都是系统性的,是牵一发而动全身,真正影响大局的不是表面的问题,这种方式可以找到问题根源。选定的项目、工序或操作,都可以从这几个方面去思考。</p><h2 id="七鱼骨图分析法"><a href="#七鱼骨图分析法" class="headerlink" title="七鱼骨图分析法"></a>七鱼骨图分析法</h2><p>又名因果分析法,是一种发现问题“根本原因”的分析方法,现代工商管理教育如MBA、EMBA等将其划分为问题型、原因型及对策型鱼骨分析等几类先进技术分析。</p>]]></content>
</entry>
<entry>
<title>Github高级搜索</title>
<link href="/2019/github-advanced-search/"/>
<url>/2019/github-advanced-search/</url>
<content type="html"><![CDATA[<h2 id="根据stars或fork数量关键词去查找"><a href="#根据stars或fork数量关键词去查找" class="headerlink" title="根据stars或fork数量关键词去查找"></a>根据stars或fork数量关键词去查找</h2><p>根据stars数量搜索,java是关键字</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java stars:>10000</span><br></pre></td></tr></table></figure><h2 id="awesome加强搜索"><a href="#awesome加强搜索" class="headerlink" title="awesome加强搜索"></a>awesome加强搜索</h2><h2 id="高亮显示某一行代码"><a href="#高亮显示某一行代码" class="headerlink" title="高亮显示某一行代码"></a>高亮显示某一行代码</h2><h2 id="项目内搜索"><a href="#项目内搜索" class="headerlink" title="项目内搜索"></a>项目内搜索</h2><h2 id="搜索某地区的大佬"><a href="#搜索某地区的大佬" class="headerlink" title="搜索某地区的大佬"></a>搜索某地区的大佬</h2><p>按地理位置搜索</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">location:china</span><br><span class="line">location:chengdu</span><br></pre></td></tr></table></figure><p>按粉丝数量搜索</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">followers:>10000</span><br></pre></td></tr></table></figure><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><p>详情见下面的链接:<br><strong><a href="https://help.github.com/cn/github/searching-for-information-on-github/understanding-the-search-syntax" target="_blank" rel="noopener">Github搜索语法</a></strong></p>]]></content>
<categories>
<category> 其它 </category>
<category> GitHub </category>
</categories>
<tags>
<tag> GitHub </tag>
<tag> Search </tag>
</tags>
</entry>
<entry>
<title>内存溢出的定位和分析</title>
<link href="/2019/out-of-memory-analysis/"/>
<url>/2019/out-of-memory-analysis/</url>
<content type="html"><![CDATA[]]></content>
<categories>
<category> Java </category>
<category> JVM </category>
</categories>
<tags>
<tag> Java </tag>
<tag> JVM </tag>
<tag> Memory </tag>
</tags>
</entry>
<entry>
<title>程序死锁定位分析</title>
<link href="/2019/deadlock-analysis/"/>
<url>/2019/deadlock-analysis/</url>
<content type="html"><![CDATA[<h2 id="什么是死锁"><a href="#什么是死锁" class="headerlink" title="什么是死锁"></a>什么是死锁</h2><p>死锁是指两个或者两个以上的进程在执行过程中,因抢夺资源而造成的一种<strong>互相等待</strong>的现象,若无外力干涉它们将都无法推进下去,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性也就很低,否则就会因争夺有限的资源而陷入死锁。</p><h2 id="产生的条件"><a href="#产生的条件" class="headerlink" title="产生的条件"></a>产生的条件</h2><ul><li>互斥:共享资源X和Y只能被一个线程占用</li><li>占有且等待:线程T1已经获取共享资源X,在等待共享资源Y的时候,不释放共享资源X</li><li>不可抢占:其他线程不能强行抢占线程T1占有的资源</li><li>循环等待:线程T1等待线程T2占有的资源,线程T2等待线程T1占有的资源,这就是循环等待。</li></ul><h2 id="死锁的例子"><a href="#死锁的例子" class="headerlink" title="死锁的例子"></a>死锁的例子</h2><h2 id="分析与解决"><a href="#分析与解决" class="headerlink" title="分析与解决"></a>分析与解决</h2><p>一般客户的生产环境没有JDK分析工具,只包含JRE的运行环境,所以可以准备一个相同版本的JDK即可。<br>在生成环境解压JDK,工具都在jdk的bin目录下</p><ul><li><p>通过jps定位进程号</p></li><li><p>通过jstack查找死锁</p></li></ul><p>如果实在Windows环境上可以使用JDK自带的分析工具JConsole去定位</p><h2 id="死锁的预防"><a href="#死锁的预防" class="headerlink" title="死锁的预防"></a>死锁的预防</h2><p>破坏占有且等待条件:保证一次申请所有的资源。</p><p>破坏不可抢占条件:synchronized无法做到,synchronized申请不到资源直接进入阻塞状态。</p><p>java.util.concurrent Lock可以解决此问题。</p><p>在JDK1.7以后,synchronized 已经得到的优化,性能已经不差于Lock锁了,所以也可以考虑使用synchronized关键字。</p><h2 id="死锁的修复"><a href="#死锁的修复" class="headerlink" title="死锁的修复"></a>死锁的修复</h2><p>如果不幸线上发生了死锁,那只能重启。只有修复程序本身才能根本的去解决死锁。避免死锁的产生条件发生。</p>]]></content>
<categories>
<category> Java </category>
<category> JVM </category>
</categories>
<tags>
<tag> Java </tag>
<tag> JVM </tag>
<tag> deadlock </tag>
</tags>
</entry>
<entry>
<title>Docker创建编译环境</title>
<link href="/2019/docker-build-os/"/>
<url>/2019/docker-build-os/</url>
<content type="html"><![CDATA[<h2 id="安装Docker-Windows"><a href="#安装Docker-Windows" class="headerlink" title="安装Docker(Windows)"></a>安装Docker(Windows)</h2><p>这里使用Windows平台的Docker,使用的是Linux的内核</p><h2 id="创建Dockerfile"><a href="#创建Dockerfile" class="headerlink" title="创建Dockerfile"></a>创建Dockerfile</h2><p>在当前目录中创建一个Dockerfile文件,内容如下,同时在目录中准备apache-ant-1.10.5.tar,apache-maven-3.2.2.tar,jdk-8u201-linux-x64.tar.gz,node-v10.15.3-linux-x64.tar.xz等文件,根据需要可以使用其他包,根据文件名修改文件即可。</p><figure class="highlight plain"><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">FROM opensuse/leap:15</span><br><span class="line">MAINTAINER [email protected]</span><br><span class="line">WORKDIR /usr/local</span><br><span class="line"></span><br><span class="line">RUN zypper update -y && zypper install -y perl gcc make libxml2 perl-XML-LibXML perl-XML-Parser net-snmp net-snmp-devel rpm rpm-build zip && zypper clean -a</span><br><span class="line"></span><br><span class="line">ADD apache-ant-1.10.5.tar /usr/local</span><br><span class="line">ADD apache-maven-3.2.2.tar /usr/local</span><br><span class="line">ADD jdk-8u201-linux-x64.tar.gz /usr/local</span><br><span class="line">ADD node-v10.15.3-linux-x64.tar.xz /usr/local</span><br><span class="line"></span><br><span class="line">ENV JAVA_HOME /usr/local/jdk1.8.0_201</span><br><span class="line">ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar</span><br><span class="line">ENV NODE_HOME /usr/local/node-v10.15.3-linux-x64</span><br><span class="line">ENV ANT_HOME /usr/local/apache-ant-1.10.5</span><br><span class="line">ENV MAVEN_HOME /usr/local/apache-maven-3.2.2</span><br><span class="line">ENV PATH $PATH:$JAVA_HOME/bin:$NODE_HOME/bin:$ANT_HOME/bin:$MAVEN_HOME/bin</span><br><span class="line"></span><br><span class="line">CMD ["/bin/bash"]</span><br></pre></td></tr></table></figure><p>当然也可以不用自己准备安装包,可以通过zypper命令去下载,但是JDK还是自己准备,我在官网找下载地址,现在需要我注册登录_(:3」∠)_。</p><figure class="highlight plain"><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">FROM opensuse/leap:15</span><br><span class="line">MAINTAINER [email protected]</span><br><span class="line">WORKDIR /usr/local</span><br><span class="line"></span><br><span class="line">RUN zypper update -y \</span><br><span class="line"> && zypper install -y perl python gcc make libxml2 perl-XML-LibXML perl-XML-Parser net-snmp net-snmp-devel vim tar bzip2 zip wget rpm rpm-build \</span><br><span class="line"> && mkdir -p /usr/local/jdk /usr/local/mvn /usr/local/go /usr/local/ant /usr/local/nodejs \</span><br><span class="line"> && wget https://apache.osuosl.org/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.tar.gz \</span><br><span class="line"> && tar -xzf apache-maven-3.6.2-bin.tar.gz -C /usr/local/mvn --strip-components=1 \</span><br><span class="line"> && wget --no-check-certificate https://dl.google.com/go/go1.13.3.linux-amd64.tar.gz \</span><br><span class="line"> && tar -zxvf go1.13.3.linux-amd64.tar.gz -C /usr/local/go --strip-components=1 \</span><br><span class="line"> && wget https://archive.apache.org/dist/ant/binaries/apache-ant-1.10.7-bin.tar.gz \</span><br><span class="line"> && tar -zxvf apache-ant-1.10.7-bin.tar.gz -C /usr/local/ant --strip-components=1 \</span><br><span class="line"> && wget https://nodejs.org/dist/v10.16.3/node-v10.16.3-linux-x64.tar.xz \</span><br><span class="line"> && xz -d node-v10.16.3-linux-x64.tar.xz \</span><br><span class="line"> && tar -xvf node-v10.16.3-linux-x64.tar -C /usr/local/nodejs --strip-components=1 \</span><br><span class="line"> && ln -s -f /usr/local/mvn/bin/mvn /usr/bin/ \</span><br><span class="line"> && ln -s -f /usr/local/go/bin/go /usr/bin/ \</span><br><span class="line"> && ln -s -f /usr/local/ant/bin/ant /usr/bin/ \</span><br><span class="line"> && ln -s -f /usr/local/nodejs/bin/node /usr/bin/ \</span><br><span class="line"> && ln -s -f /usr/local/nodejs/bin/npm /usr/bin/ \</span><br><span class="line"> && rm -f apache-maven-3.6.2-bin.tar.gz \</span><br><span class="line"> && rm -f go1.13.3.linux-amd64.tar.gz \</span><br><span class="line"> && rm -f apache-ant-1.10.7-bin.tar.gz \</span><br><span class="line"> && rm -f node-v10.16.3-linux-x64.tar \</span><br><span class="line"> && zypper clean -a</span><br><span class="line"></span><br><span class="line">ADD jdk-8u201-linux-x64.tar.gz /usr/local</span><br><span class="line"></span><br><span class="line">ENV JAVA_HOME /usr/local/jdk1.8.0_201</span><br><span class="line">ENV CLASSPATH ${JAVA_HOME}/lib/</span><br><span class="line">ENV PATH $PATH:${JAVA_HOME}/bin</span><br><span class="line">ENV MAVEN_HOME /usr/local/mvn</span><br><span class="line">ENV MAVEN_CONFIG /root/.m2</span><br><span class="line">ENV ANT_HOME /usr/local/ant</span><br><span class="line">ENV NODE_HOME /usr/local/nodejs</span><br><span class="line">ENV GOROOT /usr/local/go</span><br><span class="line"></span><br><span class="line">ENTRYPOINT [ "/bin/bash" ]</span><br></pre></td></tr></table></figure><h2 id="创建本地镜像"><a href="#创建本地镜像" class="headerlink" title="创建本地镜像"></a>创建本地镜像</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build -t build-os:1.0 .</span><br></pre></td></tr></table></figure><blockquote><p>不要省略最后一个点了</p></blockquote><h2 id="提交镜像到仓库-可选"><a href="#提交镜像到仓库-可选" class="headerlink" title="提交镜像到仓库(可选)"></a>提交镜像到仓库(可选)</h2><h2 id="根据镜像创建容器并挂载本地磁盘"><a href="#根据镜像创建容器并挂载本地磁盘" class="headerlink" title="根据镜像创建容器并挂载本地磁盘"></a>根据镜像创建容器并挂载本地磁盘</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --name=build-os -v <本地代码路径>:/usr/local/main -v <本地maven仓库路径>:/root/.m2/repository/ build-os:1.0</span><br></pre></td></tr></table></figure><h2 id="进入容器编译代码"><a href="#进入容器编译代码" class="headerlink" title="进入容器编译代码"></a>进入容器编译代码</h2><figure class="highlight plain"><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">cd /usr/local/main</span><br><span class="line"></span><br><span class="line">ant build-code</span><br></pre></td></tr></table></figure><h2 id="退出容器"><a href="#退出容器" class="headerlink" title="退出容器"></a>退出容器</h2><p>直接退出容器:<code>exit</code><br>退出后台运行:Ctrl+Q+P</p><h2 id="下次使用容器"><a href="#下次使用容器" class="headerlink" title="下次使用容器"></a>下次使用容器</h2><ul><li><p>如果容器在后台运行:<br><code>docker exec -it build-os /bin/bash</code></p></li><li><p>容器没有启动:<br><code>docker start -i build-os</code></p></li></ul>]]></content>
<categories>
<category> Docker </category>
</categories>
<tags>
<tag> docker </tag>
</tags>
</entry>
<entry>
<title>Java学习</title>
<link href="/2019/java-learning/"/>
<url>/2019/java-learning/</url>
<content type="html"><![CDATA[<p>下面主要是Java学习的目录,我会不断完善,总结所学的知识</p><ul><li>一 面试前的准备</li><li>二 Java<ul><li>2.1 <a href="../java-basic">Java基础</a><ul><li>2.1.1 重载和重写的区别</li><li>2.1.2 String 和 StringBuffer、StringBuilder 的区别是什么?String 为什么是不可变的?</li><li>2.1.3 自动装箱与拆箱</li><li>2.1.4 == 与 equals</li><li>2.1.5 关于 final 关键字的一些总结</li><li>2.1.6 Object类的常见方法总结</li><li>2.1.7 Java 中的异常处理</li><li>2.1.8 获取用键盘输入常用的的两种方法方法1:通过 Scanner</li><li>2.1.9 接口和抽象类的区别是什么</li></ul></li><li>2.2 <a href="../java-collection">Java集合框架</a><ul><li>2.2.1 Arraylist 与 LinkedList 异同</li><li>2.2.2 ArrayList 与 Vector 区别</li><li>2.2.3 HashMap的底层实现<ul><li>JDK1.8之前</li><li>JDK1.8之后</li></ul></li><li>2.2.4 HashMap 和 Hashtable 的区别</li><li>2.2.5 HashMap 的长度为什么是2的幂次方</li><li>2.2.6 HashMap 多线程操作导致死循环问题</li><li>2.2.7 HashSet 和 HashMap 区别</li><li>2.2.8 ConcurrentHashMap 和 Hashtable 的区别</li><li>2.2.9 ConcurrentHashMap线程安全的具体实现方式/底层具体实现<ul><li>JDK1.7(上面有示意图)</li><li>JDK1.8 (上面有示意图)</li></ul></li><li>2.2.10 集合框架底层数据结构总结</li></ul></li><li>2.3 Java多线程<ul><li>一 面试中关于 synchronized 关键字的 5 连击 <ul><li>1.1 说一说自己对于 synchronized 关键字的了解</li><li>1.2 说说自己是怎么使用 synchronized 关键字,在项目中用到了吗</li><li>1.4 说说 JDK1.6 之后的synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗</li></ul></li><li>二 面试中关于线程池的 4 连击<ul><li>2.2 说说 synchronized 关键字和 volatile 关键字的区别</li></ul></li><li>三 面试中关于 线程池的 2 连击 3.1 为什么要用线程池?<ul><li>3.2 实现Runnable接口和Callable接口的区别</li><li>3.3 执行execute()方法和submit()方法的区别是什么呢?</li><li>3.4 如何创建线程池</li></ul></li><li>四 面试中关于 Atomic 原子类的 4 连击 4.1 介绍一下Atomic 原子类<ul><li>4.3 讲讲 AtomicInteger 的使用</li><li>4.4 能不能给我简单介绍一下 AtomicInteger 类的原理</li></ul></li><li>五 AQS<ul><li>5.1 AQS 介绍</li><li>5.2 AQS 原理分析</li></ul></li></ul></li><li>2.4 Java虚拟机</li><li>2.5 设计模式</li></ul></li><li>三 计算机网络常见面试点总结<ul><li>3.1 TCP、UDP 协议的区别</li><li>3.2 在浏览器中输入url地址 ->> 显示主页的过程</li><li>3.3 各种协议与HTTP协议之间的关系</li><li>3.4 HTTP长连接、短连接</li><li>3.5 TCP 三次握手和四次挥手(面试常客)</li></ul></li><li>四 Linux<ul><li>4.1 简单介绍一下 Linux 文件系统?</li><li>4.2 一些常见的 Linux 命令了解吗?</li></ul></li><li>五 MySQL<ul><li>5.1 InnoDB的理解</li><li>5.2 数据库索引了解吗?</li><li>5.2.2 最左前缀原则</li><li>5.2.3 Mysql如何为表字段添加索引???</li><li>5.3 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:</li><li>5.4 事务隔离级别(图文详解)</li><li>事物的特性(ACID)</li></ul></li><li>六 Redis<ul><li>6.1 Redis原理</li><li>6.2 为什么要用 redis /为什么要用缓存</li><li>6.4 redis 和 memcached 的区别</li><li>6.5 redis 常见数据结构以及使用场景分析</li><li>6.6 redis 设置过期时间</li><li>6.7 redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)</li><li>6.8 redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)</li><li>6.9 redis 事务</li><li>6.10 缓存雪崩和缓存穿透问题解决方案</li><li>6.11 如何解决 Redis 的并发竞争 Key 问题</li><li>6.12 如何保证缓存与数据库双写时的数据一致性?</li></ul></li><li>七 Spring<ul><li>7.1 Spring Bean 的作用域</li><li>7.2 Spring 事务中的隔离级别</li><li>7.3 Spring 事务中的事务传播行为</li><li>7.4 AOP</li><li>7.5 IOC</li></ul></li><li>八 消息队列<ul><li>8.1 什么是消息队列</li><li>8.2 为什么要用消息队列</li><li>(1) 通过异步处理提高系统性能(削峰、减少响应所需时间)</li><li>(2) 降低系统耦合性</li><li>8.3 使用消息队列带来的一些问题</li><li>8.4 JMS VS AMQP</li><li>8.4.1 JMS</li><li>8.4.2 AMQP</li><li>8.4.3 JMS vs AMQP</li><li>8.5 常见的消息队列对比</li></ul></li><li>九 Dubbo<ul><li>一 重要的概念</li><li>二 Dubbo 的架构<ul><li>2.1 Dubbo 的架构图解</li><li>2.2 Dubbo 工作原理</li></ul></li><li>三 Dubbo 的负载均衡策略<ul><li>3.1 先来解释一下什么是负载均衡</li><li>3.2 再来看看 Dubbo 提供的负载均衡策略</li><li>3.2.1 Random LoadBalance(默认,基于权重的随机负载均衡机制)</li><li>3.2.2 RoundRobin LoadBalance(不推荐,基于权重的轮询负载均衡机制)</li><li>3.2.3 LeastActive LoadBalance</li><li>3.2.4 ConsistentHash LoadBalance</li><li>3.3 配置方式</li></ul></li><li>四 zookeeper宕机与dubbo直连的情况</li></ul></li><li>十 数据结构<ul><li>Queue<ul><li>什么是队列</li><li>队列的种类</li><li>Java 集合框架中的队列 Queue</li></ul></li><li>Set<ul><li>什么是 Set</li><li>HashSet 和 TreeSet 底层数据结构</li></ul></li><li>List<ul><li>什么是List</li><li>ArrayList 和 LinkedList 源码学习</li></ul></li><li>Map</li><li>树<ul><li>二叉树</li><li>完全二叉树</li><li>平衡二叉树(Self-balancing binary search tree)</li><li>B-,B+,B*树</li><li>LSM 树</li></ul></li><li>BFS及DFS</li></ul></li><li>十一 算法</li><li>十二 实际场景题</li><li>十三 BATJ真实面试题<ul><li>说一下转发(Forward)和重定向(Redirect)的区别</li><li>在浏览器中输入url地址到显示主页的过程,整个过程会使用哪些协议</li><li>TCP 三次握手和四次挥手<ul><li>为什么要三次握手</li><li>为什么要传回 SYN</li><li>传了 SYN,为啥还要传 ACK</li></ul></li><li>IP地址与MAC地址的区别</li><li>HTTP请求,响应报文格式</li><li>事务传播行为</li><li>隔离级别</li><li>Spring AOP IOC 实现原理</li><li>美团进阶篇<ul><li>1 消息队列MQ的套路</li></ul></li><li>美团终结篇<ul><li>1.1 Object类的常见方法总结</li><li>1.2 hashCode与equals</li><li>1.3 ==与equals</li><li>2 ConcurrentHashMap 相关问题</li><li>3 谈谈 synchronized 和 ReenTrantLock 的区别</li><li>5 Nginx</li></ul></li></ul></li></ul>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title>个人简历</title>
<link href="/2019/resume/"/>
<url>/2019/resume/</url>
<content type="html"><![CDATA[<h1 id="简历"><a href="#简历" class="headerlink" title="简历"></a>简历</h1><h2 id="个人信息"><a href="#个人信息" class="headerlink" title="个人信息"></a>个人信息</h2><ul><li><strong>姓名:</strong> 张甫林</li><li><strong>工作年限:</strong> 5年</li><li><strong>性别/年龄:</strong> 男 / 26岁</li><li><strong>院校/专业/学历:</strong> 四川理工学院 / 软件工程 / 本科</li></ul><hr><h2 id="联系方式"><a href="#联系方式" class="headerlink" title="联系方式"></a>联系方式</h2><ul><li><strong>手机:</strong> 182xxxx5625</li><li><strong>Email:</strong> [email protected]</li></ul><hr><h2 id="求职意向"><a href="#求职意向" class="headerlink" title="求职意向"></a>求职意向</h2><ul><li><strong>期望职位:</strong> Java高级程序员</li><li><strong>期望城市:</strong> 成都</li></ul><hr><h2 id="技能"><a href="#技能" class="headerlink" title="技能"></a>技能</h2><ul><li>熟练掌握Java语言与面向对象思想,熟悉常用设计模式</li><li>熟练掌握 Spring、SpringBoot、SpringCloud、Mybatis 等框架</li><li>熟练掌握 MySQL数据库设计及SQL优化</li><li>熟练掌握 Redis数据库</li><li>熟练掌握消息中间件 RabbitMQ 的使用</li><li>熟练使用 Maven、Git 等项目管理工具</li><li>熟悉 Linux 基本操作命令</li><li>熟悉 Tomcat、Nginx 等服务器</li><li>熟悉并发编程及高并发处理方案</li><li>熟悉 JavaScript、Angular JS、React等技术</li></ul><hr><h2 id="工作经历"><a href="#工作经历" class="headerlink" title="工作经历"></a>工作经历</h2><h3 id="DellEMC成都研发中心-2017-6-至今"><a href="#DellEMC成都研发中心-2017-6-至今" class="headerlink" title="DellEMC成都研发中心(2017.6-至今)"></a>DellEMC成都研发中心(2017.6-至今)</h3><p>在EMC期间担任Java高级程序员,主要负责新项目的开发以及原有项目的维护等工作,同时也参与了项目的设计工作,帮助解决客户的线上问题等.</p><h4 id="Avamar项目"><a href="#Avamar项目" class="headerlink" title="Avamar项目"></a>Avamar项目</h4><ul><li><strong>项目描述</strong>: Avamar是一款重复数据删除备份软件,核心技术是在客户端去重来减少网络数据传输,以达到快速备份和恢复的功能。该系统可以备份多种数据,包括文件系统,数据库和虚拟机磁盘等。支持多种备份策略来满足不同的备份需求。</li><li><strong>使用技术</strong>: 项目主要使用SpringBoot作为后端框架,引入了SpringSecurity模块,使用caffeine做本地缓存,dozer做Bean的映射工具。使用了RabbitMQ实现消息通信和应用解耦。前端主要使用AngularJS框架和Clarity组件库进行开发。</li><li><strong>责任描述</strong>: <ol><li>参与了REST-API的设计和开发</li><li>负责虚拟机备份与恢复的接口开发</li><li>使用Oauth2实现SSO,实现基于JWT的权限验证</li><li>使用caffeine实现后端本地缓存的开发</li><li>参与了前端HTML5的开发工作,为项目提供了独立可复用的UI组件。</li><li>参与了项目日常维护工作,定位和解决客户的线上问题,通过JDK工具分析死锁和内存溢出等问题。</li></ol></li></ul><h4 id="PowerProtect项目"><a href="#PowerProtect项目" class="headerlink" title="PowerProtect项目"></a>PowerProtect项目</h4><ul><li><strong>项目描述</strong>: PowerProtect是继Avamar后的下一代存储备份系统。采用新的架构,提供了可扩展和高可用的备份系统。新产品在性能和易用性上较前一代产品有了很大提高。</li><li><strong>使用技术</strong>: 项目主要使用了SpringCloud相关的微服务架构,使用ElasticSearch做数据的分布式存储,Docker做为容器进行服务部署。前端主要使用AngularJS框架和Clarity组件库进行开发。</li><li><strong>责任描述</strong>:<ol><li>参与项目中Dynamic Rule Engine模块的开发</li><li>负责前端备份策略模块的开发</li><li>负责与后端API进行交互</li><li>负责产品的维护与界面优化</li></ol></li></ul><h3 id="中软国际-2015-4-2017-6"><a href="#中软国际-2015-4-2017-6" class="headerlink" title="中软国际(2015.4-2017.6)"></a>中软国际(2015.4-2017.6)</h3><p>在中软国际期间,主要是与华为一起开发网元增强组件,同时负责相关测试工具的开发与维护工作.</p><h4 id="Trace-Server-Professional项目"><a href="#Trace-Server-Professional项目" class="headerlink" title="Trace Server Professional项目"></a>Trace Server Professional项目</h4><ul><li><strong>项目描述</strong>: TSP是华为U2000 Trace Server的增强组件,支持接入并处理多种网元数据。TSP提供对网元数据的采集、汇聚、统一建模、存储、定位等基础处理功能,同时还提供业务扩展能力、支持上层应用系统定制数据处理业务。</li><li><strong>使用技术</strong>: 该项目使用了SpringCloud,kafaka,zookeeper等技术。</li><li><strong>责任描述</strong>:<ol><li>参与项目的微服务改造</li><li>负责部分API接口的开发</li><li>负责代码单元测试的编写</li><li>负责bug修改与产品维护</li><li>负责修改Findbugs、checkStyle、PMD等静态检查工具扫描出的问题</li></ol></li></ul><h4 id="网元自动化测试工具"><a href="#网元自动化测试工具" class="headerlink" title="网元自动化测试工具"></a>网元自动化测试工具</h4><ul><li><strong>项目描述</strong>: 自动化测试工具主要是提供给华为内部的测试人员使用,工具包括U2000模拟器和测试用例执行等功能。测试人员可以在工具中直接编写测试用例。工具中自带的U2000模拟器为测试用例提供环境,可以定期执行指定目录下的用例并生成测试报告。</li><li><strong>使用技术</strong>: 该项目主要使用Java,界面由Java Swing开发,用到了Corba协议,使用JSch执行远程Shell脚本。</li><li><strong>责任描述</strong>: <ol><li>参与项目需求分析与设计</li><li>使用WindowsBuilder插件完成了部分界面开发</li><li>独立完成了JSch远程执行Shell的公共模块的开发</li><li>通过延迟加载解决了用例树加载慢的问题</li><li>负责工具的维护和扩展</li></ol></li></ul><h2 id="获奖情况"><a href="#获奖情况" class="headerlink" title="获奖情况"></a>获奖情况</h2><ul><li>大学期间参加全国大学生数学建模比赛,并获得了国家一等奖</li></ul><h2 id="博客-amp-Github"><a href="#博客-amp-Github" class="headerlink" title="博客 & Github"></a>博客 & Github</h2><ul><li>博客: <a href="https://iuin.github.io">https://iuin.github.io</a></li><li>Github: <a href="https://github.com/iuin" target="_blank" rel="noopener">https://github.com/iuin</a></li></ul><h2 id="致谢"><a href="#致谢" class="headerlink" title="致谢"></a>致谢</h2><p>感谢您花时间阅读我的简历,期待能有机会和您共事</p>]]></content>
<categories>
<category> 其它 </category>
<category> 简历 </category>
</categories>
<tags>
<tag> 简历 </tag>
</tags>
</entry>
<entry>
<title>互联网高频面试题</title>
<link href="/2019/Internet-high-frequency-interview-questions/"/>
<url>/2019/Internet-high-frequency-interview-questions/</url>
<content type="html"><![CDATA[<p><img src="JVM%E6%80%9D%E7%BB%B4%E5%AF%BC%E5%9B%BE.jpg" alt="JVM"></p>]]></content>
</entry>
<entry>
<title>Java并发</title>
<link href="/2019/null/"/>
<url>/2019/null/</url>
<content type="html"><![CDATA[]]></content>
</entry>
<entry>
<title>Java集合</title>
<link href="/2019/java-collection/"/>
<url>/2019/java-collection/</url>
<content type="html"><![CDATA[<h2 id="说说List-Set-Map三者的区别?"><a href="#说说List-Set-Map三者的区别?" class="headerlink" title="说说List,Set,Map三者的区别?"></a>说说List,Set,Map三者的区别?</h2><ul><li><strong>List(对付顺序的好帮手):</strong> List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象</li><li><strong>Set(注重独一无二的性质):</strong> 不允许重复的集合。不会有多个元素引用相同的对象。</li><li><strong>Map(用Key来搜索的专家):</strong> 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。</li></ul><h2 id="Arraylist-与-LinkedList-区别"><a href="#Arraylist-与-LinkedList-区别" class="headerlink" title="Arraylist 与 LinkedList 区别?"></a>Arraylist 与 LinkedList 区别?</h2><ul><li><p><strong>1. 是否保证线程安全:</strong> <code>ArrayList</code> 和 <code>LinkedList</code> 都是不同步的,也就是不保证线程安全;</p></li><li><p><strong>2. 底层数据结构:</strong> <code>Arraylist</code> 底层使用的是 <strong><code>Object</code> 数组</strong>;<code>LinkedList</code> 底层使用的是 <strong>双向链表</strong> 数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)</p></li><li><p><strong>3. 插入和删除是否受元素位置的影响:</strong> ① <strong><code>ArrayList</code> 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。</strong> 比如:执行<code>add(E e)</code>方法的时候, <code>ArrayList</code> 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(<code>add(int index, E element)</code>)时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② <strong><code>LinkedList</code> 采用链表存储,所以对于<code>add(E e)</code>方法的插入,删除元素时间复杂度不受元素位置的影响,近似 O(1),如果是要在指定位置<code>i</code>插入和删除元素的话(<code>(add(int index, E element)</code>) 时间复杂度近似为<code>o(n))</code>因为需要先移动到指定位置再插入。</strong></p></li><li><p><strong>4. 是否支持快速随机访问:</strong> <code>LinkedList</code> 不支持高效的随机元素访问,而 <code>ArrayList</code> 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于<code>get(int index)</code>方法)。</p></li><li><p><strong>5. 内存空间占用:</strong> ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。</p></li></ul><h3 id="补充内容-RandomAccess接口"><a href="#补充内容-RandomAccess接口" class="headerlink" title="补充内容:RandomAccess接口"></a><strong>补充内容:RandomAccess接口</strong></h3><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">RandomAccess</span> </span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>查看源码我们发现实际上 <code>RandomAccess</code> 接口中什么都没有定义。所以,在我看来 <code>RandomAccess</code> 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。</p><p>在 <code>binarySearch(</code>)方法中,它要判断传入的list 是否 <code>RamdomAccess</code> 的实例,如果是,调用<code>indexedBinarySearch()</code>方法,如果不是,那么调用<code>iteratorBinarySearch()</code>方法</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="keyword">static</span> <T></span><br><span class="line"><span class="function"><span class="keyword">int</span> <span class="title">binarySearch</span><span class="params">(List<? extends Comparable<? <span class="keyword">super</span> T>> list, T key)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (list <span class="keyword">instanceof</span> RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)</span><br><span class="line"> <span class="keyword">return</span> Collections.indexedBinarySearch(list, key);</span><br><span class="line"> <span class="keyword">else</span></span><br><span class="line"> <span class="keyword">return</span> Collections.iteratorBinarySearch(list, key);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p><code>ArrayList</code> 实现了 <code>RandomAccess</code> 接口, 而 <code>LinkedList</code> 没有实现。为什么呢?我觉得还是和底层数据结构有关!<code>ArrayList</code> 底层是数组,而 <code>LinkedList</code> 底层是链表。数组天然支持随机访问,时间复杂度为 O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问。,<code>ArrayList</code> 实现了 <code>RandomAccess</code> 接口,就表明了他具有快速随机访问功能。 <code>RandomAccess</code> 接口只是标识,并不是说 <code>ArrayList</code> 实现 <code>RandomAccess</code> 接口才具有快速随机访问功能的!</p><p><strong>下面再总结一下 list 的遍历方式选择:</strong></p><ul><li>实现了 <code>RandomAccess</code> 接口的list,优先选择普通 for 循环 ,其次 foreach,</li><li>未实现 <code>RandomAccess</code>接口的list,优先选择iterator遍历(foreach遍历底层也是通过iterator实现的,),大size的数据,千万不要使用普通for循环</li></ul><h3 id="补充内容-双向链表和双向循环链表"><a href="#补充内容-双向链表和双向循环链表" class="headerlink" title="补充内容:双向链表和双向循环链表"></a>补充内容:双向链表和双向循环链表</h3><p><strong>双向链表:</strong> 包含两个指针,一个prev指向前一个节点,一个next指向后一个节点。</p><p><strong>双向循环链表:</strong> 最后一个节点的 next 指向head,而 head 的prev指向最后一个节点,构成一个环。</p><p><img src="%E9%93%BE%E8%A1%A8.png" alt="双向链表 & 双向循环链表"></p><h2 id="ArrayList-与-Vector-区别呢-为什么要用Arraylist取代Vector呢?"><a href="#ArrayList-与-Vector-区别呢-为什么要用Arraylist取代Vector呢?" class="headerlink" title="ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?"></a>ArrayList 与 Vector 区别呢?为什么要用Arraylist取代Vector呢?</h2><p><code>Vector</code>类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector的话代码要在同步操作上耗费大量的时间。</p><p><code>Arraylist</code>不是同步的,所以在不需要保证线程安全时建议使用Arraylist。</p><h2 id="说一说-ArrayList-的扩容机制吧"><a href="#说一说-ArrayList-的扩容机制吧" class="headerlink" title="说一说 ArrayList 的扩容机制吧"></a>说一说 ArrayList 的扩容机制吧</h2><p>详见笔主的这篇文章:<a href="https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/collection/ArrayList-Grow.md" target="_blank" rel="noopener">通过源码一步一步分析ArrayList 扩容机制</a></p><h2 id="HashMap-和-Hashtable-的区别"><a href="#HashMap-和-Hashtable-的区别" class="headerlink" title="HashMap 和 Hashtable 的区别"></a>HashMap 和 Hashtable 的区别</h2><ol><li><strong>线程是否安全:</strong> HashMap 是非线程安全的,HashTable 是线程安全的;HashTable 内部的方法基本都经过<code>synchronized</code> 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);</li><li><strong>效率:</strong> 因为线程安全的问题,HashMap 要比 HashTable 效率高一点。另外,HashTable 基本被淘汰,不要在代码中使用它;</li><li><strong>对Null key 和Null value的支持:</strong> HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。。但是在 HashTable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。</li><li><strong>初始容量大小和每次扩充容量大小的不同 :</strong> ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小(HashMap 中的<code>tableSizeFor()</code>方法保证,下面给出了源代码)。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。</li><li><strong>底层数据结构:</strong> JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。</li></ol><p><strong>HashMap 中带有初始容量的构造函数:</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity, <span class="keyword">float</span> loadFactor)</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (initialCapacity < <span class="number">0</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Illegal initial capacity: "</span> +</span><br><span class="line"> initialCapacity);</span><br><span class="line"> <span class="keyword">if</span> (initialCapacity > MAXIMUM_CAPACITY)</span><br><span class="line"> initialCapacity = MAXIMUM_CAPACITY;</span><br><span class="line"> <span class="keyword">if</span> (loadFactor <= <span class="number">0</span> || Float.isNaN(loadFactor))</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"Illegal load factor: "</span> +</span><br><span class="line"> loadFactor);</span><br><span class="line"> <span class="keyword">this</span>.loadFactor = loadFactor;</span><br><span class="line"> <span class="keyword">this</span>.threshold = tableSizeFor(initialCapacity);</span><br><span class="line">}</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">HashMap</span><span class="params">(<span class="keyword">int</span> initialCapacity)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>(initialCapacity, DEFAULT_LOAD_FACTOR);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>下面这个方法保证了 HashMap 总是使用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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Returns a power of two size for the given target capacity.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> <span class="title">tableSizeFor</span><span class="params">(<span class="keyword">int</span> cap)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> n = cap - <span class="number">1</span>;</span><br><span class="line"> n |= n >>> <span class="number">1</span>;</span><br><span class="line"> n |= n >>> <span class="number">2</span>;</span><br><span class="line"> n |= n >>> <span class="number">4</span>;</span><br><span class="line"> n |= n >>> <span class="number">8</span>;</span><br><span class="line"> n |= n >>> <span class="number">16</span>;</span><br><span class="line"> <span class="keyword">return</span> (n < <span class="number">0</span>) ? <span class="number">1</span> : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + <span class="number">1</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="HashMap-和-HashSet区别"><a href="#HashMap-和-HashSet区别" class="headerlink" title="HashMap 和 HashSet区别"></a>HashMap 和 HashSet区别</h2><p>如果你看过 <code>HashSet</code> 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 <code>clone()</code>、<code>writeObject()</code>、<code>readObject()</code>是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。</p><table><thead><tr><th align="center">HashMap</th><th align="center">HashSet</th></tr></thead><tbody><tr><td align="center">实现了Map接口</td><td align="center">实现Set接口</td></tr><tr><td align="center">存储键值对</td><td align="center">仅存储对象</td></tr><tr><td align="center">调用 <code>put()</code>向map中添加元素</td><td align="center">调用 <code>add()</code>方法向Set中添加元素</td></tr><tr><td align="center">HashMap使用键(Key)计算Hashcode</td><td align="center">HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,</td></tr></tbody></table><h2 id="HashSet如何检查重复"><a href="#HashSet如何检查重复" class="headerlink" title="HashSet如何检查重复"></a>HashSet如何检查重复</h2><p>当你把对象加入<code>HashSet</code>时,HashSet会先计算对象的<code>hashcode</code>值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用<code>equals()</code>方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。(摘自我的Java启蒙书《Head fist java》第二版)</p><p><strong>hashCode()与equals()的相关规定:</strong></p><ol><li>如果两个对象相等,则hashcode一定也是相同的</li><li>两个对象相等,对两个equals方法返回true</li><li>两个对象有相同的hashcode值,它们也不一定是相等的</li><li>综上,equals方法被覆盖过,则hashCode方法也必须被覆盖</li><li>hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。</li></ol><p><strong>==与equals的区别</strong></p><ol><li>==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同</li><li>==是指对内存地址进行比较 equals()是对字符串的内容进行比较</li><li>==指引用是否相同 equals()指的是值是否相同</li></ol><h2 id="HashMap的底层实现"><a href="#HashMap的底层实现" class="headerlink" title="HashMap的底层实现"></a>HashMap的底层实现</h2><h3 id="JDK1-8之前"><a href="#JDK1-8之前" class="headerlink" title="JDK1.8之前"></a>JDK1.8之前</h3><p>JDK1.8 之前 <code>HashMap</code> 底层是 <strong>数组和链表</strong> 结合在一起使用也就是 <strong>链表散列</strong>。<strong>HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。</strong></p><p><strong>所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。</strong></p><p><strong>JDK 1.8 HashMap 的 hash 方法源码:</strong></p><p>JDK 1.8 的 hash方法 相比于 JDK 1.7 hash 方法更加简化,但是原理不变。</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">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="comment">// key.hashCode():返回散列值也就是hashcode</span></span><br><span class="line"> <span class="comment">// ^ :按位异或</span></span><br><span class="line"> <span class="comment">// >>>:无符号右移,忽略符号位,空位都以0补齐</span></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></pre></td></tr></table></figure><p>对比一下 JDK1.7的 HashMap 的 hash 方法源码.</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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">static</span> <span class="keyword">int</span> <span class="title">hash</span><span class="params">(<span class="keyword">int</span> h)</span> </span>{</span><br><span class="line"> <span class="comment">// This function ensures that hashCodes that differ only by</span></span><br><span class="line"> <span class="comment">// constant multiples at each bit position have a bounded</span></span><br><span class="line"> <span class="comment">// number of collisions (approximately 8 at default load factor).</span></span><br><span class="line"></span><br><span class="line"> h ^= (h >>> <span class="number">20</span>) ^ (h >>> <span class="number">12</span>);</span><br><span class="line"> <span class="keyword">return</span> h ^ (h >>> <span class="number">7</span>) ^ (h >>> <span class="number">4</span>);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>相比于 JDK1.8 的 hash 方法 ,JDK 1.7 的 hash 方法的性能会稍差一点点,因为毕竟扰动了 4 次。</p><p>所谓 <strong>“拉链法”</strong> 就是:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。</p><p><img src="jdk1-8-hashmap-befor.jpg" alt="jdk1.8之前的内部结构-HashMap"></p><h3 id="JDK1-8之后"><a href="#JDK1-8之后" class="headerlink" title="JDK1.8之后"></a>JDK1.8之后</h3><p>相比于之前的版本, JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。</p><p><img src="jdk1-8-hashmap-after.jpg" alt="jdk1.8之后的内部结构-HashMap"></p><blockquote><p>TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。</p></blockquote><p><strong>推荐阅读:</strong></p><ul><li>《Java 8系列之重新认识HashMap》 :<a href="https://zhuanlan.zhihu.com/p/21673805" target="_blank" rel="noopener">https://zhuanlan.zhihu.com/p/21673805</a></li></ul><h2 id="HashMap-的长度为什么是2的幂次方"><a href="#HashMap-的长度为什么是2的幂次方" class="headerlink" title="HashMap 的长度为什么是2的幂次方"></a>HashMap 的长度为什么是2的幂次方</h2><p>为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。我们上面也讲到了过了,Hash 值的范围值-2147483648到2147483647,前后加起来大概40亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但问题是一个40亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ <code>(n - 1) & hash</code>”。(n代表数组长度)。这也就解释了 HashMap 的长度为什么是2的幂次方。</p><p><strong>这个算法应该如何设计呢?</strong></p><p>我们首先可能会想到采用%取余的操作来实现。但是,重点来了:<strong>“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。”</strong> 并且 <strong>采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。</strong></p><h2 id="HashMap-多线程操作导致死循环问题"><a href="#HashMap-多线程操作导致死循环问题" class="headerlink" title="HashMap 多线程操作导致死循环问题"></a>HashMap 多线程操作导致死循环问题</h2><p>主要原因在于 并发下的Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下推荐使用 ConcurrentHashMap 。</p><p>详情请查看:<a href="https://coolshell.cn/articles/9606.html" target="_blank" rel="noopener">https://coolshell.cn/articles/9606.html</a></p><h2 id="ConcurrentHashMap-和-Hashtable-的区别"><a href="#ConcurrentHashMap-和-Hashtable-的区别" class="headerlink" title="ConcurrentHashMap 和 Hashtable 的区别"></a>ConcurrentHashMap 和 Hashtable 的区别</h2><p>ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。</p><ul><li><strong>底层数据结构:</strong> JDK1.7的 ConcurrentHashMap 底层采用 <strong>分段的数组+链表</strong> 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 <strong>数组+链表</strong> 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;</li><li><strong>实现线程安全的方式(重要):</strong> ① <strong>在JDK1.7的时候,ConcurrentHashMap(分段锁)</strong> 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 <strong>到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化)</strong> 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② <strong>Hashtable(同一把锁)</strong> :使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。</li></ul><p><strong>两者的对比图:</strong></p><p>图片来源:<a href="http://www.cnblogs.com/chengxiao/p/6842045.html" target="_blank" rel="noopener">http://www.cnblogs.com/chengxiao/p/6842045.html</a></p><p><strong>HashTable:</strong></p><p><img src="HashTable%E5%85%A8%E8%A1%A8%E9%94%81.png" alt="HashTable全表锁"></p><p><strong>JDK1.7的ConcurrentHashMap:</strong></p><p><img src="ConcurrentHashMap%E5%88%86%E6%AE%B5%E9%94%81.jpg" alt="JDK1.7的ConcurrentHashMap"></p><p><strong>JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点 Node: 链表节点):</strong></p><p><img src="JDK1.8-ConcurrentHashMap-Structure.jpg" alt="JDK1.8的ConcurrentHashMap"></p><h2 id="ConcurrentHashMap线程安全的具体实现方式-底层具体实现"><a href="#ConcurrentHashMap线程安全的具体实现方式-底层具体实现" class="headerlink" title="ConcurrentHashMap线程安全的具体实现方式/底层具体实现"></a>ConcurrentHashMap线程安全的具体实现方式/底层具体实现</h2><h3 id="JDK1-7(上面有示意图)"><a href="#JDK1-7(上面有示意图)" class="headerlink" title="JDK1.7(上面有示意图)"></a>JDK1.7(上面有示意图)</h3><p>首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。</p><p><strong>ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成</strong>。</p><p>Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Segment</span><<span class="title">K</span>,<span class="title">V</span>> <span class="keyword">extends</span> <span class="title">ReentrantLock</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>{</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。</p><h3 id="JDK1-8-(上面有示意图)"><a href="#JDK1-8-(上面有示意图)" class="headerlink" title="JDK1.8 (上面有示意图)"></a>JDK1.8 (上面有示意图)</h3><p>ConcurrentHashMap取消了Segment分段锁,采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。Java 8在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为O(N))转换为红黑树(寻址时间复杂度为O(log(N)))</p><p>synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。</p><h2 id="comparable-和-Comparator的区别"><a href="#comparable-和-Comparator的区别" class="headerlink" title="comparable 和 Comparator的区别"></a>comparable 和 Comparator的区别</h2><ul><li>comparable接口实际上是出自java.lang包 它有一个 <code>compareTo(Object obj)</code>方法用来排序</li><li>comparator接口实际上是出自 java.util 包它有一个<code>compare(Object obj1, Object obj2)</code>方法用来排序</li></ul><p>一般我们需要对一个集合使用自定义排序时,我们就要重写<code>compareTo()</code>方法或<code>compare()</code>方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写<code>compareTo()</code>方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的 <code>Collections.sort()</code>.</p><h3 id="Comparator定制排序"><a href="#Comparator定制排序" class="headerlink" title="Comparator定制排序"></a>Comparator定制排序</h3><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></pre></td><td class="code"><pre><span class="line">ArrayList<Integer> arrayList = <span class="keyword">new</span> ArrayList<Integer>();</span><br><span class="line">arrayList.add(-<span class="number">1</span>);</span><br><span class="line">arrayList.add(<span class="number">3</span>);</span><br><span class="line">arrayList.add(<span class="number">3</span>);</span><br><span class="line">arrayList.add(-<span class="number">5</span>);</span><br><span class="line">arrayList.add(<span class="number">7</span>);</span><br><span class="line">arrayList.add(<span class="number">4</span>);</span><br><span class="line">arrayList.add(-<span class="number">9</span>);</span><br><span class="line">arrayList.add(-<span class="number">7</span>);</span><br><span class="line">System.out.println(<span class="string">"原始数组:"</span>);</span><br><span class="line">System.out.println(arrayList);</span><br><span class="line"><span class="comment">// void reverse(List list):反转</span></span><br><span class="line">Collections.reverse(arrayList);</span><br><span class="line">System.out.println(<span class="string">"Collections.reverse(arrayList):"</span>);</span><br><span class="line">System.out.println(arrayList);</span><br><span class="line"></span><br><span class="line"><span class="comment">// void sort(List list),按自然排序的升序排序</span></span><br><span class="line">Collections.sort(arrayList);</span><br><span class="line">System.out.println(<span class="string">"Collections.sort(arrayList):"</span>);</span><br><span class="line">System.out.println(arrayList);</span><br><span class="line"><span class="comment">// 定制排序的用法</span></span><br><span class="line">Collections.sort(arrayList, <span class="keyword">new</span> Comparator<Integer>() {</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">int</span> <span class="title">compare</span><span class="params">(Integer o1, Integer o2)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> o2.compareTo(o1);</span><br><span class="line"> }</span><br><span class="line">});</span><br><span class="line">System.out.println(<span class="string">"定制排序后:"</span>);</span><br><span class="line">System.out.println(arrayList);</span><br></pre></td></tr></table></figure><p>Output:</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">原始数组:</span><br><span class="line">[-1, 3, 3, -5, 7, 4, -9, -7]</span><br><span class="line">Collections.reverse(arrayList):</span><br><span class="line">[-7, -9, 4, 7, -5, 3, 3, -1]</span><br><span class="line">Collections.sort(arrayList):</span><br><span class="line">[-9, -7, -5, -1, 3, 3, 4, 7]</span><br><span class="line">定制排序后:</span><br><span class="line">[7, 4, 3, 3, -1, -5, -7, -9]</span><br></pre></td></tr></table></figure><h3 id="重写compareTo方法实现按年龄来排序"><a href="#重写compareTo方法实现按年龄来排序" class="headerlink" title="重写compareTo方法实现按年龄来排序"></a>重写compareTo方法实现按年龄来排序</h3><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// person对象没有实现Comparable接口,所以必须实现,这样才不会出错,才可以使treemap中的数据按顺序排列</span></span><br><span class="line"><span class="comment">// 前面一个例子的String类已经默认实现了Comparable接口,详细可以查看String类的API文档,另外其他</span></span><br><span class="line"><span class="comment">// 像Integer类等都已经实现了Comparable接口,所以不需要另外实现了</span></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">Person</span> <span class="keyword">implements</span> <span class="title">Comparable</span><<span class="title">Person</span>> </span>{</span><br><span class="line"> <span class="keyword">private</span> String name;</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">int</span> age;</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">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">super</span>();</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> <span class="keyword">this</span>.age = age;</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">getName</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> name;</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">setName</span><span class="params">(String name)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.name = name;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">getAge</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> age;</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">setAge</span><span class="params">(<span class="keyword">int</span> age)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.age = age;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * TODO重写compareTo方法实现按年龄来排序</span></span><br><span class="line"><span class="comment"> */</span></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">compareTo</span><span class="params">(Person o)</span> </span>{</span><br><span class="line"> <span class="comment">// TODO Auto-generated method stub</span></span><br><span class="line"> <span class="keyword">if</span> (<span class="keyword">this</span>.age > o.getAge()) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (<span class="keyword">this</span>.age < o.getAge()) {</span><br><span class="line"> <span class="keyword">return</span> -<span class="number">1</span>;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> age;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><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="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"> TreeMap<Person, String> pdata = <span class="keyword">new</span> TreeMap<Person, String>();</span><br><span class="line"> pdata.put(<span class="keyword">new</span> Person(<span class="string">"张三"</span>, <span class="number">30</span>), <span class="string">"zhangsan"</span>);</span><br><span class="line"> pdata.put(<span class="keyword">new</span> Person(<span class="string">"李四"</span>, <span class="number">20</span>), <span class="string">"lisi"</span>);</span><br><span class="line"> pdata.put(<span class="keyword">new</span> Person(<span class="string">"王五"</span>, <span class="number">10</span>), <span class="string">"wangwu"</span>);</span><br><span class="line"> pdata.put(<span class="keyword">new</span> Person(<span class="string">"小红"</span>, <span class="number">5</span>), <span class="string">"xiaohong"</span>);</span><br><span class="line"> <span class="comment">// 得到key的值的同时得到key所对应的值</span></span><br><span class="line"> Set<Person> keys = pdata.keySet();</span><br><span class="line"> <span class="keyword">for</span> (Person key : keys) {</span><br><span class="line"> System.out.println(key.getAge() + <span class="string">"-"</span> + key.getName());</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>Output:</p><figure class="highlight plain"><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">5-小红</span><br><span class="line">10-王五</span><br><span class="line">20-李四</span><br><span class="line">30-张三</span><br></pre></td></tr></table></figure><h2 id="集合框架底层数据结构总结"><a href="#集合框架底层数据结构总结" class="headerlink" title="集合框架底层数据结构总结"></a>集合框架底层数据结构总结</h2><h3 id="Collection"><a href="#Collection" class="headerlink" title="Collection"></a>Collection</h3><h4 id="1-List"><a href="#1-List" class="headerlink" title="1. List"></a>1. List</h4><ul><li><strong>Arraylist:</strong> Object数组</li><li><strong>Vector:</strong> Object数组</li><li><strong>LinkedList:</strong> 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)</li></ul><h4 id="2-Set"><a href="#2-Set" class="headerlink" title="2. Set"></a>2. Set</h4><ul><li><strong>HashSet(无序,唯一):</strong> 基于 HashMap 实现的,底层采用 HashMap 来保存元素</li><li><strong>LinkedHashSet:</strong> LinkedHashSet 继承于 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的</li><li><strong>TreeSet(有序,唯一):</strong> 红黑树(自平衡的排序二叉树)</li></ul><h3 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h3><ul><li><strong>HashMap:</strong> JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间</li><li><strong>LinkedHashMap:</strong> LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看:<a href="https://www.imooc.com/article/22931" target="_blank" rel="noopener">《LinkedHashMap 源码详细分析(JDK1.8)》</a></li><li><strong>Hashtable:</strong> 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的</li><li><strong>TreeMap:</strong> 红黑树(自平衡的排序二叉树)</li></ul><h2 id="如何选用集合"><a href="#如何选用集合" class="headerlink" title="如何选用集合?"></a>如何选用集合?</h2><p>主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap.当我们只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用。</p>]]></content>
<categories>
<category> Java </category>
<category> 集合 </category>
</categories>
<tags>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title>面试技巧</title>
<link href="/2019/interview-skills/"/>
<url>/2019/interview-skills/</url>
<content type="html"><![CDATA[<h2 id="面试考察点"><a href="#面试考察点" class="headerlink" title="面试考察点"></a>面试考察点</h2><ol><li>基本概念和基本原理</li><li>实现方式与使用姿势</li><li>经常用到的知识点</li><li>实际应用中容易犯错的点</li><li>与面试方向相关的知识点</li></ol><h2 id="加分项"><a href="#加分项" class="headerlink" title="加分项"></a>加分项</h2><ol><li>知识点与典型的业务场景关联</li><li>用反例来描述实际场景中误用的危害</li><li>与知识点相关的优化点</li><li>与知识点相关的最新的技术趋势</li><li>在了解的前提下,尽量增加回答的内容深度</li></ol>]]></content>
<categories>
<category> 面试 </category>
</categories>
<tags>
<tag> 面试 </tag>
</tags>
</entry>
<entry>
<title>Java语言特性</title>
<link href="/2019/Java-language-features/"/>
<url>/2019/Java-language-features/</url>
<content type="html"><![CDATA[<p>首先来看下Java语言特性,下面是一张结构图</p><p><img src="Java%E8%AF%AD%E8%A8%80%E7%89%B9%E6%80%A7.png" alt="Java语言特性"></p><h2 id="Java并发"><a href="#Java并发" class="headerlink" title="Java并发"></a>Java并发</h2><h2 id="Java版本差异新特性"><a href="#Java版本差异新特性" class="headerlink" title="Java版本差异新特性"></a>Java版本差异新特性</h2><p><img src="JavaFeatures.png" alt="Java版本特性"></p><h2 id="Java数据类型"><a href="#Java数据类型" class="headerlink" title="Java数据类型"></a>Java数据类型</h2><p>Java 支持的数据类型包括基本数据类型和引用类型。</p><p>基本数据类型如下:</p><ul><li>整数值型:byte、short、int、long</li><li>字符型:char</li><li>浮点类型:float、double</li><li>布尔型:boolean</li><li>整数型:默认 int 型,小数默认是 double 型。Float 和 Long 类型的必须加后缀。比如:float f = 100f</li></ul><p>引用类型声明的变量是指该变量在内存中实际存储的是一个引用地址,实体在堆中。</p><p>引用类型包括类、接口、数组等。<br>特别注意,String 是引用类型不是基本类型。</p><p><strong>值传递和引用传递</strong></p><ul><li>值传递,是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。</li><li>引用传递,一般是对于对象型变量而言的,传递的是该对象地址的一个副本,并不是原对象本身。<br>一般认为,Java 内的传递都是值传递,Java 中实例对象的传递是引用传递。</li></ul><blockquote><p>Java中只有值传递, 方法中传递的都是基本类型副本的值, 或者是引用类型的地址的值. 所以直接修改值不会影响原来的值, 但是如果根据引用类型的地址去修改对象, 那么那个地址指向的对象是会被改变的.</p></blockquote><h2 id="Java常用集合"><a href="#Java常用集合" class="headerlink" title="Java常用集合"></a>Java常用集合</h2><p><img src="JavaMap.png" alt="Map集合"></p><h2 id="Java对象引用"><a href="#Java对象引用" class="headerlink" title="Java对象引用"></a>Java对象引用</h2><p>强引用<br>弱引用<br>软引用<br>虚引用</p><h2 id="Java异常机制"><a href="#Java异常机制" class="headerlink" title="Java异常机制"></a>Java异常机制</h2><h2 id="SPI机制"><a href="#SPI机制" class="headerlink" title="SPI机制"></a>SPI机制</h2><h2 id="JAVA注解处理机制"><a href="#JAVA注解处理机制" class="headerlink" title="JAVA注解处理机制"></a>JAVA注解处理机制</h2>]]></content>
<categories>
<category> Java </category>
</categories>
<tags>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title>常见设计模式与应用场景</title>
<link href="/2019/common-pattern-and-scenarios/"/>
<url>/2019/common-pattern-and-scenarios/</url>
<content type="html"><![CDATA[<p>将设计模式与实际业务场景相结合,体现对设计模式的理解和应用能力</p><h2 id="工程模式-Spring如何创建Bean"><a href="#工程模式-Spring如何创建Bean" class="headerlink" title="工程模式: Spring如何创建Bean"></a>工程模式: Spring如何创建Bean</h2><p>创建不同类型实例常用的方式</p><h2 id="代理模式-Motan服务的动态代理"><a href="#代理模式-Motan服务的动态代理" class="headerlink" title="代理模式: Motan服务的动态代理"></a>代理模式: Motan服务的动态代理</h2><p>主要应用在不适合或者不能直接引用另一个对象的场景。</p><p>静态代理<br>动态代理: JVM</p><h2 id="责任链模式-Netty消息的处理方式"><a href="#责任链模式-Netty消息的处理方式" class="headerlink" title="责任链模式: Netty消息的处理方式"></a>责任链模式: Netty消息的处理方式</h2><p>工程的流水线<br>Pipeline</p><h2 id="适配器-SLF4J如何支持Log4J"><a href="#适配器-SLF4J如何支持Log4J" class="headerlink" title="适配器: SLF4J如何支持Log4J"></a>适配器: SLF4J如何支持Log4J</h2><p>把两种不匹配的对象进行适配,也可以将对象进行解耦</p><h2 id="观察者模式-GRPC是如何支持流式请求的"><a href="#观察者模式-GRPC是如何支持流式请求的" class="headerlink" title="观察者模式: GRPC是如何支持流式请求的"></a>观察者模式: GRPC是如何支持流式请求的</h2><p>发布订阅模式,一个对象的某个行为触发一系列事件的场景</p><h2 id="构造这模式-PB序列化中的Builder"><a href="#构造这模式-PB序列化中的Builder" class="headerlink" title="构造这模式: PB序列化中的Builder"></a>构造这模式: PB序列化中的Builder</h2><p>一个对象有很多复杂属性,需要根据不同情况创建不同的具体对象</p>]]></content>
<categories>
<category> 设计模式 </category>
<category> 应用场景 </category>
</categories>
<tags>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>Docker安装zookeeper</title>
<link href="/2019/docker-zookeeper/"/>
<url>/2019/docker-zookeeper/</url>
<content type="html"><![CDATA[<h3 id="拉取镜像"><a href="#拉取镜像" class="headerlink" title="拉取镜像"></a>拉取镜像</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull zookeeper:3.4</span><br></pre></td></tr></table></figure><h3 id="单机模式"><a href="#单机模式" class="headerlink" title="单机模式"></a>单机模式</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name zk -p 2181:2181 zookeeper:3.4</span><br></pre></td></tr></table></figure><h3 id="伪集群模式"><a href="#伪集群模式" class="headerlink" title="伪集群模式"></a>伪集群模式</h3><p>集群为大于等于3个奇数,如 3、5、7,不宜太多,集群机器多了选举和数据同步耗时长,不稳定。</p><p>创建docker-compose.yml文件,内容如下:</p><figure class="highlight yaml"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="attr">version:</span> <span class="string">'3.4'</span></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line"><span class="attr"> zk:</span></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line"><span class="attr"> zk1:</span></span><br><span class="line"><span class="attr"> image:</span> <span class="attr">zookeeper:3.4</span></span><br><span class="line"><span class="attr"> container_name:</span> <span class="string">zk1</span></span><br><span class="line"><span class="attr"> networks:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">zk</span></span><br><span class="line"><span class="attr"> ports:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">"21811:2181"</span></span><br><span class="line"><span class="attr"> environment:</span></span><br><span class="line"><span class="attr"> ZOO_MY_ID:</span> <span class="number">1</span></span><br><span class="line"><span class="attr"> ZOO_SERVERS:</span> <span class="string">server.1=0.0.0.0:2888:3888</span> <span class="string">server.2=zk2:2888:3888</span> <span class="string">server.3=zk3:2888:3888</span></span><br><span class="line"><span class="attr"> zk2:</span></span><br><span class="line"><span class="attr"> image:</span> <span class="attr">zookeeper:3.4</span></span><br><span class="line"><span class="attr"> container_name:</span> <span class="string">zk2</span></span><br><span class="line"><span class="attr"> networks:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">zk</span></span><br><span class="line"><span class="attr"> ports:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">"21812:2181"</span></span><br><span class="line"><span class="attr"> environment:</span></span><br><span class="line"><span class="attr"> ZOO_MY_ID:</span> <span class="number">2</span></span><br><span class="line"><span class="attr"> ZOO_SERVERS:</span> <span class="string">server.1=zk1:2888:3888</span> <span class="string">server.2=0.0.0.0:2888:3888</span> <span class="string">server.3=zk3:2888:3888</span></span><br><span class="line"><span class="attr"> zk3:</span></span><br><span class="line"><span class="attr"> image:</span> <span class="attr">zookeeper:3.4</span></span><br><span class="line"><span class="attr"> container_name:</span> <span class="string">zk3</span></span><br><span class="line"><span class="attr"> networks:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">zk</span></span><br><span class="line"><span class="attr"> ports:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">"21813:2181"</span></span><br><span class="line"><span class="attr"> environment:</span></span><br><span class="line"><span class="attr"> ZOO_MY_ID:</span> <span class="number">3</span></span><br><span class="line"><span class="attr"> ZOO_SERVERS:</span> <span class="string">server.1=zk1:2888:3888</span> <span class="string">server.2=zk2:2888:3888</span> <span class="string">server.3=0.0.0.0:2888:3888</span></span><br></pre></td></tr></table></figure><ol><li><p>创建容器不启动</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up --no-start</span><br></pre></td></tr></table></figure></li><li><p>创建容器并启动</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose up</span><br></pre></td></tr></table></figure></li><li><p>启动容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose start</span><br></pre></td></tr></table></figure></li><li><p>停止容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose stop</span><br></pre></td></tr></table></figure></li><li><p>移除停止的容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker-compose rm</span><br></pre></td></tr></table></figure></li></ol><h3 id="验证集群"><a href="#验证集群" class="headerlink" title="验证集群"></a>验证集群</h3><p>进入镜像</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it zk1 bash</span><br></pre></td></tr></table></figure><p>执行下面命令,查看状态</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">./bin/zkServer.sh status</span><br></pre></td></tr></table></figure><p>Mode: follower是从节点<br>Mode: leader是主节点</p><h3 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h3><p><a href="https://www.jianshu.com/p/c486133a70e4" target="_blank" rel="noopener">基于 Docker 安装 Zookeeper</a></p>]]></content>
<categories>
<category> Docker </category>
</categories>
<tags>
<tag> docker </tag>
<tag> zookeeper </tag>
</tags>
</entry>
<entry>
<title>Docker基础</title>
<link href="/2019/docker-basic/"/>
<url>/2019/docker-basic/</url>
<content type="html"><![CDATA[<h2 id="Ubuntu安装"><a href="#Ubuntu安装" class="headerlink" title="Ubuntu安装"></a>Ubuntu安装</h2><ol><li><p>获取最新版本的 Docker 安装包</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">wget -qO- https://get.docker.com/ | sh</span><br></pre></td></tr></table></figure><blockquote><p>当要以非root用户可以直接运行docker时,需要执行 sudo usermod -aG docker runoob 命令,然后重新登陆,否则会有报错<br>如果执行很慢的话,添加下面的源试试</p></blockquote><figure class="highlight shell"><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">sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak</span><br><span class="line">sudo sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list</span><br><span class="line">sudo apt update</span><br></pre></td></tr></table></figure></li><li><p>启动docker 后台服务</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo service docker start</span><br></pre></td></tr></table></figure></li><li><p>测试运行hello-world</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run hello-world</span><br></pre></td></tr></table></figure></li><li><p>镜像加速, 配置Daemon<br>创建 /etc/docker/daemon.json 文件,添加下面的内容:</p><figure class="highlight json"><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><br><span class="line"> <span class="attr">"registry-mirrors"</span>: [<span class="string">"http://hub-mirror.c.163.com"</span>]</span><br><span class="line">}</span><br></pre></td></tr></table></figure></li></ol><h2 id="Docker-使用"><a href="#Docker-使用" class="headerlink" title="Docker 使用"></a>Docker 使用</h2><h3 id="拉取镜像"><a href="#拉取镜像" class="headerlink" title="拉取镜像"></a>拉取镜像</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull tomcat</span><br></pre></td></tr></table></figure><h3 id="根据镜像创建容器"><a href="#根据镜像创建容器" class="headerlink" title="根据镜像创建容器"></a>根据镜像创建容器</h3><p>下面这个命令如果没有镜像,回去仓库去获取, –name 取一个名字, -p 进行端口映射</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name tomcat -p 8080:8080 tomcat:latest</span><br></pre></td></tr></table></figure><h3 id="查看镜像"><a href="#查看镜像" class="headerlink" title="查看镜像"></a>查看镜像</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker images</span><br></pre></td></tr></table></figure><h3 id="进入容器"><a href="#进入容器" class="headerlink" title="进入容器"></a>进入容器</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it tomcat bash</span><br></pre></td></tr></table></figure><h3 id="查看正在运行的容器"><a href="#查看正在运行的容器" class="headerlink" title="查看正在运行的容器"></a>查看正在运行的容器</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker ps</span><br></pre></td></tr></table></figure><h3 id="部署项目到tomcat"><a href="#部署项目到tomcat" class="headerlink" title="部署项目到tomcat"></a>部署项目到tomcat</h3><p>把项目打包成war文件,假设为demo.war, 然后在war包所在的目录,执行以下命令, war包会自动解压,然后执行下面命令重启容器</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker cp demo.war mytomcat:/usr/local/tomcat/webapps</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker restart mytomcat</span><br></pre></td></tr></table></figure><h3 id="测试tomcat容器"><a href="#测试tomcat容器" class="headerlink" title="测试tomcat容器"></a>测试tomcat容器</h3><p>如果没有war包, 当然也可以先自己写一个index.html文件, 然后拷贝到容器中,</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">h1</span>></span>Demo!<span class="tag"></<span class="name">h1</span>></span></span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec -it tomcat bash</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">mkdir -p /usr/local/tomcat/webapps/demo</span><br></pre></td></tr></table></figure><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker cp index.html tomcat:/usr/local/tomcat/webapps/demo</span><br></pre></td></tr></table></figure><p>最后在浏览器输入:<a href="http://localhost:8080/demo" target="_blank" rel="noopener">http://localhost:8080/demo</a> ,即可访问项目</p><h3 id="挂载目录"><a href="#挂载目录" class="headerlink" title="挂载目录"></a>挂载目录</h3><p>将主机中当前目录下的test挂载到容器的/test</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run --name tomcat -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/test -d tomcat</span><br></pre></td></tr></table></figure><h3 id="DockerFile"><a href="#DockerFile" class="headerlink" title="DockerFile"></a>DockerFile</h3><p>创建自定义的tomcat镜像</p><figure class="highlight plain"><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></pre></td><td class="code"><pre><span class="line">FROM centos</span><br><span class="line">MAINTAINER [email protected]</span><br><span class="line">#把宿主机的文件拷贝到容器中</span><br><span class="line">COPY c.txt /user/local/cincontainer.txt</span><br><span class="line">#拷贝java和tomcat并解压</span><br><span class="line">ADD jdk-8u171-linux-x64.tar.gz /usr/local/</span><br><span class="line">ADD apache-tomcat-9.0.8.tar.gz /usr/local/</span><br><span class="line">#安装vim编辑器</span><br><span class="line">RUN yum -y install vim</span><br><span class="line">#设置工作访问时候的路径,登录落脚点</span><br><span class="line">ENV MYPATH /usr/local/</span><br><span class="line">WORKDIR $MYPATH</span><br><span class="line">#配置java和tomcat的环境变量</span><br><span class="line">ENV JAVA_HOME user/local/jdk1.8.0_171</span><br><span class="line">ENV CLASSPATH $JAVA_HOME/lib/dt.jar:JAVA_HOME/lib/tools.jar</span><br><span class="line">ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.8</span><br><span class="line">ENV CATALINA_BASE /usr/local/apache-tomcat-9.0.8</span><br><span class="line">ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin:CATALINA_BASE/bin</span><br><span class="line"># 容器运行时监听端口</span><br><span class="line">EXPOSE 8080</span><br><span class="line">#启动运行tomcat</span><br><span class="line">CMD ["/usr/local/apache-tomcat-9.0.8/bin/catalina.sh","run"]</span><br></pre></td></tr></table></figure><p>构建</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build -f Dockerfile tomcat9 .</span><br></pre></td></tr></table></figure><p>或者默认编译文件名为Dockerfile,则可以使用下面的命令</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker build -t tomcat9:1.0 .</span><br></pre></td></tr></table></figure><h3 id="安装Mysql"><a href="#安装Mysql" class="headerlink" title="安装Mysql"></a>安装Mysql</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -p 3306:3306 --name mysql -v /usr/local/mysql/conf:/etc/mysql/conf.d -v /usr/local/mysql/logs:/logs -v /usr/local/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.6</span><br></pre></td></tr></table></figure><p>所有数据库dump为sql文件</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker exec mysql sh -c 'exec mysqldump --all-databases -uroot -p"123456" ' > /usr/local/all-databases.sql</span><br></pre></td></tr></table></figure><h3 id="安装Redis"><a href="#安装Redis" class="headerlink" title="安装Redis"></a>安装Redis</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull redis:3.2</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -p 6379:6379 --name redis -v /usr/local/redis/data:/data -v /usr/local/redis/conf/redis.conf:/usr/local/etc/redis/redis.conf -d redis:3.2 redis-server /usr/local/etc/redis/redis.conf --appendonly yes</span><br></pre></td></tr></table></figure><h3 id="发布镜像到云"><a href="#发布镜像到云" class="headerlink" title="发布镜像到云"></a>发布镜像到云</h3><p>本地的容器提交为本地镜像</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker commit -a iuin -m "new images" 容器ID centos:2.0</span><br></pre></td></tr></table></figure><p>本地镜像推到云端</p><figure class="highlight plain"><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">docker login</span><br><span class="line"></span><br><span class="line">docker tag [ImageId] iuin/centos:2.0</span><br><span class="line"></span><br><span class="line">docker push iuin/centos:2.0</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> Docker </category>
</categories>
<tags>
<tag> docker </tag>
</tags>
</entry>
<entry>
<title>Slides 演示</title>
<link href="/2019/slides-demo/"/>
<url>/2019/slides-demo/</url>
<content type="html"><![CDATA[<h2 id="Slides-演示"><a href="#Slides-演示" class="headerlink" title="Slides 演示"></a>Slides 演示</h2><!-- .slide: data-background="#00C4B6" data-transition="concave"--><h1 id="Author-Fulin"><a href="#Author-Fulin" class="headerlink" title="Author: Fulin "></a>Author: Fulin <!-- .element: style="float: left;margin-top:200px;"--></h1><h2 id="Agenda"><a href="#Agenda" class="headerlink" title="Agenda"></a>Agenda</h2><!-- .slide: data-background="#C7916B" data-transition="concave"--><ul><li>Item 1 <!-- .element: class="fragment" data-fragment-index="1" --></li><li>Item 2 <!-- .element: class="fragment" data-fragment-index="2" --></li><li><h1 id="Item-3"><a href="#Item-3" class="headerlink" title="Item 3 "></a>Item 3 <!-- .element: class="fragment" data-fragment-index="3" --></h1></li></ul><h2 id="1-Add-a-slides-page"><a href="#1-Add-a-slides-page" class="headerlink" title="1. Add a slides page"></a>1. Add a slides page</h2><p>// ……</p><p>===</p><p>// ……</p><p>===</p><h2 id="2-Add-the-layout-type"><a href="#2-Add-the-layout-type" class="headerlink" title="2. Add the layout type"></a>2. Add the layout type</h2><!-- .slide: data-transition="fade" data-background="#00C4B6" --><p>// ……</p>]]></content>
<categories>
<category> 其它 </category>
</categories>
<tags>
<tag> slides </tag>
</tags>
</entry>
<entry>
<title>Hexo Theme Melody</title>
<link href="/2019/hexo-melody/"/>
<url>/2019/hexo-melody/</url>
<content type="html"><![CDATA[<p><strong>主题配置问路径hexo-blog\themes\melody_config.yml</strong></p><h2 id="代码高亮主题"><a href="#代码高亮主题" class="headerlink" title="代码高亮主题"></a>代码高亮主题</h2><p>theme-melody 支持了Material Theme全部5种代码高亮样式:</p><ul><li>default</li><li>darker</li><li>pale night</li><li>light</li><li>ocean (从v1.5.5开始支持)</li></ul><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">highlight_theme:</span> <span class="string">default</span> <span class="comment"># default/darker/pale night/light</span></span><br></pre></td></tr></table></figure><h2 id="代码换行"><a href="#代码换行" class="headerlink" title="代码换行"></a>代码换行</h2><p>在默认情况下,hexo-highlight在编译的时候不会实现代码自动换行。如果你不希望在代码块的区域里有横向滚动条的话,那么你可以考虑开启这个功能。</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">code_word_wrap:</span> <span class="literal">true</span></span><br></pre></td></tr></table></figure><p>然后找到你站点的hexo配置文件_config.yml,你能看到类似如下highlight的配置:</p><figure class="highlight yml"><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="attr">highlight:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> line_number:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> auto_detect:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr"> tab_replace:</span></span><br></pre></td></tr></table></figure><p>请将line_number改成false:</p><figure class="highlight yml"><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="attr">highlight:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> line_number:</span> <span class="literal">false</span> <span class="comment"># <- 改这里</span></span><br><span class="line"><span class="attr"> auto_detect:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr"> tab_replace:</span></span><br></pre></td></tr></table></figure><h2 id="导航菜单"><a href="#导航菜单" class="headerlink" title="导航菜单"></a>导航菜单</h2><p>在右上角的区域是导航菜单项。Hexo有默认的/和/archives的路径。如果你想拥有其他比如tags和categories的页面,请按照下面步骤来操作:</p><ol><li>前往你的Hexo博客的根目录</li><li>输入hexo new page tags</li><li>你会找到source/tags/index.md这个文件</li><li>修改这个文件<figure class="highlight yml"><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="meta">---</span></span><br><span class="line"><span class="attr">title:</span> <span class="string">标签</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2018</span><span class="bullet">-01</span><span class="bullet">-05</span> <span class="number">00</span><span class="string">:00:00</span></span><br><span class="line"><span class="attr">type:</span> <span class="string">"tags"</span></span><br><span class="line"><span class="meta">---</span></span><br></pre></td></tr></table></figure></li></ol><blockquote><p>type必须是tags!如果你要增加categories页面的话也是一样的。</p></blockquote><figure class="highlight yml"><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="attr">menu:</span></span><br><span class="line"><span class="attr"> Home:</span> <span class="string">/</span></span><br><span class="line"><span class="attr"> Archives:</span> <span class="string">/archives</span></span><br><span class="line"><span class="attr"> Tags:</span> <span class="string">/tags</span></span><br><span class="line"><span class="attr"> Categories:</span> <span class="string">/categories</span></span><br></pre></td></tr></table></figure><p>你也可以修改菜单项名称</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">menu:</span></span><br><span class="line"> <span class="string">主页:</span> <span class="string">/</span></span><br></pre></td></tr></table></figure><h2 id="自动节选"><a href="#自动节选" class="headerlink" title="自动节选"></a>自动节选</h2><p>现在,从版本1.5开始,如果你没有在<code>melody.yml</code>里设置<code>auto_excerpt</code>的选项,你的文章将会在首页上完整地展现出来。如果你在文章里加上了<code><!-- more --></code>标记,那么它将会被替换成阅读更多的一个按钮。如果你不想在每篇文章里都加上<code><!-- more --></code>这个标记,那么你可以通过设置<code>auto_excerpt</code>来自动帮你生成文章节选。(默认取前150个字)</p><figure class="highlight yml"><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="attr">auto_excerpt:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> length:</span> <span class="number">150</span></span><br></pre></td></tr></table></figure><h2 id="顶部图"><a href="#顶部图" class="headerlink" title="顶部图"></a>顶部图</h2><p>顶部图是theme-melody最神奇的配置项. 它拥有true、false或者具体图片url三种值.</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">top_img:</span> <span class="literal">true</span> <span class="comment"># 默认图</span></span><br></pre></td></tr></table></figure><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">top_img:</span> <span class="literal">false</span> <span class="comment"># 无图</span></span><br></pre></td></tr></table></figure><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">top_img:</span> <span class="attr">https://xxxxx.jpg</span> <span class="comment"># 自定义图</span></span><br></pre></td></tr></table></figure><h3 id="为特定的文章页配置特定的顶部图"><a href="#为特定的文章页配置特定的顶部图" class="headerlink" title="为特定的文章页配置特定的顶部图"></a>为特定的文章页配置特定的顶部图</h3><p>在你的文章md文件的头部,加入top_img项,然后输入你想要的顶部图的url即可</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">title:</span> <span class="string">Hi,</span> <span class="string">theme-melody!</span></span><br><span class="line"><span class="attr">tags:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">hexo</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">hexo</span> <span class="string">theme</span></span><br><span class="line"><span class="attr">top_img:</span> <span class="attr">https://xxxxxxx.jpg</span> <span class="comment"># < top_img在这里插入</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2017</span><span class="bullet">-09</span><span class="bullet">-07</span></span><br><span class="line"><span class="meta">---</span></span><br></pre></td></tr></table></figure><h2 id="文章相关项"><a href="#文章相关项" class="headerlink" title="文章相关项"></a>文章相关项</h2><p>这个选项是用来显示文章的相关信息的。</p><figure class="highlight yml"><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"><span class="attr">post_meta:</span></span><br><span class="line"><span class="attr"> date_type:</span> <span class="string">created</span> <span class="comment"># or updated 文章日期是创建日或者更新日</span></span><br><span class="line"><span class="attr"> categories:</span> <span class="literal">true</span> <span class="comment"># or false 是否显示分类</span></span><br><span class="line"><span class="attr"> tags:</span> <span class="literal">true</span> <span class="comment"># or false 是否显示标签</span></span><br></pre></td></tr></table></figure><h2 id="文章相关二维码"><a href="#文章相关二维码" class="headerlink" title="文章相关二维码"></a>文章相关二维码</h2><p>在你每篇文章的结尾,给读者展示你自己的二维码。二维码的图片url以及相关说明都取决于你。配置格式如下:</p><figure class="highlight yml"><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="attr">QR_code:</span></span><br><span class="line"><span class="attr"> - itemlist:</span></span><br><span class="line"><span class="attr"> img:</span> <span class="attr">https://xxxx1.jpg</span></span><br><span class="line"><span class="attr"> text:</span> <span class="string">支付宝打赏</span></span><br><span class="line"><span class="attr"> - itemlist:</span></span><br><span class="line"><span class="attr"> img:</span> <span class="attr">https://xxxx2.jpg</span></span><br><span class="line"><span class="attr"> text:</span> <span class="string">微信打赏</span></span><br></pre></td></tr></table></figure><h2 id="文章广告区"><a href="#文章广告区" class="headerlink" title="文章广告区"></a>文章广告区</h2><p>在你的文章页面里加上广告!你可以放置一个你自己想展示的广告或者也可以是个音乐播放器等等。这个区域你做主。<br>info中是想展示的内容</p><figure class="highlight yml"><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="attr">adv:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> info:</span> <span class="string"><a</span> <span class="string">href="https://www.vultr.com/?ref=7231808"><img</span> <span class="string">src="https://www.vultr.com/media/banner_1.png"</span> <span class="string">width="728"</span> <span class="string">height="90"></a></span></span><br></pre></td></tr></table></figure><h2 id="头像"><a href="#头像" class="headerlink" title="头像"></a>头像</h2><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">avatar:</span> <span class="attr">https://xxxx.jpg</span></span><br></pre></td></tr></table></figure><h2 id="Follow-Me-按钮"><a href="#Follow-Me-按钮" class="headerlink" title="Follow Me 按钮"></a>Follow Me 按钮</h2><figure class="highlight yml"><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"><span class="attr">follow:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span></span><br><span class="line"><span class="attr"> url:</span> <span class="string">'https://github.com/USERNAME'</span></span><br><span class="line"><span class="attr"> text:</span> <span class="string">'Follow Me'</span></span><br></pre></td></tr></table></figure><h2 id="目录"><a href="#目录" class="headerlink" title="目录"></a>目录</h2><p>你的文章能够拥有一个清晰的目录列表。目录位于侧边栏,并且会随着滚动条的滚动自动展开目录结构。</p><figure class="highlight yml"><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="attr">toc:</span></span><br><span class="line"><span class="attr"> enable:</span> <span class="literal">true</span> <span class="comment"># or false</span></span><br><span class="line"><span class="attr"> number:</span> <span class="literal">true</span> <span class="comment"># or false. 版本v1.5.6新增</span></span><br></pre></td></tr></table></figure><h2 id="为特定的文章配置特定的目录章节数字"><a href="#为特定的文章配置特定的目录章节数字" class="headerlink" title="为特定的文章配置特定的目录章节数字"></a>为特定的文章配置特定的目录章节数字</h2><p>在你的文章md文件的头部,加入toc_number项,并配置true或者false即可</p><figure class="highlight yml"><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="attr">title:</span> <span class="string">Hi,</span> <span class="string">theme-melody!</span></span><br><span class="line"><span class="attr">tags:</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">hexo</span></span><br><span class="line"><span class="bullet"> -</span> <span class="string">hexo</span> <span class="string">theme</span></span><br><span class="line"><span class="attr">toc_number:</span> <span class="literal">false</span> <span class="comment"># < add toc_number to here. 版本v1.5.6新增</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2017</span><span class="bullet">-09</span><span class="bullet">-07</span></span><br><span class="line"><span class="meta">---</span></span><br></pre></td></tr></table></figure><h2 id="页脚自定义文本"><a href="#页脚自定义文本" class="headerlink" title="页脚自定义文本"></a>页脚自定义文本</h2><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">footer_custom_text:</span> <span class="string">Hi,</span> <span class="string">welcome</span> <span class="string">to</span> <span class="string">my</span> <span class="string"><a</span> <span class="string">href="https://molunerfinn.com">blog</a>!</span></span><br></pre></td></tr></table></figure><h2 id="幻灯片Slides页面"><a href="#幻灯片Slides页面" class="headerlink" title="幻灯片Slides页面"></a>幻灯片Slides页面</h2><p>幻灯片Slides页面,可以做PPT展示</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">slide:</span></span><br><span class="line"><span class="attr"> separator:</span> <span class="meta">---</span></span><br><span class="line"><span class="attr"> separator_vertical:</span> <span class="bullet">--</span></span><br><span class="line"><span class="attr"> charset:</span> <span class="string">utf-8</span></span><br><span class="line"><span class="attr"> theme:</span> <span class="string">black</span></span><br><span class="line"><span class="attr"> mouseWheel:</span> <span class="literal">false</span></span><br><span class="line"><span class="attr"> transition:</span> <span class="string">slide</span></span><br><span class="line"><span class="attr"> transitionSpeed:</span> <span class="string">default</span></span><br><span class="line"><span class="attr"> parallaxBackgroundImage:</span> <span class="string">''</span></span><br><span class="line"><span class="attr"> parallaxBackgroundSize:</span> <span class="string">''</span></span><br><span class="line"><span class="attr"> parallaxBackgroundHorizontal:</span> <span class="literal">null</span></span><br><span class="line"><span class="attr"> parallaxBackgroundVertical:</span> <span class="literal">null</span></span><br></pre></td></tr></table></figure><blockquote><p>上述是 theme-melody 所提供的 reveal.js 的配置项, 可以参考官方文档的说明 <a href="https://github.com/hakimel/reveal.js#configuration" target="_blank" rel="noopener">https://github.com/hakimel/reveal.js#configuration</a></p></blockquote><h2 id="创建一个slide文章页面"><a href="#创建一个slide文章页面" class="headerlink" title="创建一个slide文章页面"></a>创建一个slide文章页面</h2><p>像往常一样在文章文件夹里创建一个md文件. 在该文件的顶部配置区加上一个layout: slides配置项。</p><figure class="highlight plain"><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">title: hexo-theme-melody v1.5 supports iframe & slides</span><br><span class="line">date: 2018-03-06 19:57:52</span><br><span class="line">layout: slides</span><br></pre></td></tr></table></figure><p>除了在melody.yml里配置全局的slides页面属性,你也可以为你的某个页面配置单独的slide设置。</p><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="attr">title:</span> <span class="string">hexo-theme-melody</span> <span class="string">v1.5</span> <span class="string">supports</span> <span class="string">slides</span> <span class="string">&</span> <span class="string">iframe</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2018</span><span class="bullet">-03</span><span class="bullet">-06</span> <span class="number">19</span><span class="string">:57:52</span></span><br><span class="line"><span class="attr">tags:</span> <span class="string">hexo</span></span><br><span class="line"><span class="attr">layout:</span> <span class="string">slides</span></span><br><span class="line"><span class="attr">slide:</span></span><br><span class="line"><span class="attr"> theme:</span> <span class="string">night</span></span><br><span class="line"><span class="attr"> separator:</span> <span class="string">===</span></span><br><span class="line"><span class="attr"> separator_vertical:</span> <span class="string">==</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"></span><br><span class="line"><span class="comment">### hexo-theme-melody <small>v1.5</small></span></span><br><span class="line"><span class="string"><!--</span> <span class="string">.slide:</span> <span class="string">data-background="#49B1F5"</span> <span class="bullet">--></span></span><br><span class="line"></span><br><span class="line"><span class="string">Supports</span> <span class="string">iframe</span> <span class="string">&</span> <span class="string">slides.</span> <span class="string">You</span> <span class="string">can</span> <span class="string">use</span> <span class="string">a</span> <span class="string">layout</span> <span class="string">called</span> <span class="string">`slides`</span> <span class="string">to</span> <span class="string">enabled</span> <span class="string">the</span> <span class="string">slides</span> <span class="string">layout.</span></span><br><span class="line"></span><br><span class="line"><span class="string">Also</span> <span class="string">you</span> <span class="string">can</span> <span class="string">add</span> <span class="string">a</span> <span class="string">`iframe`</span> <span class="string">front-matter</span> <span class="string">with</span> <span class="string">the</span> <span class="string">`slides`</span> <span class="string">layout</span> <span class="string">in</span> <span class="string">your</span> <span class="string">`md`</span> <span class="string">file</span> <span class="string">to</span> <span class="string">enable</span> <span class="string">the</span> <span class="string">iframe</span> <span class="string">page.</span></span><br><span class="line"></span><br><span class="line"><span class="comment">### Steps</span></span><br><span class="line"><span class="string"><!--</span> <span class="string">.slide:</span> <span class="string">data-transition="concave"</span> <span class="string">data-background="#C7916B"</span> <span class="bullet">--></span></span><br><span class="line"></span><br><span class="line"><span class="comment">#### 1. Add a slides page</span></span><br><span class="line"></span><br><span class="line"><span class="string">//</span> <span class="string">......</span></span><br><span class="line"></span><br><span class="line"><span class="string">==</span></span><br><span class="line"></span><br><span class="line"><span class="string">//</span> <span class="string">......</span></span><br><span class="line"></span><br><span class="line"><span class="string">===</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#### 2. Add the layout type</span></span><br><span class="line"><span class="string"><!--</span> <span class="string">.slide:</span> <span class="string">data-transition="fade"</span> <span class="string">data-background="#00C4B6"</span> <span class="bullet">--></span></span><br><span class="line"></span><br><span class="line"><span class="string">//</span> <span class="string">......</span></span><br></pre></td></tr></table></figure><h2 id="创建一个Iframe页面"><a href="#创建一个Iframe页面" class="headerlink" title="创建一个Iframe页面"></a>创建一个Iframe页面</h2><p>如果你想创建一个只有Iframe的页面,可以在文章的顶部配置区加入iframe的选项。</p><figure class="highlight yml"><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"><span class="attr">title:</span> <span class="string">hexo-theme-melody</span> <span class="string">v1.5</span> <span class="string">supports</span> <span class="string">iframe</span> <span class="string">&</span> <span class="string">slides</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2018</span><span class="bullet">-03</span><span class="bullet">-06</span> <span class="number">19</span><span class="string">:57:52</span></span><br><span class="line"><span class="attr">layout:</span> <span class="string">slides</span></span><br><span class="line"><span class="attr">iframe:</span> <span class="attr">https://the-url-whatever-you-like</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>layout: slides必须指定,否则iframe的页面将不生效</strong></p></blockquote><h2 id="创建Slides页面"><a href="#创建Slides页面" class="headerlink" title="创建Slides页面"></a>创建Slides页面</h2><ol><li>前往你的Hexo博客的根目录</li><li>输入hexo new page slides</li><li>你会找到source/slides/index.md这个文件</li><li>修改这个文件</li></ol><h2 id="创建相册页"><a href="#创建相册页" class="headerlink" title="创建相册页"></a>创建相册页</h2><p>theme-melody 提供了一个叫做gallery的标签,让你能够在markdown文件里生成gallery-item。</p><p>修改你刚刚创建的source/gallery/index.md,并加上gallery 标签。</p><figure class="highlight yml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="string">img-url</span> <span class="string">[title]</span> <span class="string">%}</span></span><br></pre></td></tr></table></figure><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="attr">title:</span> <span class="string">Gallery</span> </span><br><span class="line"><span class="attr">date:</span> <span class="number">2018</span><span class="bullet">-01</span><span class="bullet">-05</span> <span class="number">00</span><span class="string">:00:00</span></span><br><span class="line"><span class="attr">type:</span> <span class="string">"gallery"</span></span><br><span class="line"><span class="meta">---</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://ws1.sinaimg.cn/large/8700af19gy1fp5i6o2vghj20ea0eajse</span> <span class="string">melody</span> <span class="string">%}</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://user-images.githubusercontent.com/12621342/37325500-23e8f77c-26c9-11e8-8e24-eb4346f1fff5.png</span> <span class="string">background</span> <span class="string">%}</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://ws1.sinaimg.cn/large/8700af19gy1fp5i64zaxqj20b40b474b</span> <span class="string">demo1</span> <span class="string">%}</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://ws1.sinaimg.cn/large/8700af19ly1fn2h26q32uj21120kudqq</span> <span class="string">demo2</span> <span class="string">%}</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://ws1.sinaimg.cn/large/8700af19ly1fnhdaimi40j218g0p0dic</span> <span class="string">demo3</span> <span class="string">%}</span></span><br><span class="line"><span class="string">{%</span> <span class="string">gallery</span> <span class="attr">https://ws1.sinaimg.cn/large/8700af19ly1fn2i5kjh2pj21120kuncd</span> <span class="string">%}</span></span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> 其它 </category>
</categories>
<tags>
<tag> 其他 </tag>
</tags>
</entry>
<entry>
<title>Angular国际化</title>
<link href="/2019/angular-i18n/"/>
<url>/2019/angular-i18n/</url>
<content type="html"><![CDATA[<h2 id="安装-ngx-translate模块包"><a href="#安装-ngx-translate模块包" class="headerlink" title="安装 ngx-translate模块包"></a>安装 ngx-translate模块包</h2><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">npm install <span class="meta">@ngx</span>-translate/core --save</span><br><span class="line">npm install <span class="meta">@ngx</span>-translate/http-loader --save</span><br></pre></td></tr></table></figure><blockquote><p>ng6 需引入ngx-translate 10.0以上版本</p></blockquote><h2 id="创建-i18n-语言文件"><a href="#创建-i18n-语言文件" class="headerlink" title="创建 i18n 语言文件"></a>创建 i18n 语言文件</h2><p>在src文件夹下创建 国际化语言文件夹 locales,在locales文件夹下创建相应的语言包文件,如图</p><p><img src="locales.png" alt="资源文件"></p><blockquote><p>建议放在assets/i18n文件夹下</p></blockquote><h2 id="根模块app-module-ts-导入该模块"><a href="#根模块app-module-ts-导入该模块" class="headerlink" title="根模块app.module.ts 导入该模块"></a>根模块app.module.ts 导入该模块</h2><p>导入所需要的包</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {TranslateModule, TranslateLoader} <span class="keyword">from</span> <span class="string">'@ngx-translate/core'</span>;</span><br><span class="line"><span class="keyword">import</span> {TranslateHttpLoader} <span class="keyword">from</span> <span class="string">'@ngx-translate/http-loader'</span>;</span><br></pre></td></tr></table></figure><p>因为我们采用的是外部文件配置语言包的方法,所以还需要引入http模块</p><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> {HttpClientModule, HttpClient} <span class="keyword">from</span> <span class="string">'@angular/common/http'</span>;</span><br></pre></td></tr></table></figure><p>模块配置</p><figure class="highlight ts"><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="comment">//导出加载函数</span></span><br><span class="line"><span class="keyword">export</span> <span class="function"><span class="keyword">function</span> <span class="title">createTranslateHttpLoader</span>(<span class="params">http:HttpClient</span>)</span>{</span><br><span class="line"> <span class="keyword">return</span> <span class="keyword">new</span> TranslateHttpLoader(http, <span class="string">'./locales/'</span>, <span class="string">'.json'</span>);</span><br><span class="line">}</span><br><span class="line"><span class="meta">@NgModule</span>({</span><br><span class="line"> declarations: [</span><br><span class="line"> AppComponent</span><br><span class="line">],</span><br><span class="line">imports: [</span><br><span class="line"> TranslateModule.forRoot({</span><br><span class="line"> loader:{</span><br><span class="line"> provide:TranslateLoader,</span><br><span class="line"> useFactory:[createTranslateHttpLoader],</span><br><span class="line"> deps:[HttpClient]</span><br><span class="line"> }</span><br><span class="line"> })</span><br><span class="line">],</span><br><span class="line">providers: [],</span><br><span class="line">bootstrap: [AppComponent]</span><br><span class="line">})</span><br></pre></td></tr></table></figure><h2 id="在组件中使用"><a href="#在组件中使用" class="headerlink" title="在组件中使用"></a>在组件中使用</h2><p>1.ts文件使用translateService服务</p><figure class="highlight ts"><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="keyword">import</span> { TranslateService } <span class="keyword">from</span> <span class="string">'@ngx-translate/core'</span>;</span><br><span class="line"><span class="meta">@Component</span>({</span><br><span class="line"> selector: <span class="string">'app-root'</span>,</span><br><span class="line"> templateUrl: <span class="string">'./app.component.html'</span>,</span><br><span class="line"> styleUrls: [<span class="string">'./app.component.css'</span>]</span><br><span class="line">})</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">class</span> AppComponent {</span><br><span class="line"> title = <span class="string">'app'</span>;</span><br><span class="line"> en=<span class="literal">true</span>;</span><br><span class="line"> zh=<span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">constructor</span>(<span class="params"><span class="keyword">private</span> translate:TranslateService</span>){</span><br><span class="line"> <span class="comment">//添加语言支持</span></span><br><span class="line"> translate.addLangs([<span class="string">"en"</span>, <span class="string">"zh"</span>]);</span><br><span class="line"> <span class="comment">//设置默认语言,一般在无法匹配的时候使用</span></span><br><span class="line"> translate.setDefaultLang(<span class="string">'zh'</span>);</span><br><span class="line"> <span class="comment">//获取当前浏览器环境的语言比如en、 zh</span></span><br><span class="line"> <span class="keyword">let</span> browserLang = translate.getBrowserLang();</span><br><span class="line"> translate.use(browserLang.match(<span class="regexp">/en|zh/</span>) ? browserLang : <span class="string">'zh'</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"> changeLang(lang) {</span><br><span class="line"> <span class="keyword">this</span>.translate.use(lang);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>2.html中使用</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag"><<span class="name">div</span> <span class="attr">style</span>=<span class="string">"margin-top:50px;"</span>></span>{{'welcome' | translate}<span class="tag"></<span class="name">div</span>></span></span><br><span class="line"><span class="tag"><<span class="name">div</span>></span>{{'title' | translate}}!<span class="tag"></<span class="name">div</span>></span></span><br></pre></td></tr></table></figure><p>TranslateService提供了一系列的方法,这里讲下get和instant两个方法。get方法有两个参数,第一个参数是键,必填,字符串或字符串数组类型,第二个参数是插入字符串中的值,可选,对象类型。返回类型为Observable,注意,如果第一个参数传递的是数组,返回的数据是以数组元素为键的对象。<br>instant方法的参数和返回类型与get方法一致,与get方法不同的是该方法是同步的,当lang改变时,是无法即时更新的。大多数时候,instant方法可以满足我们的使用需求,可是在页面缓存的情况下,比如动态的标签栏,无法动态刷新。<br>如果想要动态刷新,可以使用onLangChange去监听语言切换时间,然后再次调用instant方法去获取新的值。</p>]]></content>
<categories>
<category> 前端 </category>
<category> Angular </category>
</categories>
<tags>
<tag> Angular </tag>
<tag> 国际化 </tag>
</tags>
</entry>
<entry>
<title>SpringBoot国际化</title>
<link href="/2019/spring-boot-i18n/"/>
<url>/2019/spring-boot-i18n/</url>
<content type="html"><![CDATA[<p>我们可以利用MessageSource接口中的getMessage方法去访问本地化资源文件</p><p>MessagesSource只是一个接口,真正的实现类是ResourceBundleMessageSource, 它默认会加载classpath路径下messages开头的properties文件。如果要自定义路径,配置spring.messages.basename的值即可。默认格式是messages_国家_地区.properties。我们这里省略了地区。</p><p><img src="ResourceBundleMessageSource.png" alt="ResourceBundleMessageSource"></p><p>LocaleContextHolder类中的getLocale方法可以获取请求中Accept-Language属性的值,如果获取不到语言类型,会去messages.properties文件中去找</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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">import</span> org.springframework.context.MessageSource;</span><br><span class="line"><span class="keyword">import</span> org.springframework.context.i18n.LocaleContextHolder;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Service;</span><br><span class="line"></span><br><span class="line"><span class="meta">@Service</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">I18nService</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> MessageSource messageSource;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">I18nService</span><span class="params">(MessageSource messageSource)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.messageSource = messageSource;</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">getMessage</span><span class="params">(String code)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> getMessage(code, (Object[]) <span class="keyword">null</span>);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> String <span class="title">getMessage</span><span class="params">(String code, Object... args)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> messageSource.getMessage(code, args, LocaleContextHolder.getLocale());</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">getMessage</span><span class="params">(String code, Object[] args, String defaultMessage)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> messageSource.getMessage(code, args, defaultMessage, LocaleContextHolder.getLocale());</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">spring.messages.basename=i18n/messages</span><br></pre></td></tr></table></figure>]]></content>
<categories>
<category> SpringBoot </category>
<category> 国际化 </category>
</categories>
<tags>
<tag> 国际化 </tag>
<tag> SpringBoot </tag>
</tags>
</entry>
<entry>
<title>单例模式</title>
<link href="/2019/singleton-pattern/"/>
<url>/2019/singleton-pattern/</url>
<content type="html"><![CDATA[<p>单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。</p><p>这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。</p><h2 id="单例模式的实现方式"><a href="#单例模式的实现方式" class="headerlink" title="单例模式的实现方式"></a>单例模式的实现方式</h2><h3 id="饿汉式"><a href="#饿汉式" class="headerlink" title="饿汉式"></a>饿汉式</h3><p><strong>延迟初始化</strong>:否<br><strong>多线程安全</strong>:是</p><p><strong>优点</strong>:没有加锁,执行效率会提高。<br><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></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">Singleton</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance = <span class="keyword">new</span> Singleton();</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</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> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> instance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。</p></blockquote><h3 id="双检锁-双重校验锁-DCL"><a href="#双检锁-双重校验锁-DCL" class="headerlink" title="双检锁/双重校验锁 DCL"></a>双检锁/双重校验锁 DCL</h3><p><strong>延迟初始化</strong>:是<br><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></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">Singleton</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">static</span> Singleton singleton;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</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> Singleton <span class="title">getSingleton</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">if</span> (singleton == <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">synchronized</span> (Singleton.class) {</span><br><span class="line"> <span class="keyword">if</span> (singleton == <span class="keyword">null</span>) {</span><br><span class="line"> singleton = <span class="keyword">new</span> Singleton();</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> singleton;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>这种方式采用双锁机制,安全且在多线程情况下能保持高性能。这里必须添加<strong>volatile</strong> 关键字,使得该实例对其他线程可见,不然会有小概率导致多线程不安全,具体出现的情况有可能是空指针异常。一个线程已经已经将singleton 的引用指向了一块内存地址,但是对象还为空,但其它线程不可见,判断不为null就直接返回了。</p></blockquote><h3 id="登记式-静态内部类"><a href="#登记式-静态内部类" class="headerlink" title="登记式/静态内部类"></a>登记式/静态内部类</h3><p><strong>延迟初始化</strong>:是<br><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></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">Singleton</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SingletonHolder</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton INSTANCE = <span class="keyword">new</span> Singleton();</span><br><span class="line"> }</span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="title">Singleton</span> <span class="params">()</span></span>{} </span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Singleton <span class="title">getInstance</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> SingletonHolder.INSTANCE;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><blockquote><p>这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。<br>这种方式同样利用了 classloader 机制来保证初始化 instance 时只有一个线程,它跟第 1 种方式不同的是:第 1 种方式只要 Singleton 类被装载了,那么 instance 就会被实例化(没有达到 lazy loading 效果),而这种方式是 Singleton 类被装载了,instance 不一定被初始化。因为 SingletonHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance。想象一下,如果实例化 instance 很消耗资源,所以想让它延迟加载,另外一方面,又不希望在 Singleton 类加载时就实例化,因为不能确保 Singleton 类还可能在其他的地方被主动使用从而被加载,那么这个时候实例化 instance 显然是不合适的。这个时候,这种方式相比第 1 种方式就显得很合理。</p></blockquote>]]></content>
<categories>
<category> 设计模式 </category>
<category> 单例模式 </category>
</categories>
<tags>
<tag> 设计模式 </tag>
</tags>
</entry>
<entry>
<title>TCP协议</title>
<link href="/2019/tcp/"/>
<url>/2019/tcp/</url>
<content type="html"><![CDATA[<p>在介绍TCP协议之前,需要先了解一下<code>4/7层网络模型</code></p><h2 id="4-7层网络模型"><a href="#4-7层网络模型" class="headerlink" title="4/7层网络模型"></a>4/7层网络模型</h2><h2 id="TCP特点"><a href="#TCP特点" class="headerlink" title="TCP特点"></a>TCP特点</h2><ul><li>基于链接(点对点)</li><li>双工通信</li><li>可靠传输</li><li>拥塞控制,在网络状况不佳的时候尽量降低系统由于重传带来的带宽开销</li><li>基于字节流而非报文</li></ul><h2 id="建立链接三次握手"><a href="#建立链接三次握手" class="headerlink" title="建立链接三次握手"></a>建立链接三次握手</h2><p>三次握手,简单来说,就是:</p><ul><li>发送方:我要和你建立链接了哦!</li><li>接收方:你真的要和我建立链接吗?</li><li>发送方:我真的要和你建立链接(成功).</li></ul><blockquote><p><strong>SYN</strong>: (同步序列编号,Synchronize Sequence Numbers)<br><strong>ACK</strong>: (确认编号,Acknowledgement Number)<br><strong>FIN</strong>: (结束标志,FINish)</p></blockquote><p><img src="tcp-3.png" alt="三次握手"></p><ul><li><strong>第一次握手</strong>:Client 将标志位 SYN=1 ,随机产生一个值 seq=J ,并将该数据包发送给 Server 。此时,Client 进入SYN_SENT 状态,等待 Server 确认。</li><li><strong>第二次握手</strong>:Server 收到数据包后由标志位 SYN=1 知道Client请求建立连接,Server 将标志位 SYN 和 ACK 都置为 1 ,ack=J+1,随机产生一个值 seq=K ,并将该数据包发送给 Client 以确认连接请求,Server 进入 SYN_RCVD 状态。此时,Server 进入 SYC_RCVD 状态。</li><li><strong>第三次握手</strong>:Client 收到确认后,检查 ack 是否为 J+1 ,ACK 是否为 1 。<ul><li>如果正确,则将标志位 ACK 置为 1 ,ack=K+1 ,并将该数据包发送给 Server 。此时,Client 进入 ESTABLISHED 状态。</li><li>Server 检查 ack 是否为 K+1 ,ACK 是否为 1 ,如果正确则连接建立成功。此时 Server 进入 ESTABLISHED 状态,完成三次握手,随后 Client 与 Server 之间可以开始传输数据了。</li></ul></li></ul><blockquote><p>仔细看来,Client 会发起两次数据包,分别是 SYNC 和 ACK ;Server 会发起一次数据包,包含 SYNC 和 ACK 。也就是说,三次握手的过程中,Client 和 Server 互相做了一次 SYNC 和 ACK </p></blockquote><blockquote><p>为什么TCP连接需要三次握手,两次不可以么? 这主要是为了防止已失效的连接请求报文突然又传送到了服务端,因而产生错误。防止服务器端一直等待而浪费资源。</p></blockquote><blockquote><p>“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文段并没有丢失,而是在某个网络结点长时间的滞留了,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。但server却以为新的运输连接已经建立,并一直等待client发来数据。这样,server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况,client不会向server的确认发出确认。server由于收不到确认,就知道client并没有要求建立连接。”</p></blockquote><h2 id="关闭链接四次挥手"><a href="#关闭链接四次挥手" class="headerlink" title="关闭链接四次挥手"></a>关闭链接四次挥手</h2><p>四次挥手,简单来说,就是:</p><ul><li>发送方:我要和你断开连接!</li><li>接收方:好的,断吧。</li><li>接收方:我也要和你断开连接!</li><li>发送方:好的,断吧。</li></ul><p><img src="tcp-4.png" alt="四次挥手"></p><p><img src="tcp-4-2.png" alt="四次挥手"></p><ul><li><strong>第一次挥手</strong>: Client 发送一个 FIN=M ,用来关闭 Client 到 Server 的数据传送。此时,Client 进入 FIN_WAIT_1 状态。</li><li><strong>第二次挥手</strong>: Server 收到 FIN 后,发送一个 ACK 给 Client ,确认序号为 M+1(与 SYN 相同,一个 FIN 占用一个序号)。此时,Server 进入 CLOSE_WAIT 状态。注意,TCP 链接处于半关闭状态,即客户端已经没有要发送的数据了,但服务端若发送数据,则客户端仍要接收。</li><li><strong>第三次挥手</strong>: Server 发送一个 FIN=N ,用来关闭 Server 到 Client 的数据传送。此时 Server 进入 LAST_ACK 状态。</li><li><strong>第四次挥手</strong>: Client 收到 FIN 后,此时 Client 进入 TIME_WAIT 状态。接着,Client 发送一个 ACK 给 Server ,确认序号为 N+1 。Server 接收到后,此时 Server 进入 CLOSED 状态,完成四次挥手。</li></ul><h3 id="为什么要四次挥手"><a href="#为什么要四次挥手" class="headerlink" title="为什么要四次挥手"></a>为什么要四次挥手</h3><p>那四次分手又是为何呢?TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。如果要正确的理解四次分手的原理,就需要了解四次分手过程中的状态变化。</p><ul><li><strong>FIN_WAIT_1</strong>: 这个状态要好好解释一下,其实FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。而这两种状态的区别是:FIN_WAIT_1状态实际上是当SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用netstat看到。(主动方)</li><li><strong>FIN_WAIT_2</strong>:上面已经详细解释了这种状态,实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对方,我暂时还有点数据需要传送给你(ACK信息),稍后再关闭连接。(主动方)</li><li><strong>CLOSE_WAIT</strong>:这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close这个SOCKET,发送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。(被动方)</li><li><strong>LAST_ACK</strong>: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,也即可以进入到CLOSED可用状态了。(被动方)</li><li><strong>TIME_WAIT:</strong> 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果FINWAIT1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。(主动方)</li><li><strong>CLOSED</strong>: 表示连接中断。</li></ul><h3 id="2MSL-报文最大生存时间"><a href="#2MSL-报文最大生存时间" class="headerlink" title="2MSL - 报文最大生存时间"></a>2MSL - 报文最大生存时间</h3><p>2MSL即两倍的MSL,TCP的TIME_WAIT状态也称为2MSL等待状态,当TCP的一端发起主动关闭,在发出最后一个ACK包后,即第3次握手完成后发送了第四次握手的ACK包后就进入了TIME_WAIT状态,必须在此状态上停留两倍的MSL时间,等待2MSL时间主要目的是怕最后一个ACK包对方没收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。不过在实际应用中可以通过设置SO_REUSEADDR选项达到不必等待2MSL时间结束再使用此端口。</p><h2 id="报文状态标志于连接状态"><a href="#报文状态标志于连接状态" class="headerlink" title="报文状态标志于连接状态"></a>报文状态标志于连接状态</h2><ul><li><strong>CLOSED</strong>: 表示初始状态。</li><li><strong>LISTEN</strong>: 表示服务器端的某个SOCKET处于监听状态,可以接受连接。</li><li><strong>SYN_SENT</strong>:在服务端监听后,客户端SOCKET执行CONNECT连接时,客户端发送SYN报文,此时客户端就进入<br>SYN_SENT状态,等待服务端的确认</li><li><strong>SYN_RCVD</strong>: 表示服务端接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三<br>次握手会话过程中的一个中间状态,很短暂,基本上用netstat你是很难看到这种状态的,除非你特意写了一<br>个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。因此这种状态时,当收到客户端的<br>ACK报文后,它会进入到ESTABLISHED状态。</li><li><strong>ESTABLISHED</strong>: 表示连接已经建立了。</li><li><strong>FIN_WAIT_1</strong>: 这个是已经建立连接之后,其中一方请求终止连接,等待对方的FIN报文。FIN_WAIT_1状态是当<br>SOCKET在ESTABLISHED状态时,它想主动关闭连接,向对方发送了FIN报文,此时该SOCKET即进入到FIN_WAIT_1<br>状态。而当对方回应ACK报文后,则进入到FIN_WAIT_2状态,当然在实际的正常情况下,无论对方何种情况下<br>,都应该马上回应ACK报文,所以FIN_WAIT_1状态一般是比较难见到的,而FIN_WAIT_2状态还有时常常可以用<br>netstat看到。</li><li><strong>FIN_WAIT_2</strong>: 实际上FIN_WAIT_2状态下的SOCKET,表示半连接,也即有一方要求close连接,但另外还告诉对<br>方,我暂时还有点数据需要传送给你,稍后再关闭连接。</li><li><strong>TIME_WAIT</strong>: 表示收到了对方的FIN报文,并发送出了ACK报文,就等2MSL后即可回到CLOSED可用状态了。如果<br>FIN_WAIT_1状态下,收到了对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须<br>经过FIN_WAIT_2状态。</li><li><strong>CLOSING</strong>: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你<br>发送FIN报文后,按理来说是应该先收到(或同时收到)对方的ACK报文,再收到对方的FIN报文。但是CLOSING状<br>态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此<br>种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时close一个SOCKET的话,那么就出现<br>了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。</li><li><strong>CLOSE_WAIT</strong>: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方close一个SOCKET后发送FIN报文给<br>自己,你系统毫无疑问地会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,实际上你真<br>正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以close这个SOCKET,发<br>送FIN报文给对方,也即关闭连接。所以你在CLOSE_WAIT状态下,需要完成的事情是等待你去关闭连接。</li><li><strong>LAST_ACK</strong>: 这个状态还是比较容易好理解的,它是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。<br>当收到ACK报文后,也即可以进入到CLOSED可用状态了。</li></ul><h2 id="Nagel算法与ACK延迟"><a href="#Nagel算法与ACK延迟" class="headerlink" title="Nagel算法与ACK延迟"></a>Nagel算法与ACK延迟</h2><p><a href="https://www.cnblogs.com/wanpengcoder/p/5366156.html" target="_blank" rel="noopener">TCP之Nagle算法&&延迟ACK</a></p><h2 id="滑动窗口与流量控制"><a href="#滑动窗口与流量控制" class="headerlink" title="滑动窗口与流量控制"></a>滑动窗口与流量控制</h2><p>滑动窗口协议(Sliding Window Protocol),属于TCP协议的一种应用,用于网络数据传输时的流量控制,以避免拥塞的发生。该协议允许发送方在停止并等待确认前发送多个数据分组。由于发送方不必每发一个分组就停下来等待确认,因此该协议可以加速数据的传输,提高网络吞吐量。</p><p>TCP采用可变滑动窗口来实现流量控制。TCP连接的两端交互作用,互相提供数据流的相关信息,包括报文段序列号、ACK号和窗口大小(即接收端的可用空间)。发送端根据这些信息动态调节窗口大小来控制发送,以达到流量控制的目的。每个TCP头部的窗口大小字段表明接收端可用缓存空间的大小,以字节为单位。该字段长度为16位,但窗口缩放选项可用大于65535的值。报文段发送方在相反方向上可接受的最大序列号值为TCP头部中ACK号和窗口大小字段之和(单位保持一致)。</p><p><a href="https://blog.csdn.net/qq_37653144/article/details/82765098" target="_blank" rel="noopener">TCP滑动窗口与流量控制</a></p>]]></content>
<categories>
<category> 计算机网络 </category>
<category> TCP协议 </category>
</categories>
<tags>
<tag> 网络 </tag>
<tag> TCP </tag>
</tags>
</entry>
<entry>
<title>Linux常用命令</title>
<link href="/2019/linux-common-command/"/>
<url>/2019/linux-common-command/</url>
<content type="html"><![CDATA[<p>Linux常用命令对服务问题的排查和定位有很大帮助, 这里整理总结一下工作中常用的命令</p><h2 id="awk"><a href="#awk" class="headerlink" title="awk"></a>awk</h2><p>下面的例子主要来自于阮一峰的博客。<br>Awk是一种便于使用且表达能力强的程序设计语言,可应用于各种计算和数据处理任务。它依次处理文件的每一行,并读取里面的每一个字段。对于日志、CSV 那样的每行格式相同的文本文件,awk可能是最方便的工具。</p><h3 id="基本用法"><a href="#基本用法" class="headerlink" title="基本用法"></a>基本用法</h3><blockquote><p>awk 动作 文件名</p></blockquote><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk <span class="string">'{print $0}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">'this is a test'</span> | awk <span class="string">'{print $0}'</span></span><br></pre></td></tr></table></figure><p><code>this is a test</code></p><p>上面代码中,print $0就是把标准输入this is a test,重新打印了一遍。</p><p>awk会根据空格和制表符,将每一行分成若干字段,依次用$1、$2、$3代表第一个字段、第二个字段、第三个字段等等。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">'this is a test'</span> | awk <span class="string">'{print $4}'</span></span><br></pre></td></tr></table></figure><p><code>test</code></p><p>创建一个demo.txt文件,下面是文件内容:</p><figure class="highlight plain"><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">root:x:0:0:root:/root:/usr/bin/zsh</span><br><span class="line">daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin</span><br><span class="line">bin:x:2:2:bin:/bin:/usr/sbin/nologin</span><br><span class="line">sys:x:3:3:sys:/dev:/usr/sbin/nologin</span><br><span class="line">sync:x:4:65534:sync:/bin:/bin/sync</span><br></pre></td></tr></table></figure><p>这个文件的字段分隔符是冒号(:),所以要用-F参数指定分隔符为冒号。然后,才能提取到它的第一个字段。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{ print $1 }'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">root</span><br><span class="line">daemon</span><br><span class="line">bin</span><br><span class="line">sys</span><br><span class="line">sync</span><br></pre></td></tr></table></figure><h3 id="变量"><a href="#变量" class="headerlink" title="变量"></a>变量</h3><p>除了<code>$ +</code>数字表示某个字段,awk还提供其他一些变量。</p><p>变量<code>NF</code>表示当前行有多少个字段,因此<code>$NF</code>就代表最后一个字段。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="string">'this is a test'</span> | awk <span class="string">'{print $NF}'</span></span><br></pre></td></tr></table></figure><p><code>test</code></p><p><code>$(NF-1)</code>代表倒数第二个字段。print命令里面的逗号,表示输出的时候,两个部分之间使用空格分隔。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{print $1, $(NF-1)}'</span> demo.txt</span><br></pre></td></tr></table></figure><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">root /root</span><br><span class="line">daemon /usr/sbin</span><br><span class="line">bin /bin</span><br><span class="line">sys /dev</span><br><span class="line">sync /bin</span><br></pre></td></tr></table></figure><p>变量<code>NR</code>表示当前处理的是第几行, <code>print</code>命令里面,如果原样输出字符,要放在双引号里面。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{print NR ") " $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">1) root</span><br><span class="line">2) daemon</span><br><span class="line">3) bin</span><br><span class="line">4) sys</span><br><span class="line">5) sync</span><br></pre></td></tr></table></figure><p>awk常用内置变量如下:</p><ul><li>NF: 当前行有多少个字段</li><li>NR: 当前处理的是第几行</li><li>FILENAME: 当前文件名</li><li>FS: 字段分隔符,默认是空格和制表符。</li><li>RS: 行分隔符,用于分割每一行,默认是换行符。</li><li>OFS: 输出字段的分隔符,用于打印时分隔字段,默认为空格。</li><li>ORS: 输出记录的分隔符,用于打印时分隔记录,默认为换行符。</li><li>OFMT: 数字输出的格式,默认为%.6g</li></ul><h3 id="函数"><a href="#函数" class="headerlink" title="函数"></a>函数</h3><p>awk还提供了一些内置函数,方便对原始数据的处理。</p><p>函数<code>toupper()</code>用于将字符转为大写。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{ print toupper($1) }'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">ROOT</span><br><span class="line">DAEMON</span><br><span class="line">BIN</span><br><span class="line">SYS</span><br><span class="line">SYNC</span><br></pre></td></tr></table></figure><p>其他常用函数如下:</p><ul><li>toupper(): 字符转为大写。</li><li>tolower(): 字符转为小写。</li><li>length(): 返回字符串长度。</li><li>substr(): 返回子字符串。</li><li>sin(): 正弦。</li><li>cos(): 余弦。</li><li>sqrt(): 平方根。</li><li>rand(): 随机数。</li></ul><h3 id="条件"><a href="#条件" class="headerlink" title="条件"></a>条件</h3><p>awk允许指定输出条件,只输出符合条件的行。</p><blockquote><p>awk ‘条件 动作’ 文件名</p></blockquote><p>下面的代码print命令前面是一个正则表达式,只输出包含usr的行</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'/usr/ {print $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">root</span><br><span class="line">daemon</span><br><span class="line">bin</span><br><span class="line">sys</span><br></pre></td></tr></table></figure><p>下面的例子只输出奇数行,</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'NR % 2 == 1 {print $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">root</span><br><span class="line">bin</span><br><span class="line">sync</span><br></pre></td></tr></table></figure><p>下面的例子只输出第三行以后的行。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'NR >3 {print $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sys</span><br><span class="line">sync</span><br></pre></td></tr></table></figure><p>下面的例子输出第一个字段等于指定值的行。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'$1 == "root" || $1 == "bin" {print $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">root</span><br><span class="line">bin</span><br></pre></td></tr></table></figure><h3 id="if-语句"><a href="#if-语句" class="headerlink" title="if 语句"></a>if 语句</h3><p>awk提供了if结构,用于编写复杂的条件。</p><p>下面的代码输出第一个字段的第一个字符大于m的行。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{if ($1 > "m") print $1}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">root</span><br><span class="line">sys</span><br><span class="line">sync</span><br></pre></td></tr></table></figure><p>if结构还可以指定else部分。</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">awk -F <span class="string">':'</span> <span class="string">'{if ($1 > "m") print $1; else print "---"}'</span> demo.txt</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">root</span><br><span class="line">---</span><br><span class="line">---</span><br><span class="line">sys</span><br><span class="line">sync</span><br></pre></td></tr></table></figure><h2 id="top"><a href="#top" class="headerlink" title="top"></a>top</h2><p>top命令经常用来监控Linux的系统状况,比如cpu、内存的使用,程序员基本都知道这个命令,但比较奇怪的是能用好它的人却很少,例如top监控视图中内存数值的含义就有不少的曲解。</p><p>本文通过一个运行中的WEB服务器的top监控截图,讲述top视图中的各种数据的含义,还包括视图中各进程(任务)的字段的排序。</p><p><img src="top-pic1.png" alt="TOP"></p><h3 id="TOP基本视图数据含义"><a href="#TOP基本视图数据含义" class="headerlink" title="TOP基本视图数据含义"></a>TOP基本视图数据含义</h3><ul><li><p>第一行:</p><ul><li><strong>19:05:32</strong> : 当前系统时间</li><li><strong>42 days, 19:05:</strong> : 系统已经运行了42天19小时05分钟(在这期间没 重启过)</li><li><strong>2 users</strong> : 当前有2个用户登录系统</li><li><strong>load average: 0.23, 0.26. 0.27</strong> : load average后面的三个数 别是1分钟、5分钟、15分钟的负载情况</li></ul><blockquote><p>load average数据是每隔5秒钟检查一次活跃的进程数,然后按特定算法计算出的数值。如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了。</p></blockquote></li><li><p>第二行:进程</p><ul><li><strong>168 total</strong> : 系统现在共有168个进程</li><li><strong>2 running</strong> : 其中处于运行中的有2个</li><li><strong>166 sleeping</strong> : 166个在休眠</li><li><strong>0 stopped</strong> : stoped状态的有0个</li><li><strong>0 zombie</strong> : 僵尸状态的有0个</li></ul></li><li><p>第三行:cpu状态</p><ul><li><strong>12.5% us</strong> : 用户空间占用CPU的百分比。</li><li><strong>4.2% sy</strong> : 内核空间占用CPU的百分比。</li><li><strong>0.5% ni</strong> : 改变过优先级的进程占用CPU的百分比</li><li><strong>82.8% id</strong> : 空闲CPU百分比</li><li><strong>0.0% wa</strong> : IO等待占用CPU的百分比</li><li><strong>0.0% hi</strong> : 硬中断(Hardware IRQ)占用CPU的百分比</li><li><strong>0.0% si</strong> : 软中断(Software Interrupts)占用CPU的百分比</li></ul><blockquote><p>在这里CPU的使用比率和windows概念不同,如果你不理解用户空间和内核空间,需要了解一下。</p></blockquote></li></ul><ul><li><p>第四行:内存状态</p><ul><li><strong>5994240k total</strong> : 物理内存总量</li><li><strong>5751368k used</strong> : 使用中的内存总量</li><li><strong>242872k free</strong> : 空闲内存总量</li><li><strong>10476k buffers</strong> : 缓存的内存量</li></ul><blockquote><p>这里要说明的是不能用windows的内存概念理解这些数据,如果按windows的方式此台服务器“危矣”:8G的内存总量只剩下530M的可用内存。Linux的内存管理有其特殊性,复杂点需要一本书来说明,这里只是简单说点和我们传统概念(windows)的不同。</p></blockquote><blockquote><p>第四行中使用中的内存总量(used)指的是现在系统内核控制的内存数,空闲内存总量(free)是内核还未纳入其管控范围的数量。纳入内核管理的内存不见得都在使用中,还包括过去使用过的现在可以被重复利用的内存,内核并不把这些可被重新使用的内存交还到free中去,因此在linux上free内存会越来越少,但不用为此担心。</p></blockquote></li><li><p>第五行:swap交换分区</p><ul><li><strong>15999996k total</strong> : 交换区总量</li><li><strong>1520700k used</strong>: 使用的交换区总量</li><li><strong>14479296k free</strong>: 空闲交换区总量</li><li><strong>554840k cached</strong>: 缓冲的交换区总量</li></ul><blockquote><p>如果出于习惯去计算可用内存数,这里有个近似的计算公式:第四行的free + 第四行的buffers + 第五行的cached,按这个公式此台服务器的可用内存: 242872+10476+554840 = 808,188kb = 789MB。</p></blockquote><blockquote><p>对于内存监控,在top里我们要时刻监控第五行swap交换分区的used,如果这个数值在不断的变化,说明内核在不断进行内存和swap的数据交换,这是真正的内存不够用了。</p></blockquote></li><li><p>第六行:空行</p></li></ul><ul><li>第七行以下:各进程(任务)的状态监控<ul><li><strong>PID</strong> : 进程id</li><li><strong>USER</strong> : 进程所有者</li><li><strong>PR</strong> : 进程优先级</li><li><strong>NI</strong> : nice值。负值表示高优先级,正值表示低优先级</li><li><strong>VIRT</strong> : 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES</li><li><strong>RES</strong> : 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA</li><li><strong>SHR</strong> : 共享内存大小,单位kb</li><li><strong>S</strong> : 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程</li><li><strong>%CPU</strong> : 上次更新到现在的CPU时间占用百分比</li><li><strong>%MEM</strong> : 进程使用的物理内存百分比</li><li><strong>TIME+</strong> : 进程使用的CPU时间总计,单位1/100秒</li><li><strong>COMMAND</strong> : 进程名称(命令名/命令行)</li></ul></li></ul><h3 id="多核CPU监控"><a href="#多核CPU监控" class="headerlink" title="多核CPU监控"></a>多核CPU监控</h3><p>在top基本视图中,按键盘数字<code>1</code>,可监控每个逻辑CPU的状况</p><h3 id="top列排序"><a href="#top列排序" class="headerlink" title="top列排序"></a>top列排序</h3><p>top默认的排序列是 <strong>%CPU</strong>, 通过<code>shift + ></code>或<code>shift + <</code>可以向右或左改变排序列</p><h3 id="设置信息更新时间"><a href="#设置信息更新时间" class="headerlink" title="设置信息更新时间"></a>设置信息更新时间</h3><p><code>top -d 3</code><br>表示更新周期为3秒</p><h3 id="显示指定的进程信息"><a href="#显示指定的进程信息" class="headerlink" title="显示指定的进程信息"></a>显示指定的进程信息</h3><p><code>top -p 139</code><br>显示进程号为139的进程信息,CPU、内存占用率等</p><h3 id="显示更新指定次后退出"><a href="#显示更新指定次后退出" class="headerlink" title="显示更新指定次后退出"></a>显示更新指定次后退出</h3><p><code>top -n 10</code><br>更新十次后退出</p><h2 id="grep"><a href="#grep" class="headerlink" title="grep"></a>grep</h2><p>grep 命令用于查找文件里符合条件的字符串。工作中我常用来过滤日志中的一些关键信息.</p><p>过滤出所有日志中的异常信息行, 取结果前20条开看看, <code>-B1</code>指取匹配到的前一行, <code>-i</code>忽略大小写</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -i <span class="string">"Exception"</span> mcserver.log.* -B1 | head -n 20</span><br></pre></td></tr></table></figure><p>下面这个<code>-c</code>可以统计每个文件里面匹配到的个数, 列出所有文件, 可以用来缩小文件范围</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -i <span class="string">"Exception"</span> mcserver.log.* -c</span><br></pre></td></tr></table></figure><p><code>-v</code>表示显示不包含匹配文本的所有行, <code>{1..3}</code>表示取1到3</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">grep -v <span class="string">"Exception"</span> mcserver.log.{1..3} -c</span><br></pre></td></tr></table></figure><figure class="highlight plain"><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">mcserver.log.1:102398</span><br><span class="line">mcserver.log.2:105916</span><br><span class="line">mcserver.log.3:101884</span><br></pre></td></tr></table></figure><h2 id="sed"><a href="#sed" class="headerlink" title="sed"></a>sed</h2><p>sed 命令是利用脚本来处理文本文件。sed 可依照脚本的指令来处理、编辑文本文件。主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。</p><p>下面是test.txt的内容</p><figure class="highlight plain"><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">root:x:0:0:root:/root:/bin/bash</span><br><span class="line">daemon:x:1:1:daemon:/usr/sbin:/bin/sh</span><br><span class="line">bin:x:2:2:bin:/bin:/bin/sh</span><br><span class="line">sys:x:3:3:sys:/dev:/bin/sh</span><br><span class="line">sync:x:4:65534:sync:/bin:/bin/sync</span><br></pre></td></tr></table></figure><p>以行为单位的新增/删除,将文件的2-3行删除</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">'2,3d'</span> test.txt</span><br></pre></td></tr></table></figure><p>数据的搜寻并替换,将root替换为admin</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">'s/root/admin/g'</span> test.txt</span><br></pre></td></tr></table></figure><p>在第二行添加<code>"ignore_vc_cert"=false</code></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">'2a "ignore_vc_cert"=false'</span> test.txt</span><br></pre></td></tr></table></figure><p>匹配到包含<code>"ignore_vc_cert"</code>的那一行,然后将false替换为true</p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sed -i <span class="string">'/"ignore_vc_cert"/ s/false/true/'</span> test.txt</span><br></pre></td></tr></table></figure><hr><p>以后再更新,目前工作中常用的就这些</p>]]></content>
<categories>
<category> 操作系统 </category>
<category> Linux常用命令 </category>
</categories>
<tags>
<tag> 操作系统 </tag>
<tag> Linux </tag>
</tags>
</entry>
<entry>
<title>Markdown基本语法</title>
<link href="/2019/markdown-basic-syntax/"/>
<url>/2019/markdown-basic-syntax/</url>
<content type="html"><)</span><br></pre></td></tr></table></figure><p>图片title(图片title)可以省略</p><p><img src="pic.jpg" alt="图片名称" title="图片title"></p><h2 id="超链接"><a href="#超链接" class="headerlink" title="超链接"></a>超链接</h2><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[<span class="string">哔哩哔哩</span>](<span class="link">https://www.bilibili.com/ (我是B站忠实用户</span>))</span><br></pre></td></tr></table></figure><blockquote><p>链接title(链接title)可以省略</p></blockquote><p><a href="https://www.bilibili.com/" title="我是B站忠实用户" target="_blank" rel="noopener">哔哩哔哩</a></p><h2 id="列表"><a href="#列表" class="headerlink" title="列表"></a>列表</h2><h3 id="无序列表"><a href="#无序列表" class="headerlink" title="无序列表"></a>无序列表</h3><p>- 列表内容<br>+ 列表内容<br>* 列表内容</p><blockquote><p>注意:- + * 跟内容之间都要有一个空格</p></blockquote><ul><li>列表内容</li><li>列表内容</li><li>列表内容</li></ul><figure class="highlight md"><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="bullet">- </span>列表内容</span><br><span class="line"><span class="bullet">- </span>列表内容</span><br><span class="line"><span class="bullet">- </span>列表内容</span><br></pre></td></tr></table></figure><h3 id="有序列表"><a href="#有序列表" class="headerlink" title="有序列表"></a>有序列表</h3><ol><li>列表内容</li><li>列表内容</li><li>列表内容</li></ol><figure class="highlight md"><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="bullet">1. </span>列表内容</span><br><span class="line"><span class="bullet">2. </span>列表内容</span><br><span class="line"><span class="bullet">3. </span>列表内容</span><br></pre></td></tr></table></figure><blockquote><p>注意:数字后面有个.和空格</p></blockquote><h3 id="列表嵌套"><a href="#列表嵌套" class="headerlink" title="列表嵌套"></a>列表嵌套</h3><p>上一级和下一级之间敲三个空格即可</p><h2 id="表格"><a href="#表格" class="headerlink" title="表格"></a>表格</h2><table><thead><tr><th>表头</th><th align="center">表头</th><th align="right">表头</th></tr></thead><tbody><tr><td>内容</td><td align="center">内容</td><td align="right">内容</td></tr><tr><td>内容</td><td align="center">内容</td><td align="right">内容</td></tr></tbody></table><figure class="highlight md"><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">表头|表头|表头</span><br><span class="line">---|:--:|---:</span><br><span class="line">内容|内容|内容</span><br><span class="line">内容|内容|内容</span><br></pre></td></tr></table></figure><blockquote><p>第二行分割表头和内容。<br>有一个就行,为了对齐,多加了几个<br>文字默认居左<br>两边加<code>:</code>表示文字居中<br>右边加<code>:</code>表示文字居右<br>注:原生的语法两边都要用 | 包起来。此处省略</p></blockquote><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>语法:<br>单行代码:代码之间分别用一个反引号包起来</p><figure class="highlight md"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="code">`单行代码`</span></span><br></pre></td></tr></table></figure><p>多行用三个```</p><p>😄</p><p>##常用Emoji</p><table><thead><tr><th>表情</th><th align="center">表情</th><th align="right">表情</th></tr></thead><tbody><tr><td>❤</td><td align="center">📒</td><td align="right">📖</td></tr><tr><td>💬</td><td align="center">📃</td><td align="right">📕📘</td></tr><tr><td>🕓</td><td align="center">✏</td><td align="right">😁</td></tr><tr><td>⌛</td><td align="center">😅</td><td align="right">😈</td></tr><tr><td>✔</td><td align="center">😉</td><td align="right">🤔</td></tr><tr><td>❌</td><td align="center">👉</td><td align="right">👇</td></tr><tr><td>✖</td><td align="center">🚩</td><td align="right">🏴</td></tr><tr><td>❓</td><td align="center">❔</td><td align="right">❕</td></tr><tr><td>❗</td><td align="center">👌</td><td align="right">😛</td></tr></tbody></table>]]></content>
<tags>
<tag> Markdown </tag>
</tags>
</entry>
<entry>
<title>Java基础</title>
<link href="/2019/java-basic/"/>
<url>/2019/java-basic/</url>
<content type="html"><![CDATA[<p>这个算是我的第一篇博客吧,我先从Java开始</p><h2 id="面向对象概念"><a href="#面向对象概念" class="headerlink" title="面向对象概念"></a>面向对象概念</h2><p>面向对象是一种思想,世间万物都可以看做一个对象,这里只讨论面向对象编程(OOP),Java 是一个支持并发、基于类和面向对象的计算机编程语言。面向对象软件开发具有以下优点:</p><ul><li>代码开发模块化,更易维护和修改。</li><li>代码复用性强。</li><li>增强代码的可靠性和灵活性。</li><li>增加代码的可读性。</li></ul><h2 id="面向对象的特征"><a href="#面向对象的特征" class="headerlink" title="面向对象的特征"></a>面向对象的特征</h2><p><strong>封装、继承、多态、抽象</strong></p><ol><li><p>封装,给对象提供了隐藏内部特性和行为的能力。对象提供一些能被其他对象访问的方法来改变它内部的数据。在 Java 当中,有 4 种修饰符: default、public、private 和 protected 。每一种修饰符给其他的位于同一个包或者不同包下面对象赋予了不同的访问权限。<br>下面列出了使用封装的一些好处:</p><ul><li>通过隐藏对象的属性来保护对象内部的状态。</li><li>提高了代码的可用性和可维护性,因为对象的行为可以被单独的改变或者是扩展。</li><li>禁止对象之间的不良交互提高模块化。</li></ul></li><li><p>继承,给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用行,也可以在不修改类的情况下给现存的类添加新特性。</p></li><li><p>多态,是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作,可以应用到其他类型的值上面。</p></li><li><p>抽象,是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。<br>Java 支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的是把类的行为和实现细节分离开。</p></li></ol><h2 id="接口与抽象类的区别?"><a href="#接口与抽象类的区别?" class="headerlink" title="接口与抽象类的区别?"></a>接口与抽象类的区别?</h2><p>首先要搞懂什么是抽象类,什么是接口</p><h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><ul><li>接口不能被实例化</li><li>接口只能包含方法声明</li><li>接口的成员包括方法、属性、索引器、事件</li><li>接口中不能包含常量、字段(域)、构造函数、析构函数、静态成员</li></ul><h3 id="抽象类"><a href="#抽象类" class="headerlink" title="抽象类"></a>抽象类</h3><p>抽象类不能创建实例,它只能作为父类被继承。抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为其子类的模板,从而避免了子类的随意性。</p><ul><li>抽象方法只作声明,而不包含实现,可以看成是没有实现体的虚方法</li><li>抽象类不能被实例化</li><li>抽象类可以但不是必须有抽象属性和抽象方法,但是一旦有了抽象方法,就一定要把这个类声明为抽象类</li><li>具体派生类必须覆盖基类的抽象方法</li><li>抽象派生类可以覆盖基类的抽象方法,也可以不覆盖。如果不覆盖,则其具体派生类必须覆盖它们</li></ul><h3 id="接口与抽象类的区别"><a href="#接口与抽象类的区别" class="headerlink" title="接口与抽象类的区别"></a>接口与抽象类的区别</h3><ul><li>抽象类可以有构造方法,接口中不能有构造方法。</li><li>抽象类中可以有普通成员变量,接口中没有普通成员变量</li><li>抽象类中可以包含静态方法,接口中不能包含静态方法</li><li>一个类可以实现多个接口,但只能继承一个抽象类。</li><li>接口可以被多重实现,抽象类只能被单一继承</li><li>如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法</li></ul><h3 id="接口和抽象类的相同点"><a href="#接口和抽象类的相同点" class="headerlink" title="接口和抽象类的相同点"></a>接口和抽象类的相同点</h3><ul><li>都可以被继承</li><li>都不能被实例化</li><li>都可以包含方法声明</li><li>派生类必须实现未实现的方法</li></ul><h2 id="Java-IO"><a href="#Java-IO" class="headerlink" title="Java IO"></a>Java IO</h2><p><img src="javaIO.jpg" alt="java IO"></p><h2 id="Java-序列化"><a href="#Java-序列化" class="headerlink" title="Java 序列化"></a>Java 序列化</h2><p>序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。</p><ul><li>可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。</li><li>序列化是为了解决在对对象流进行读写操作时所引发的问题。<br>反序列化的过程,则是和序列化相反的过程。</li></ul><blockquote><p>对于不想进行序列化的变量,使用 transient 关键字修饰。</p><ul><li>当对象被序列化时,阻止实例中那些用此关键字修饰的的变量序列化。</li><li>当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。</li><li>transient 只能修饰变量,不能修饰类和方法。</li></ul></blockquote><h2 id="对象克隆"><a href="#对象克隆" class="headerlink" title="对象克隆"></a>对象克隆</h2><p>一般来说,有两种方式:</p><ol><li>实现 Cloneable 接口,并重写 Object 类中的 #clone() 方法。可以实现浅克隆,也可以实现深克隆。</li><li>实现 Serializable 接口,通过对象的序列化和反序列化实现克隆。可以实现真正的深克隆。</li></ol><h2 id="Java中的异常类有哪几类-分别怎么使用"><a href="#Java中的异常类有哪几类-分别怎么使用" class="headerlink" title="Java中的异常类有哪几类?分别怎么使用?"></a>Java中的异常类有哪几类?分别怎么使用?</h2><p>说到异常的分类先从Throwable类说起,Throwable类是Java异常类型的顶层父类,一个对象只有是 Throwable 类的(直接或者间接)实例,他才是一个异常对象,才能被异常处理机制识别。JDK中内建了一些常用的异常类,我们也可以自定义异常。</p><p>Exception分为CheckedException和RuntimeException,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException。</p><p>Error是程序无法处理的, 如果OutOfMemoryError、OutOfMemoryError等等, 这些异常发生时, java虚拟机一般会终止线程。<br>运行时异常都是RuntimeException类及其子类,如 NullPointerException、IndexOutOfBoundsException等, 这些异常是不检查的异常, 是在程序运行的时候可能会发生的, 所以程序可以捕捉, 也可以不捕捉。这些错误一般是由程序的逻辑错误引起的, 程序应该从逻辑角度去尽量避免。<br>检查异常是运行时异常以外的异常, 也是Exception及其子类, 这些异常从程序的角度来说是必须经过捕捉检查处理的, 否则不能通过编译. 如IOException、SQLException等。</p><p><img src="exception.png" alt="Java异常的分类和类结构图"></p><h3 id="编译时异常"><a href="#编译时异常" class="headerlink" title="编译时异常"></a>编译时异常</h3><p>常见的编译时异常有:</p><ul><li>IOException</li><li>SQLException</li><li>CloneNotSupportedException</li><li>ParseException</li><li>ClassNotFoundException</li><li>NoSuchMetodException</li></ul><h3 id="运行时异常"><a href="#运行时异常" class="headerlink" title="运行时异常"></a>运行时异常</h3><p>常见的运行时异常有:</p><ul><li>NullPointerException: 空指针异常,一般出现于数组,空对-象的变量和方法</li><li>ArrayIndexOutOfBoundsException: 数组越界异常</li><li>ArrayStoreException: 数据存储异常</li><li>NoClassDefFoundException: java运行时系统找不到所引用的类</li><li>ArithmeticException: 算数异常,一般在被除数是0中</li><li>ClassCastException: 类型转换异常</li><li>IllegalArgumentException: 非法参数异常</li><li>IllegalThreadStateException: 非法线程状态异常</li><li>NumberFormatException: 数据格式异常</li><li>OutOfMemoryException: 内存溢出异常</li><li>PatternSyntaxException: 正则异常</li><li>ConcurrentModificationException: 并发修改异常</li></ul><h3 id="自定义异常"><a href="#自定义异常" class="headerlink" title="自定义异常"></a>自定义异常</h3><p>创建一个类继承RuntimeException,这样就能创建一个运行时异常</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">TooMuchMoneyException</span> <span class="keyword">extends</span> <span class="title">RuntimeException</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String errorMsg;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">TooMuchMoneyException</span> <span class="params">(String errorMsg)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(errorMsg);</span><br><span class="line"> <span class="keyword">this</span>.errorMsg = errorMsg;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="异常的使用的注意地方"><a href="#异常的使用的注意地方" class="headerlink" title="异常的使用的注意地方"></a>异常的使用的注意地方</h3><ul><li>不要将异常处理用于正常的控制流(设计良好的 API 不应该强迫它的调用者为了正常的控制流而使用异常)。</li><li>对可以恢复的情况使用受检异常,对编程错误使用运行时异常。</li><li>避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)。</li><li>优先使用标准的异常。</li><li>每个方法抛出的异常都要有文档。</li><li>保持异常的原子性</li><li>不要在 catch 中忽略掉捕获到的异常。</li></ul><p>如果要创建一个检查性异常,就继承Exception</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">NotSuchMoneyFoundException</span> <span class="keyword">extends</span> <span class="title">Exception</span></span>{</span><br><span class="line"> <span class="keyword">private</span> String errorMsg;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">NotSuchMoneyFoundException</span><span class="params">(String errorMsg)</span></span>{</span><br><span class="line"> <span class="keyword">super</span>(errorMsg);</span><br><span class="line"> <span class="keyword">this</span>.errorMsg = errorMsg;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h2 id="反射的用途及实现"><a href="#反射的用途及实现" class="headerlink" title="反射的用途及实现"></a>反射的用途及实现</h2><p>Java 反射机制主要提供了以下功能:</p><ul><li>在运行时构造一个类的对象。</li><li>判断一个类所具有的成员变量和方法。</li><li>调用一个对象的方法。</li><li>生成动态代理。</li></ul><p>反射的应用很多,很多框架都有用到:</p><ul><li>Spring 框架的 IoC 基于反射创建对象和设置依赖属性。</li><li>Spring MVC 的请求调用对应方法,也是通过反射。</li><li>JDBC 的 Class#forName(String className) 方法,也是使用反射。</li></ul><h2 id="Class-forName-和-ClassLoader-的区别"><a href="#Class-forName-和-ClassLoader-的区别" class="headerlink" title="Class.forName 和 ClassLoader 的区别"></a>Class.forName 和 ClassLoader 的区别</h2><p>这两者,都可用来对类进行加载。差别在于:</p><ul><li>Class.forName(…) 方法,除了将类的 .class 文件加载到JVM 中之外,还会对类进行解释,执行类中的 static 块。</li><li>ClassLoader 只干一件事情,就是将 .class 文件加载到 JVM 中,不会执行 static 中的内容,只有在 newInstance 才会去执行 static 块。</li></ul><blockquote><p>Class#forName(name, initialize, loader) 方法,带参函数也可控制是否加载 static 块,并且只有调用了newInstance 方法采用调用构造函数,创建类的对象。</p></blockquote><h2 id="Java-对象创建的方式"><a href="#Java-对象创建的方式" class="headerlink" title="Java 对象创建的方式"></a>Java 对象创建的方式</h2><ol><li>使用 new 关键字创建对象。</li><li>使用 Class 类的 newInstance 方法(反射机制)。</li><li>使用 Constructor 类的 newInstance 方法(反射机制)。</li><li>使用 clone 方法创建对象。</li><li>使用(反)序列化机制创建对象。</li></ol>]]></content>
<categories>
<category> Java </category>
<category> 基础 </category>
</categories>
<tags>
<tag> Java </tag>
</tags>
</entry>
<entry>
<title>Java 面试题</title>
<link href="/2019/JAVA-interview/"/>
<url>/2019/JAVA-interview/</url>
<content type="html"><![CDATA[<blockquote><h2 id="📚Java-基础"><a href="#📚Java-基础" class="headerlink" title="📚Java 基础"></a>📚Java 基础</h2></blockquote><h3 id="📃面向对象三大特征"><a href="#📃面向对象三大特征" class="headerlink" title="📃面向对象三大特征"></a>📃面向对象三大特征</h3><h3 id="📃重载和重写的区别"><a href="#📃重载和重写的区别" class="headerlink" title="📃重载和重写的区别"></a>📃重载和重写的区别</h3><h3 id="📃String,StringBuffer,StringBuilder的区别"><a href="#📃String,StringBuffer,StringBuilder的区别" class="headerlink" title="📃String,StringBuffer,StringBuilder的区别"></a>📃String,StringBuffer,StringBuilder的区别</h3><h3 id="📃final,finally,finalize的区别"><a href="#📃final,finally,finalize的区别" class="headerlink" title="📃final,finally,finalize的区别"></a>📃final,finally,finalize的区别</h3><h3 id="📃-和equals的区别"><a href="#📃-和equals的区别" class="headerlink" title="📃==和equals的区别"></a>📃==和equals的区别</h3><h3 id="📃接口和抽象类的区别"><a href="#📃接口和抽象类的区别" class="headerlink" title="📃接口和抽象类的区别"></a>📃接口和抽象类的区别</h3><h3 id="📃什么是强引用-、软引用、-弱引用、虚引用"><a href="#📃什么是强引用-、软引用、-弱引用、虚引用" class="headerlink" title="📃什么是强引用 、软引用、 弱引用、虚引用"></a>📃什么是强引用 、软引用、 弱引用、虚引用</h3><h3 id="📃字符型常量和字符串常量的区别"><a href="#📃字符型常量和字符串常量的区别" class="headerlink" title="📃字符型常量和字符串常量的区别"></a>📃字符型常量和字符串常量的区别</h3><h3 id="📃wait和sleep的区别"><a href="#📃wait和sleep的区别" class="headerlink" title="📃wait和sleep的区别"></a>📃wait和sleep的区别</h3><h3 id="📃异常分类以及处理机制"><a href="#📃异常分类以及处理机制" class="headerlink" title="📃异常分类以及处理机制"></a>📃异常分类以及处理机制</h3><h3 id="📃自动装箱与拆箱"><a href="#📃自动装箱与拆箱" class="headerlink" title="📃自动装箱与拆箱"></a>📃自动装箱与拆箱</h3><h3 id="📃成员变量与局部变量的区别有哪些?"><a href="#📃成员变量与局部变量的区别有哪些?" class="headerlink" title="📃成员变量与局部变量的区别有哪些?"></a>📃成员变量与局部变量的区别有哪些?</h3><h3 id="📃构造方法有哪些特性?"><a href="#📃构造方法有哪些特性?" class="headerlink" title="📃构造方法有哪些特性?"></a>📃构造方法有哪些特性?</h3><h3 id="📃介绍hashCode-与-equals方法"><a href="#📃介绍hashCode-与-equals方法" class="headerlink" title="📃介绍hashCode 与 equals方法"></a>📃介绍hashCode 与 equals方法</h3><h3 id="📃为什么Java中只有值传递"><a href="#📃为什么Java中只有值传递" class="headerlink" title="📃为什么Java中只有值传递"></a>📃为什么Java中只有值传递</h3><h3 id="📃Java序列化中如何让某些字段不进行序列化"><a href="#📃Java序列化中如何让某些字段不进行序列化" class="headerlink" title="📃Java序列化中如何让某些字段不进行序列化"></a>📃Java序列化中如何让某些字段不进行序列化</h3><h3 id="📃既然有了字节流-为什么还要有字符流"><a href="#📃既然有了字节流-为什么还要有字符流" class="headerlink" title="📃既然有了字节流,为什么还要有字符流"></a>📃既然有了字节流,为什么还要有字符流</h3><h3 id="📃BIO-NIO-AIO-的区别"><a href="#📃BIO-NIO-AIO-的区别" class="headerlink" title="📃BIO,NIO,AIO 的区别"></a>📃BIO,NIO,AIO 的区别</h3><h3 id="📃深拷贝和浅拷贝"><a href="#📃深拷贝和浅拷贝" class="headerlink" title="📃深拷贝和浅拷贝"></a>📃深拷贝和浅拷贝</h3><h3 id="📃cloneable接口实现原理"><a href="#📃cloneable接口实现原理" class="headerlink" title="📃cloneable接口实现原理"></a>📃cloneable接口实现原理</h3><h3 id="📃Java反射"><a href="#📃Java反射" class="headerlink" title="📃Java反射"></a>📃Java反射</h3><hr><blockquote><h2 id="📚Java-集合"><a href="#📚Java-集合" class="headerlink" title="📚Java 集合"></a>📚Java 集合</h2></blockquote><h3 id="📃数组在内存中如何分配"><a href="#📃数组在内存中如何分配" class="headerlink" title="📃数组在内存中如何分配"></a>📃数组在内存中如何分配</h3><h3 id="📃Arrays-sort-实现原理和-Collection-实现原理"><a href="#📃Arrays-sort-实现原理和-Collection-实现原理" class="headerlink" title="📃Arrays.sort 实现原理和 Collection 实现原理"></a>📃Arrays.sort 实现原理和 Collection 实现原理</h3><h3 id="📃List-和-Set-的区别"><a href="#📃List-和-Set-的区别" class="headerlink" title="📃List 和 Set 的区别"></a>📃List 和 Set 的区别</h3><h3 id="📃ArrayList-与-Vector-区别"><a href="#📃ArrayList-与-Vector-区别" class="headerlink" title="📃ArrayList 与 Vector 区别"></a>📃ArrayList 与 Vector 区别</h3><h3 id="📃ArrayList-的扩容机制"><a href="#📃ArrayList-的扩容机制" class="headerlink" title="📃ArrayList 的扩容机制"></a>📃ArrayList 的扩容机制</h3><h3 id="📃HashMap-和-Hashtable-的区别"><a href="#📃HashMap-和-Hashtable-的区别" class="headerlink" title="📃HashMap 和 Hashtable 的区别"></a>📃HashMap 和 Hashtable 的区别</h3><h3 id="📃HashMap的底层实现"><a href="#📃HashMap的底层实现" class="headerlink" title="📃HashMap的底层实现"></a>📃HashMap的底层实现</h3><h3 id="📃HashMap-是线程安全的吗,为什么不是线程安全的"><a href="#📃HashMap-是线程安全的吗,为什么不是线程安全的" class="headerlink" title="📃HashMap 是线程安全的吗,为什么不是线程安全的"></a>📃HashMap 是线程安全的吗,为什么不是线程安全的</h3><h3 id="📃JDK1-8中-HashMap-的扩容过程"><a href="#📃JDK1-8中-HashMap-的扩容过程" class="headerlink" title="📃JDK1.8中 HashMap 的扩容过程"></a>📃JDK1.8中 HashMap 的扩容过程</h3><h3 id="📃JDK1-8中-HashMap-做了哪些优化"><a href="#📃JDK1-8中-HashMap-做了哪些优化" class="headerlink" title="📃JDK1.8中 HashMap 做了哪些优化"></a>📃JDK1.8中 HashMap 做了哪些优化</h3><h3 id="📃HashMap-的长度为什么是2的幂次方"><a href="#📃HashMap-的长度为什么是2的幂次方" class="headerlink" title="📃HashMap 的长度为什么是2的幂次方"></a>📃HashMap 的长度为什么是2的幂次方</h3><h3 id="📃HashMap-多线程操作导致死循环问题"><a href="#📃HashMap-多线程操作导致死循环问题" class="headerlink" title="📃HashMap 多线程操作导致死循环问题"></a>📃HashMap 多线程操作导致死循环问题</h3><h3 id="📃HashSet-是如何保证不重复的"><a href="#📃HashSet-是如何保证不重复的" class="headerlink" title="📃HashSet 是如何保证不重复的"></a>📃HashSet 是如何保证不重复的</h3><h3 id="📃HashSet-和-HashMap-区别"><a href="#📃HashSet-和-HashMap-区别" class="headerlink" title="📃HashSet 和 HashMap 区别"></a>📃HashSet 和 HashMap 区别</h3><h3 id="📃ConcurrentHashMap-和-Hashtable-的区别"><a href="#📃ConcurrentHashMap-和-Hashtable-的区别" class="headerlink" title="📃ConcurrentHashMap 和 Hashtable 的区别"></a>📃ConcurrentHashMap 和 Hashtable 的区别</h3><h3 id="📃ConcurrentHashMap线程安全的具体实现方式"><a href="#📃ConcurrentHashMap线程安全的具体实现方式" class="headerlink" title="📃ConcurrentHashMap线程安全的具体实现方式"></a>📃ConcurrentHashMap线程安全的具体实现方式</h3><h3 id="📃LinkedHashMap的应用"><a href="#📃LinkedHashMap的应用" class="headerlink" title="📃LinkedHashMap的应用"></a>📃LinkedHashMap的应用</h3><h3 id="📃TreeMap的数据结构"><a href="#📃TreeMap的数据结构" class="headerlink" title="📃TreeMap的数据结构"></a>📃TreeMap的数据结构</h3><h3 id="📃comparable-和-Comparator的区别"><a href="#📃comparable-和-Comparator的区别" class="headerlink" title="📃comparable 和 Comparator的区别"></a>📃comparable 和 Comparator的区别</h3><hr><blockquote><h2 id="📚Java-并发"><a href="#📚Java-并发" class="headerlink" title="📚Java 并发"></a>📚Java 并发</h2></blockquote><h3 id="📃简述线程和进程的关系,区别和优缺点"><a href="#📃简述线程和进程的关系,区别和优缺点" class="headerlink" title="📃简述线程和进程的关系,区别和优缺点"></a>📃简述线程和进程的关系,区别和优缺点</h3><h3 id="📃为什么程序计数器、虚拟机栈和本地方法栈是线程私有的"><a href="#📃为什么程序计数器、虚拟机栈和本地方法栈是线程私有的" class="headerlink" title="📃为什么程序计数器、虚拟机栈和本地方法栈是线程私有的"></a>📃为什么程序计数器、虚拟机栈和本地方法栈是线程私有的</h3><h3 id="📃为什么虚拟机栈和本地方法栈是私有"><a href="#📃为什么虚拟机栈和本地方法栈是私有" class="headerlink" title="📃为什么虚拟机栈和本地方法栈是私有"></a>📃为什么虚拟机栈和本地方法栈是私有</h3><h3 id="📃解释堆和方法区"><a href="#📃解释堆和方法区" class="headerlink" title="📃解释堆和方法区"></a>📃解释堆和方法区</h3><h3 id="📃并发与并行的区别"><a href="#📃并发与并行的区别" class="headerlink" title="📃并发与并行的区别"></a>📃并发与并行的区别</h3><h3 id="📃为什么要使用多线程"><a href="#📃为什么要使用多线程" class="headerlink" title="📃为什么要使用多线程"></a>📃为什么要使用多线程</h3><h3 id="📃线程的生命周期和状态"><a href="#📃线程的生命周期和状态" class="headerlink" title="📃线程的生命周期和状态"></a>📃线程的生命周期和状态</h3><h3 id="📃什么是上下文切换"><a href="#📃什么是上下文切换" class="headerlink" title="📃什么是上下文切换"></a>📃什么是上下文切换</h3><h3 id="📃什么是线程死锁"><a href="#📃什么是线程死锁" class="headerlink" title="📃什么是线程死锁"></a>📃什么是线程死锁</h3><h3 id="📃如何避免死锁"><a href="#📃如何避免死锁" class="headerlink" title="📃如何避免死锁"></a>📃如何避免死锁</h3><h3 id="📃synchronized-关键字的了解"><a href="#📃synchronized-关键字的了解" class="headerlink" title="📃synchronized 关键字的了解"></a>📃synchronized 关键字的了解</h3><h3 id="📃synchronized-的底层原理"><a href="#📃synchronized-的底层原理" class="headerlink" title="📃synchronized 的底层原理"></a>📃synchronized 的底层原理</h3><h3 id="📃JDK1-6-之后的synchronized-关键字的底层优化"><a href="#📃JDK1-6-之后的synchronized-关键字的底层优化" class="headerlink" title="📃JDK1.6 之后的synchronized 关键字的底层优化"></a>📃JDK1.6 之后的synchronized 关键字的底层优化</h3><h3 id="📃synchronized和ReentrantLock-的区别"><a href="#📃synchronized和ReentrantLock-的区别" class="headerlink" title="📃synchronized和ReentrantLock 的区别"></a>📃synchronized和ReentrantLock 的区别</h3><h3 id="📃介绍Java内存模型"><a href="#📃介绍Java内存模型" class="headerlink" title="📃介绍Java内存模型"></a>📃介绍Java内存模型</h3><h3 id="📃volatile-的实现原理"><a href="#📃volatile-的实现原理" class="headerlink" title="📃volatile 的实现原理"></a>📃volatile 的实现原理</h3><h3 id="📃synchronized-关键字和-volatile-关键字的区别"><a href="#📃synchronized-关键字和-volatile-关键字的区别" class="headerlink" title="📃synchronized 关键字和 volatile 关键字的区别"></a>📃synchronized 关键字和 volatile 关键字的区别</h3><h3 id="📃ThreadLocal原理,用的时候需要注意什么"><a href="#📃ThreadLocal原理,用的时候需要注意什么" class="headerlink" title="📃ThreadLocal原理,用的时候需要注意什么"></a>📃ThreadLocal原理,用的时候需要注意什么</h3><h3 id="📃ThreadLocal的内存泄露问题"><a href="#📃ThreadLocal的内存泄露问题" class="headerlink" title="📃ThreadLocal的内存泄露问题"></a>📃ThreadLocal的内存泄露问题</h3><h3 id="📃为什么要用线程池"><a href="#📃为什么要用线程池" class="headerlink" title="📃为什么要用线程池"></a>📃为什么要用线程池</h3><h3 id="📃线程池原理分析"><a href="#📃线程池原理分析" class="headerlink" title="📃线程池原理分析"></a>📃线程池原理分析</h3><h3 id="📃实现Runnable接口和Callable接口的区别"><a href="#📃实现Runnable接口和Callable接口的区别" class="headerlink" title="📃实现Runnable接口和Callable接口的区别"></a>📃实现Runnable接口和Callable接口的区别</h3><h3 id="📃执行execute-方法和submit-方法的区别"><a href="#📃执行execute-方法和submit-方法的区别" class="headerlink" title="📃执行execute()方法和submit()方法的区别"></a>📃执行execute()方法和submit()方法的区别</h3><h3 id="📃如何创建线程池"><a href="#📃如何创建线程池" class="headerlink" title="📃如何创建线程池"></a>📃如何创建线程池</h3><h3 id="📃ThreadPoolExecutor构造函数的参数分析"><a href="#📃ThreadPoolExecutor构造函数的参数分析" class="headerlink" title="📃ThreadPoolExecutor构造函数的参数分析"></a>📃ThreadPoolExecutor构造函数的参数分析</h3><h3 id="📃ThreadPoolExecutor的饱和策略"><a href="#📃ThreadPoolExecutor的饱和策略" class="headerlink" title="📃ThreadPoolExecutor的饱和策略"></a>📃ThreadPoolExecutor的饱和策略</h3><h3 id="📃Atomic-原子类"><a href="#📃Atomic-原子类" class="headerlink" title="📃Atomic 原子类"></a>📃Atomic 原子类</h3><h3 id="📃JUC-包中的原子类是哪4类"><a href="#📃JUC-包中的原子类是哪4类" class="headerlink" title="📃JUC 包中的原子类是哪4类"></a>📃JUC 包中的原子类是哪4类</h3><h3 id="📃AtomicInteger-的使用与原理"><a href="#📃AtomicInteger-的使用与原理" class="headerlink" title="📃AtomicInteger 的使用与原理"></a>📃AtomicInteger 的使用与原理</h3><h3 id="📃什么是AQS(AbstractQueuedSynchronizer)"><a href="#📃什么是AQS(AbstractQueuedSynchronizer)" class="headerlink" title="📃什么是AQS(AbstractQueuedSynchronizer)"></a>📃什么是AQS(AbstractQueuedSynchronizer)</h3><h3 id="📃AQS-原理"><a href="#📃AQS-原理" class="headerlink" title="📃AQS 原理"></a>📃AQS 原理</h3><h3 id="📃AQS-对资源的共享方式"><a href="#📃AQS-对资源的共享方式" class="headerlink" title="📃AQS 对资源的共享方式"></a>📃AQS 对资源的共享方式</h3><h3 id="📃ConcurrentHashMap的原理"><a href="#📃ConcurrentHashMap的原理" class="headerlink" title="📃ConcurrentHashMap的原理"></a>📃ConcurrentHashMap的原理</h3><h3 id="📃八种阻塞队列以及各个阻塞队列的特性"><a href="#📃八种阻塞队列以及各个阻塞队列的特性" class="headerlink" title="📃八种阻塞队列以及各个阻塞队列的特性"></a>📃八种阻塞队列以及各个阻塞队列的特性</h3><h3 id="📃CopyOnWriteArrayList的原理"><a href="#📃CopyOnWriteArrayList的原理" class="headerlink" title="📃CopyOnWriteArrayList的原理"></a>📃CopyOnWriteArrayList的原理</h3><h3 id="📃ConcurrentSkipListMap的原理"><a href="#📃ConcurrentSkipListMap的原理" class="headerlink" title="📃ConcurrentSkipListMap的原理"></a>📃ConcurrentSkipListMap的原理</h3><h3 id="📃ScheduledThreadPoolExecutor-的介绍"><a href="#📃ScheduledThreadPoolExecutor-的介绍" class="headerlink" title="📃ScheduledThreadPoolExecutor 的介绍"></a>📃ScheduledThreadPoolExecutor 的介绍</h3><h3 id="📃乐观锁和悲观锁介绍"><a href="#📃乐观锁和悲观锁介绍" class="headerlink" title="📃乐观锁和悲观锁介绍"></a>📃乐观锁和悲观锁介绍</h3><h3 id="📃乐观锁和悲观锁的使用场景"><a href="#📃乐观锁和悲观锁的使用场景" class="headerlink" title="📃乐观锁和悲观锁的使用场景"></a>📃乐观锁和悲观锁的使用场景</h3><h3 id="📃乐观锁常见的两种实现方式"><a href="#📃乐观锁常见的两种实现方式" class="headerlink" title="📃乐观锁常见的两种实现方式"></a>📃乐观锁常见的两种实现方式</h3><h3 id="📃乐观锁的缺点"><a href="#📃乐观锁的缺点" class="headerlink" title="📃乐观锁的缺点"></a>📃乐观锁的缺点</h3><h3 id="📃如何解决ABA问题"><a href="#📃如何解决ABA问题" class="headerlink" title="📃如何解决ABA问题"></a>📃如何解决ABA问题</h3><h3 id="📃CAS与synchronized的使用情景"><a href="#📃CAS与synchronized的使用情景" class="headerlink" title="📃CAS与synchronized的使用情景"></a>📃CAS与synchronized的使用情景</h3><h3 id="📃什么是Semaphore(信号量)"><a href="#📃什么是Semaphore(信号量)" class="headerlink" title="📃什么是Semaphore(信号量)"></a>📃什么是Semaphore(信号量)</h3><h3 id="📃CountDownLatch-和-CyclicBarrier-的用法,以及相互之间的差别"><a href="#📃CountDownLatch-和-CyclicBarrier-的用法,以及相互之间的差别" class="headerlink" title="📃CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别"></a>📃CountDownLatch 和 CyclicBarrier 的用法,以及相互之间的差别</h3><h3 id="📃ReentrantLock-和-ReentrantReadWriteLock的区别"><a href="#📃ReentrantLock-和-ReentrantReadWriteLock的区别" class="headerlink" title="📃ReentrantLock 和 ReentrantReadWriteLock的区别"></a>📃ReentrantLock 和 ReentrantReadWriteLock的区别</h3><h3 id="📃LockSupport工具"><a href="#📃LockSupport工具" class="headerlink" title="📃LockSupport工具"></a>📃LockSupport工具</h3><h3 id="📃Condition接口及其实现原理"><a href="#📃Condition接口及其实现原理" class="headerlink" title="📃Condition接口及其实现原理"></a>📃Condition接口及其实现原理</h3><h3 id="📃Fork-Join框架的理解"><a href="#📃Fork-Join框架的理解" class="headerlink" title="📃Fork/Join框架的理解"></a>📃Fork/Join框架的理解</h3><h3 id="📃分段锁的原理-锁力度减小的思考"><a href="#📃分段锁的原理-锁力度减小的思考" class="headerlink" title="📃分段锁的原理,锁力度减小的思考"></a>📃分段锁的原理,锁力度减小的思考</h3><h3 id="📃几种常见的线程池及使用场景"><a href="#📃几种常见的线程池及使用场景" class="headerlink" title="📃几种常见的线程池及使用场景"></a>📃几种常见的线程池及使用场景</h3><h3 id="📃线程池都有哪几种工作队列"><a href="#📃线程池都有哪几种工作队列" class="headerlink" title="📃线程池都有哪几种工作队列"></a>📃线程池都有哪几种工作队列</h3><h3 id="📃怎么理解无界队列和有界队列"><a href="#📃怎么理解无界队列和有界队列" class="headerlink" title="📃怎么理解无界队列和有界队列"></a>📃怎么理解无界队列和有界队列</h3><h3 id="📃线程池如何调优"><a href="#📃线程池如何调优" class="headerlink" title="📃线程池如何调优"></a>📃线程池如何调优</h3><hr><blockquote><h2 id="📚JVM"><a href="#📚JVM" class="headerlink" title="📚JVM"></a>📚JVM</h2></blockquote><h3 id="📃jvm内存模型"><a href="#📃jvm内存模型" class="headerlink" title="📃jvm内存模型"></a>📃jvm内存模型</h3><h3 id="📃对象的创建过程"><a href="#📃对象的创建过程" class="headerlink" title="📃对象的创建过程"></a>📃对象的创建过程</h3><h3 id="📃什么情况下会出现内存溢出,内存泄漏"><a href="#📃什么情况下会出现内存溢出,内存泄漏" class="headerlink" title="📃什么情况下会出现内存溢出,内存泄漏"></a>📃什么情况下会出现内存溢出,内存泄漏</h3><h3 id="📃Java线程栈"><a href="#📃Java线程栈" class="headerlink" title="📃Java线程栈"></a>📃Java线程栈</h3><h3 id="📃JVM-年轻代到年老代的晋升过程的判断条件是什么"><a href="#📃JVM-年轻代到年老代的晋升过程的判断条件是什么" class="headerlink" title="📃JVM 年轻代到年老代的晋升过程的判断条件是什么"></a>📃JVM 年轻代到年老代的晋升过程的判断条件是什么</h3><h3 id="📃JVM-出现-fullGC-很频繁,怎么去线上排查问题"><a href="#📃JVM-出现-fullGC-很频繁,怎么去线上排查问题" class="headerlink" title="📃JVM 出现 fullGC 很频繁,怎么去线上排查问题"></a>📃JVM 出现 fullGC 很频繁,怎么去线上排查问题</h3><h3 id="📃类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式"><a href="#📃类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式" class="headerlink" title="📃类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式"></a>📃类加载为什么要使用双亲委派模式,有没有什么场景是打破了这个模式</h3><h3 id="📃类的加载过程"><a href="#📃类的加载过程" class="headerlink" title="📃类的加载过程"></a>📃类的加载过程</h3><h3 id="📃类的实例化顺序"><a href="#📃类的实例化顺序" class="headerlink" title="📃类的实例化顺序"></a>📃类的实例化顺序</h3><h3 id="📃JVM垃圾回收机制,何时触发MinorGC等操作"><a href="#📃JVM垃圾回收机制,何时触发MinorGC等操作" class="headerlink" title="📃JVM垃圾回收机制,何时触发MinorGC等操作"></a>📃JVM垃圾回收机制,何时触发MinorGC等操作</h3><h3 id="📃JVM-中一次完整的-GC-流程(从-ygc-到-fgc)是怎样的"><a href="#📃JVM-中一次完整的-GC-流程(从-ygc-到-fgc)是怎样的" class="headerlink" title="📃JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的"></a>📃JVM 中一次完整的 GC 流程(从 ygc 到 fgc)是怎样的</h3><h3 id="📃各种回收器,各自优缺点,重点CMS、G1"><a href="#📃各种回收器,各自优缺点,重点CMS、G1" class="headerlink" title="📃各种回收器,各自优缺点,重点CMS、G1"></a>📃各种回收器,各自优缺点,重点CMS、G1</h3><h3 id="📃各种回收算法的比较"><a href="#📃各种回收算法的比较" class="headerlink" title="📃各种回收算法的比较"></a>📃各种回收算法的比较</h3><h3 id="📃为什么jdk8用metaspace数据结构用来替代perm"><a href="#📃为什么jdk8用metaspace数据结构用来替代perm" class="headerlink" title="📃为什么jdk8用metaspace数据结构用来替代perm"></a>📃为什么jdk8用metaspace数据结构用来替代perm</h3><h3 id="📃JVM老年代和新生代的比例"><a href="#📃JVM老年代和新生代的比例" class="headerlink" title="📃JVM老年代和新生代的比例"></a>📃JVM老年代和新生代的比例</h3><h3 id="📃为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗"><a href="#📃为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗" class="headerlink" title="📃为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗"></a>📃为什么要把堆和栈区分出来呢?栈中不是也可以存储数据吗</h3><h3 id="📃为什么不把基本类型放堆中呢"><a href="#📃为什么不把基本类型放堆中呢" class="headerlink" title="📃为什么不把基本类型放堆中呢"></a>📃为什么不把基本类型放堆中呢</h3><h3 id="📃在Java中,什么是是栈的起始点,同是也是程序的起始点"><a href="#📃在Java中,什么是是栈的起始点,同是也是程序的起始点" class="headerlink" title="📃在Java中,什么是是栈的起始点,同是也是程序的起始点"></a>📃在Java中,什么是是栈的起始点,同是也是程序的起始点</h3><h3 id="📃Java虚拟机中,数据类型可以分为哪几类"><a href="#📃Java虚拟机中,数据类型可以分为哪几类" class="headerlink" title="📃Java虚拟机中,数据类型可以分为哪几类"></a>📃Java虚拟机中,数据类型可以分为哪几类</h3><h3 id="📃Java中有没有指针的概念"><a href="#📃Java中有没有指针的概念" class="headerlink" title="📃Java中有没有指针的概念"></a>📃Java中有没有指针的概念</h3><h3 id="📃Java中,栈的大小通过什么参数来设置"><a href="#📃Java中,栈的大小通过什么参数来设置" class="headerlink" title="📃Java中,栈的大小通过什么参数来设置"></a>📃Java中,栈的大小通过什么参数来设置</h3><h3 id="📃一个空Object对象的占多大空间"><a href="#📃一个空Object对象的占多大空间" class="headerlink" title="📃一个空Object对象的占多大空间"></a>📃一个空Object对象的占多大空间</h3><h3 id="📃对象引用类型分为哪几类"><a href="#📃对象引用类型分为哪几类" class="headerlink" title="📃对象引用类型分为哪几类"></a>📃对象引用类型分为哪几类</h3><h3 id="📃如何解决内存碎片的问题"><a href="#📃如何解决内存碎片的问题" class="headerlink" title="📃如何解决内存碎片的问题"></a>📃如何解决内存碎片的问题</h3><h3 id="📃如何解决同时存在的对象创建和对象回收问题"><a href="#📃如何解决同时存在的对象创建和对象回收问题" class="headerlink" title="📃如何解决同时存在的对象创建和对象回收问题"></a>📃如何解决同时存在的对象创建和对象回收问题</h3><h3 id="📃如何选择合适的垃圾收集算法"><a href="#📃如何选择合适的垃圾收集算法" class="headerlink" title="📃如何选择合适的垃圾收集算法"></a>📃如何选择合适的垃圾收集算法</h3><h3 id="📃JVM中最大堆大小有没有限制"><a href="#📃JVM中最大堆大小有没有限制" class="headerlink" title="📃JVM中最大堆大小有没有限制"></a>📃JVM中最大堆大小有没有限制</h3><h3 id="📃吞吐量优先选择什么垃圾回收器"><a href="#📃吞吐量优先选择什么垃圾回收器" class="headerlink" title="📃吞吐量优先选择什么垃圾回收器"></a>📃吞吐量优先选择什么垃圾回收器</h3><h3 id="📃响应时间优先选择什么垃圾回收器"><a href="#📃响应时间优先选择什么垃圾回收器" class="headerlink" title="📃响应时间优先选择什么垃圾回收器"></a>📃响应时间优先选择什么垃圾回收器</h3><h3 id="📃如何进行JVM调优"><a href="#📃如何进行JVM调优" class="headerlink" title="📃如何进行JVM调优"></a>📃如何进行JVM调优</h3><hr><blockquote><h2 id="📚MySQL"><a href="#📚MySQL" class="headerlink" title="📚MySQL"></a>📚MySQL</h2></blockquote><h3 id="📃MyISAM和InnoDB区别"><a href="#📃MyISAM和InnoDB区别" class="headerlink" title="📃MyISAM和InnoDB区别"></a>📃MyISAM和InnoDB区别</h3><h3 id="📃为什么使用索引"><a href="#📃为什么使用索引" class="headerlink" title="📃为什么使用索引"></a>📃为什么使用索引</h3><h3 id="📃索引是如何提高查询速度的"><a href="#📃索引是如何提高查询速度的" class="headerlink" title="📃索引是如何提高查询速度的"></a>📃索引是如何提高查询速度的</h3><h3 id="📃使用索引需要注意些什么"><a href="#📃使用索引需要注意些什么" class="headerlink" title="📃使用索引需要注意些什么"></a>📃使用索引需要注意些什么</h3><h3 id="📃BTree索引和哈希索引"><a href="#📃BTree索引和哈希索引" class="headerlink" title="📃BTree索引和哈希索引"></a>📃BTree索引和哈希索引</h3><h3 id="📃MyISAM和InnoDB实现BTree索引方式的区别"><a href="#📃MyISAM和InnoDB实现BTree索引方式的区别" class="headerlink" title="📃MyISAM和InnoDB实现BTree索引方式的区别"></a>📃MyISAM和InnoDB实现BTree索引方式的区别</h3><h3 id="📃什么是覆盖索引"><a href="#📃什么是覆盖索引" class="headerlink" title="📃什么是覆盖索引"></a>📃什么是覆盖索引</h3><h3 id="📃选择索引和利用索引查询的3个原则"><a href="#📃选择索引和利用索引查询的3个原则" class="headerlink" title="📃选择索引和利用索引查询的3个原则"></a>📃选择索引和利用索引查询的3个原则</h3><h3 id="📃什么是事务"><a href="#📃什么是事务" class="headerlink" title="📃什么是事务"></a>📃什么是事务</h3><h3 id="📃事物的四大特性"><a href="#📃事物的四大特性" class="headerlink" title="📃事物的四大特性"></a>📃事物的四大特性</h3><h3 id="📃并发事务带来哪些问题"><a href="#📃并发事务带来哪些问题" class="headerlink" title="📃并发事务带来哪些问题"></a>📃并发事务带来哪些问题</h3><h3 id="📃不可重复读和幻读区别"><a href="#📃不可重复读和幻读区别" class="headerlink" title="📃不可重复读和幻读区别"></a>📃不可重复读和幻读区别</h3><h3 id="📃事务隔离级别有哪些"><a href="#📃事务隔离级别有哪些" class="headerlink" title="📃事务隔离级别有哪些"></a>📃事务隔离级别有哪些</h3><h3 id="📃MySQL的默认隔离级别"><a href="#📃MySQL的默认隔离级别" class="headerlink" title="📃MySQL的默认隔离级别"></a>📃MySQL的默认隔离级别</h3><h3 id="📃锁机制与InnoDB锁算法"><a href="#📃锁机制与InnoDB锁算法" class="headerlink" title="📃锁机制与InnoDB锁算法"></a>📃锁机制与InnoDB锁算法</h3><h3 id="📃表级锁和行级锁对比"><a href="#📃表级锁和行级锁对比" class="headerlink" title="📃表级锁和行级锁对比"></a>📃表级锁和行级锁对比</h3><h3 id="📃InnoDB存储引擎的三种锁的算法"><a href="#📃InnoDB存储引擎的三种锁的算法" class="headerlink" title="📃InnoDB存储引擎的三种锁的算法"></a>📃InnoDB存储引擎的三种锁的算法</h3><h3 id="📃大表的优化"><a href="#📃大表的优化" class="headerlink" title="📃大表的优化"></a>📃大表的优化</h3><h3 id="📃分库分表之后-id-主键如何处理"><a href="#📃分库分表之后-id-主键如何处理" class="headerlink" title="📃分库分表之后,id 主键如何处理"></a>📃分库分表之后,id 主键如何处理</h3><h3 id="📃snowflake算法"><a href="#📃snowflake算法" class="headerlink" title="📃snowflake算法"></a>📃snowflake算法</h3><h3 id="📃美团的Leaf分布式ID生成系统"><a href="#📃美团的Leaf分布式ID生成系统" class="headerlink" title="📃美团的Leaf分布式ID生成系统"></a>📃美团的Leaf分布式ID生成系统</h3><h3 id="📃一条SQL语句在MySQL中如何执行的"><a href="#📃一条SQL语句在MySQL中如何执行的" class="headerlink" title="📃一条SQL语句在MySQL中如何执行的"></a>📃一条SQL语句在MySQL中如何执行的</h3><h3 id="📃MySQL高性能优化规范建议"><a href="#📃MySQL高性能优化规范建议" class="headerlink" title="📃MySQL高性能优化规范建议"></a>📃MySQL高性能优化规范建议</h3><h3 id="📃一条SQL语句执行得很慢的原因有哪些"><a href="#📃一条SQL语句执行得很慢的原因有哪些" class="headerlink" title="📃一条SQL语句执行得很慢的原因有哪些"></a>📃一条SQL语句执行得很慢的原因有哪些</h3><hr><blockquote><h2 id="📚Spring"><a href="#📚Spring" class="headerlink" title="📚Spring"></a>📚Spring</h2></blockquote><h3 id="📃BeanFactory-和-FactoryBean?"><a href="#📃BeanFactory-和-FactoryBean?" class="headerlink" title="📃BeanFactory 和 FactoryBean?"></a>📃BeanFactory 和 FactoryBean?</h3><h3 id="📃Spring-IOC-的理解,其初始化过程?"><a href="#📃Spring-IOC-的理解,其初始化过程?" class="headerlink" title="📃Spring IOC 的理解,其初始化过程?"></a>📃Spring IOC 的理解,其初始化过程?</h3><h3 id="📃Soring-有多少种IoC容器"><a href="#📃Soring-有多少种IoC容器" class="headerlink" title="📃Soring 有多少种IoC容器"></a>📃Soring 有多少种IoC容器</h3><h3 id="📃IoC和DI有什么区别"><a href="#📃IoC和DI有什么区别" class="headerlink" title="📃IoC和DI有什么区别"></a>📃IoC和DI有什么区别</h3><h3 id="📃BeanFactory-和-ApplicationContext?"><a href="#📃BeanFactory-和-ApplicationContext?" class="headerlink" title="📃BeanFactory 和 ApplicationContext?"></a>📃BeanFactory 和 ApplicationContext?</h3><h3 id="📃IoC的好处有哪些"><a href="#📃IoC的好处有哪些" class="headerlink" title="📃IoC的好处有哪些"></a>📃IoC的好处有哪些</h3><h3 id="📃Spring框架找那个有哪些不同类型的事件"><a href="#📃Spring框架找那个有哪些不同类型的事件" class="headerlink" title="📃Spring框架找那个有哪些不同类型的事件"></a>📃Spring框架找那个有哪些不同类型的事件</h3><h3 id="📃Spring-Bean-的生命周期,如何被管理的?"><a href="#📃Spring-Bean-的生命周期,如何被管理的?" class="headerlink" title="📃Spring Bean 的生命周期,如何被管理的?"></a>📃Spring Bean 的生命周期,如何被管理的?</h3><h3 id="📃Spring-Bean-的加载过程是怎样的?"><a href="#📃Spring-Bean-的加载过程是怎样的?" class="headerlink" title="📃Spring Bean 的加载过程是怎样的?"></a>📃Spring Bean 的加载过程是怎样的?</h3><h3 id="📃Spring-支持哪些Spring-Scope"><a href="#📃Spring-支持哪些Spring-Scope" class="headerlink" title="📃Spring 支持哪些Spring Scope"></a>📃Spring 支持哪些Spring Scope</h3><h3 id="📃什么是Spring的内部Bean"><a href="#📃什么是Spring的内部Bean" class="headerlink" title="📃什么是Spring的内部Bean"></a>📃什么是Spring的内部Bean</h3><h3 id="📃什么是Spring装配"><a href="#📃什么是Spring装配" class="headerlink" title="📃什么是Spring装配"></a>📃什么是Spring装配</h3><h3 id="📃Spring-框架中单例Bean是线程安全的吗"><a href="#📃Spring-框架中单例Bean是线程安全的吗" class="headerlink" title="📃Spring 框架中单例Bean是线程安全的吗"></a>📃Spring 框架中单例Bean是线程安全的吗</h3><h3 id="📃Spring-Bean如何解决循环依赖的问题"><a href="#📃Spring-Bean如何解决循环依赖的问题" class="headerlink" title="📃Spring Bean如何解决循环依赖的问题"></a>📃Spring Bean如何解决循环依赖的问题</h3><h3 id="📃什么是AOP"><a href="#📃什么是AOP" class="headerlink" title="📃什么是AOP"></a>📃什么是AOP</h3><h3 id="📃JoinPoint和PointCut的区别"><a href="#📃JoinPoint和PointCut的区别" class="headerlink" title="📃JoinPoint和PointCut的区别"></a>📃JoinPoint和PointCut的区别</h3><h3 id="📃AOP有哪些实现方式"><a href="#📃AOP有哪些实现方式" class="headerlink" title="📃AOP有哪些实现方式"></a>📃AOP有哪些实现方式</h3><h3 id="📃什么是编织-Weaving"><a href="#📃什么是编织-Weaving" class="headerlink" title="📃什么是编织(Weaving)"></a>📃什么是编织(Weaving)</h3><h3 id="📃什么是事务-1"><a href="#📃什么是事务-1" class="headerlink" title="📃什么是事务"></a>📃什么是事务</h3><h3 id="📃事务的特性指的是"><a href="#📃事务的特性指的是" class="headerlink" title="📃事务的特性指的是"></a>📃事务的特性指的是</h3><h3 id="📃Spring支持的事务管理类型"><a href="#📃Spring支持的事务管理类型" class="headerlink" title="📃Spring支持的事务管理类型"></a>📃Spring支持的事务管理类型</h3><h3 id="📃Spring-事务如何和不同的数据持久化框架做集成"><a href="#📃Spring-事务如何和不同的数据持久化框架做集成" class="headerlink" title="📃Spring 事务如何和不同的数据持久化框架做集成"></a>📃Spring 事务如何和不同的数据持久化框架做集成</h3><h3 id="📃为什么在Spring事务中不能切换数据源"><a href="#📃为什么在Spring事务中不能切换数据源" class="headerlink" title="📃为什么在Spring事务中不能切换数据源"></a>📃为什么在Spring事务中不能切换数据源</h3><h3 id="📃什么是事务的隔离级别"><a href="#📃什么是事务的隔离级别" class="headerlink" title="📃什么是事务的隔离级别"></a>📃什么是事务的隔离级别</h3><h3 id="📃有哪些隔离级别"><a href="#📃有哪些隔离级别" class="headerlink" title="📃有哪些隔离级别"></a>📃有哪些隔离级别</h3><h3 id="📃什么是事务的传播级别"><a href="#📃什么是事务的传播级别" class="headerlink" title="📃什么是事务的传播级别"></a>📃什么是事务的传播级别</h3><h3 id="📃有哪些传播级别"><a href="#📃有哪些传播级别" class="headerlink" title="📃有哪些传播级别"></a>📃有哪些传播级别</h3><h3 id="📃事务的超时属性,只读属性和回滚规则"><a href="#📃事务的超时属性,只读属性和回滚规则" class="headerlink" title="📃事务的超时属性,只读属性和回滚规则"></a>📃事务的超时属性,只读属性和回滚规则</h3><h3 id="📃如果要你实现Spring-AOP,请问怎么实现"><a href="#📃如果要你实现Spring-AOP,请问怎么实现" class="headerlink" title="📃如果要你实现Spring AOP,请问怎么实现"></a>📃如果要你实现Spring AOP,请问怎么实现</h3><h3 id="📃如果要你实现Spring-IOC,你会注意哪些问题"><a href="#📃如果要你实现Spring-IOC,你会注意哪些问题" class="headerlink" title="📃如果要你实现Spring IOC,你会注意哪些问题"></a>📃如果要你实现Spring IOC,你会注意哪些问题</h3><h3 id="📃Spring-是如何管理事务的,事务管理机制"><a href="#📃Spring-是如何管理事务的,事务管理机制" class="headerlink" title="📃Spring 是如何管理事务的,事务管理机制"></a>📃Spring 是如何管理事务的,事务管理机制</h3><h3 id="📃Spring-的不同事务传播行为有哪些,干什么用的"><a href="#📃Spring-的不同事务传播行为有哪些,干什么用的" class="headerlink" title="📃Spring 的不同事务传播行为有哪些,干什么用的"></a>📃Spring 的不同事务传播行为有哪些,干什么用的</h3><h3 id="📃Spring-中用到了那些设计模式"><a href="#📃Spring-中用到了那些设计模式" class="headerlink" title="📃Spring 中用到了那些设计模式"></a>📃Spring 中用到了那些设计模式</h3><h3 id="📃Spring-循环注入的原理"><a href="#📃Spring-循环注入的原理" class="headerlink" title="📃Spring 循环注入的原理"></a>📃Spring 循环注入的原理</h3><h3 id="📃Spring-AOP的理解,各个术语,他们是怎么相互工作的"><a href="#📃Spring-AOP的理解,各个术语,他们是怎么相互工作的" class="headerlink" title="📃Spring AOP的理解,各个术语,他们是怎么相互工作的"></a>📃Spring AOP的理解,各个术语,他们是怎么相互工作的</h3><h3 id="📃Spring-如何保证-Controller-并发的安全"><a href="#📃Spring-如何保证-Controller-并发的安全" class="headerlink" title="📃Spring 如何保证 Controller 并发的安全"></a>📃Spring 如何保证 Controller 并发的安全</h3><hr><blockquote><h2 id="📚Spring-MVC"><a href="#📚Spring-MVC" class="headerlink" title="📚Spring MVC"></a>📚Spring MVC</h2></blockquote><h3 id="📃Spring-MVC-的工作原理"><a href="#📃Spring-MVC-的工作原理" class="headerlink" title="📃Spring MVC 的工作原理"></a>📃Spring MVC 的工作原理</h3><h3 id="📃介绍下-Spring-MVC-的核心组件"><a href="#📃介绍下-Spring-MVC-的核心组件" class="headerlink" title="📃介绍下 Spring MVC 的核心组件"></a>📃介绍下 Spring MVC 的核心组件</h3><h3 id="📃描述一下-DispatcherServlet-的工作流程"><a href="#📃描述一下-DispatcherServlet-的工作流程" class="headerlink" title="📃描述一下 DispatcherServlet 的工作流程"></a>📃描述一下 DispatcherServlet 的工作流程</h3><h3 id="📃介绍一下-WebApplicationContext"><a href="#📃介绍一下-WebApplicationContext" class="headerlink" title="📃介绍一下 WebApplicationContext"></a>📃介绍一下 WebApplicationContext</h3><h3 id="📃Spring-MVC-的-Controller-是不是单例"><a href="#📃Spring-MVC-的-Controller-是不是单例" class="headerlink" title="📃Spring MVC 的 Controller 是不是单例"></a>📃Spring MVC 的 Controller 是不是单例</h3><h3 id="📃Spring-MVC-怎样设定重定向和转发"><a href="#📃Spring-MVC-怎样设定重定向和转发" class="headerlink" title="📃Spring MVC 怎样设定重定向和转发"></a>📃Spring MVC 怎样设定重定向和转发</h3><h3 id="📃Spring-MVC-的拦截器可以做哪些事情"><a href="#📃Spring-MVC-的拦截器可以做哪些事情" class="headerlink" title="📃Spring MVC 的拦截器可以做哪些事情"></a>📃Spring MVC 的拦截器可以做哪些事情</h3><h3 id="📃Spring-MVC-的拦截器和-Filter-过滤器有什么差别"><a href="#📃Spring-MVC-的拦截器和-Filter-过滤器有什么差别" class="headerlink" title="📃Spring MVC 的拦截器和 Filter 过滤器有什么差别"></a>📃Spring MVC 的拦截器和 Filter 过滤器有什么差别</h3><h3 id="📃REST-代表着什么"><a href="#📃REST-代表着什么" class="headerlink" title="📃REST 代表着什么"></a>📃REST 代表着什么</h3><h3 id="📃资源是什么"><a href="#📃资源是什么" class="headerlink" title="📃资源是什么"></a>📃资源是什么</h3><h3 id="📃什么是安全的-REST-操作"><a href="#📃什么是安全的-REST-操作" class="headerlink" title="📃什么是安全的 REST 操作"></a>📃什么是安全的 REST 操作</h3><h3 id="📃什么是幂等操作-为什么幂等操作如此重要"><a href="#📃什么是幂等操作-为什么幂等操作如此重要" class="headerlink" title="📃什么是幂等操作? 为什么幂等操作如此重要"></a>📃什么是幂等操作? 为什么幂等操作如此重要</h3><h3 id="📃REST-是可扩展的或说是协同的吗"><a href="#📃REST-是可扩展的或说是协同的吗" class="headerlink" title="📃REST 是可扩展的或说是协同的吗"></a>📃REST 是可扩展的或说是协同的吗</h3><h3 id="📃REST-用哪种-HTTP-方法呢"><a href="#📃REST-用哪种-HTTP-方法呢" class="headerlink" title="📃REST 用哪种 HTTP 方法呢"></a>📃REST 用哪种 HTTP 方法呢</h3><h3 id="📃删除的-HTTP-状态返回码是什么"><a href="#📃删除的-HTTP-状态返回码是什么" class="headerlink" title="📃删除的 HTTP 状态返回码是什么"></a>📃删除的 HTTP 状态返回码是什么</h3><h3 id="📃REST-API-是无状态的吗"><a href="#📃REST-API-是无状态的吗" class="headerlink" title="📃REST API 是无状态的吗"></a>📃REST API 是无状态的吗</h3><h3 id="📃REST安全吗-你能做什么来保护它"><a href="#📃REST安全吗-你能做什么来保护它" class="headerlink" title="📃REST安全吗? 你能做什么来保护它"></a>📃REST安全吗? 你能做什么来保护它</h3><h3 id="📃RestTemplate-的优势是什么"><a href="#📃RestTemplate-的优势是什么" class="headerlink" title="📃RestTemplate 的优势是什么"></a>📃RestTemplate 的优势是什么</h3><h3 id="📃HttpMessageConverter-在-Spring-REST-中代表什么"><a href="#📃HttpMessageConverter-在-Spring-REST-中代表什么" class="headerlink" title="📃HttpMessageConverter 在 Spring REST 中代表什么"></a>📃HttpMessageConverter 在 Spring REST 中代表什么</h3><h3 id="📃如何创建-HttpMessageConverter-的自定义实现来支持一种新的请求-响应"><a href="#📃如何创建-HttpMessageConverter-的自定义实现来支持一种新的请求-响应" class="headerlink" title="📃如何创建 HttpMessageConverter 的自定义实现来支持一种新的请求/响应"></a>📃如何创建 HttpMessageConverter 的自定义实现来支持一种新的请求/响应</h3><h3 id="📃-PathVariable-注解,在-Spring-MVC-做了什么-为什么-REST-在-Spring-中如此有用"><a href="#📃-PathVariable-注解,在-Spring-MVC-做了什么-为什么-REST-在-Spring-中如此有用" class="headerlink" title="📃@PathVariable 注解,在 Spring MVC 做了什么? 为什么 REST 在 Spring 中如此有用"></a>📃@PathVariable 注解,在 Spring MVC 做了什么? 为什么 REST 在 Spring 中如此有用</h3><hr><blockquote><h2 id="📚SpringBoot"><a href="#📚SpringBoot" class="headerlink" title="📚SpringBoot"></a>📚SpringBoot</h2></blockquote><h3 id="📃-Spring-Boot-是什么?"><a href="#📃-Spring-Boot-是什么?" class="headerlink" title="📃 Spring Boot 是什么?"></a>📃 Spring Boot 是什么?</h3><h3 id="📃-Spring-Boot-提供了哪些核心功能"><a href="#📃-Spring-Boot-提供了哪些核心功能" class="headerlink" title="📃 Spring Boot 提供了哪些核心功能"></a>📃 Spring Boot 提供了哪些核心功能</h3><h3 id="📃-Spring-Boot-有什么优缺点"><a href="#📃-Spring-Boot-有什么优缺点" class="headerlink" title="📃 Spring Boot 有什么优缺点"></a>📃 Spring Boot 有什么优缺点</h3><h3 id="📃-Spring-Boot、Spring-MVC-和-Spring-有什么区别"><a href="#📃-Spring-Boot、Spring-MVC-和-Spring-有什么区别" class="headerlink" title="📃 Spring Boot、Spring MVC 和 Spring 有什么区别"></a>📃 Spring Boot、Spring MVC 和 Spring 有什么区别</h3><h3 id="📃-Spring-Boot-中的-Starter-是什么"><a href="#📃-Spring-Boot-中的-Starter-是什么" class="headerlink" title="📃 Spring Boot 中的 Starter 是什么"></a>📃 Spring Boot 中的 Starter 是什么</h3><h3 id="📃-Spring-Boot-常用的-Starter-有哪些"><a href="#📃-Spring-Boot-常用的-Starter-有哪些" class="headerlink" title="📃 Spring Boot 常用的 Starter 有哪些"></a>📃 Spring Boot 常用的 Starter 有哪些</h3><h3 id="📃-创建一个-Spring-Boot-Project-的最简单的方法是什么"><a href="#📃-创建一个-Spring-Boot-Project-的最简单的方法是什么" class="headerlink" title="📃 创建一个 Spring Boot Project 的最简单的方法是什么"></a>📃 创建一个 Spring Boot Project 的最简单的方法是什么</h3><h3 id="📃-如何统一引入-Spring-Boot-版本"><a href="#📃-如何统一引入-Spring-Boot-版本" class="headerlink" title="📃 如何统一引入 Spring Boot 版本"></a>📃 如何统一引入 Spring Boot 版本</h3><h3 id="📃-运行-Spring-Boot-有哪几种方式"><a href="#📃-运行-Spring-Boot-有哪几种方式" class="headerlink" title="📃 运行 Spring Boot 有哪几种方式"></a>📃 运行 Spring Boot 有哪几种方式</h3><h3 id="📃-如何打包-Spring-Boot-项目"><a href="#📃-如何打包-Spring-Boot-项目" class="headerlink" title="📃 如何打包 Spring Boot 项目"></a>📃 如何打包 Spring Boot 项目</h3><h3 id="📃-如果更改内嵌-Tomcat-的端口"><a href="#📃-如果更改内嵌-Tomcat-的端口" class="headerlink" title="📃 如果更改内嵌 Tomcat 的端口"></a>📃 如果更改内嵌 Tomcat 的端口</h3><h3 id="📃-如何重新加载-Spring-Boot-上的更改,而无需重新启动服务器"><a href="#📃-如何重新加载-Spring-Boot-上的更改,而无需重新启动服务器" class="headerlink" title="📃 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器"></a>📃 如何重新加载 Spring Boot 上的更改,而无需重新启动服务器</h3><h3 id="📃-Spring-Boot-的配置文件有哪几种格式"><a href="#📃-Spring-Boot-的配置文件有哪几种格式" class="headerlink" title="📃 Spring Boot 的配置文件有哪几种格式"></a>📃 Spring Boot 的配置文件有哪几种格式</h3><h3 id="📃-Spring-Boot-默认配置文件是什么"><a href="#📃-Spring-Boot-默认配置文件是什么" class="headerlink" title="📃 Spring Boot 默认配置文件是什么"></a>📃 Spring Boot 默认配置文件是什么</h3><h3 id="📃-Spring-Boot-如何定义多套不同环境配置"><a href="#📃-Spring-Boot-如何定义多套不同环境配置" class="headerlink" title="📃 Spring Boot 如何定义多套不同环境配置"></a>📃 Spring Boot 如何定义多套不同环境配置</h3><h3 id="📃-Spring-Boot-配置加载顺序"><a href="#📃-Spring-Boot-配置加载顺序" class="headerlink" title="📃 Spring Boot 配置加载顺序"></a>📃 Spring Boot 配置加载顺序</h3><h3 id="📃-Spring-Boot-有哪些配置方式"><a href="#📃-Spring-Boot-有哪些配置方式" class="headerlink" title="📃 Spring Boot 有哪些配置方式"></a>📃 Spring Boot 有哪些配置方式</h3><h3 id="📃-Spring-Boot-的核心注解是哪个"><a href="#📃-Spring-Boot-的核心注解是哪个" class="headerlink" title="📃 Spring Boot 的核心注解是哪个"></a>📃 Spring Boot 的核心注解是哪个</h3><h3 id="📃-什么是-Spring-Boot-自动配置"><a href="#📃-什么是-Spring-Boot-自动配置" class="headerlink" title="📃 什么是 Spring Boot 自动配置"></a>📃 什么是 Spring Boot 自动配置</h3><h3 id="📃-Spring-Boot-有哪几种读取配置的方式"><a href="#📃-Spring-Boot-有哪几种读取配置的方式" class="headerlink" title="📃 Spring Boot 有哪几种读取配置的方式"></a>📃 Spring Boot 有哪几种读取配置的方式</h3><h3 id="📃-使用-Spring-Boot-后,项目结构是怎么样的呢"><a href="#📃-使用-Spring-Boot-后,项目结构是怎么样的呢" class="headerlink" title="📃 使用 Spring Boot 后,项目结构是怎么样的呢"></a>📃 使用 Spring Boot 后,项目结构是怎么样的呢</h3><h3 id="📃-如何在-Spring-Boot-启动的时候运行一些特殊的代码"><a href="#📃-如何在-Spring-Boot-启动的时候运行一些特殊的代码" class="headerlink" title="📃 如何在 Spring Boot 启动的时候运行一些特殊的代码"></a>📃 如何在 Spring Boot 启动的时候运行一些特殊的代码</h3><h3 id="📃-Spring-Boot-2-X-有什么新特性"><a href="#📃-Spring-Boot-2-X-有什么新特性" class="headerlink" title="📃 Spring Boot 2.X 有什么新特性"></a>📃 Spring Boot 2.X 有什么新特性</h3><hr><blockquote><h2 id="📚SpringCloud"><a href="#📚SpringCloud" class="headerlink" title="📚SpringCloud"></a>📚SpringCloud</h2></blockquote><h3 id="📃什么是-Spring-Cloud-?"><a href="#📃什么是-Spring-Cloud-?" class="headerlink" title="📃什么是 Spring Cloud ?"></a>📃什么是 Spring Cloud ?</h3><h3 id="📃Spring-Cloud-核心功能是什么?"><a href="#📃Spring-Cloud-核心功能是什么?" class="headerlink" title="📃Spring Cloud 核心功能是什么?"></a>📃Spring Cloud 核心功能是什么?</h3><h3 id="📃Spring-Cloud-有哪些组件?"><a href="#📃Spring-Cloud-有哪些组件?" class="headerlink" title="📃Spring Cloud 有哪些组件?"></a>📃Spring Cloud 有哪些组件?</h3><h3 id="📃Spring-Cloud-和-Spring-Boot-的区别和关系?"><a href="#📃Spring-Cloud-和-Spring-Boot-的区别和关系?" class="headerlink" title="📃Spring Cloud 和 Spring Boot 的区别和关系?"></a>📃Spring Cloud 和 Spring Boot 的区别和关系?</h3><h3 id="📃Spring-Cloud-和-Dubbo-的区别?"><a href="#📃Spring-Cloud-和-Dubbo-的区别?" class="headerlink" title="📃Spring Cloud 和 Dubbo 的区别?"></a>📃Spring Cloud 和 Dubbo 的区别?</h3><h3 id="📃什么是微服务?"><a href="#📃什么是微服务?" class="headerlink" title="📃什么是微服务?"></a>📃什么是微服务?</h3><h3 id="📃微服务的优缺点分别是什么?"><a href="#📃微服务的优缺点分别是什么?" class="headerlink" title="📃微服务的优缺点分别是什么?"></a>📃微服务的优缺点分别是什么?</h3><h3 id="📃注册中心"><a href="#📃注册中心" class="headerlink" title="📃注册中心"></a>📃注册中心</h3><h3 id="📃为什么要使用服务发现?"><a href="#📃为什么要使用服务发现?" class="headerlink" title="📃为什么要使用服务发现?"></a>📃为什么要使用服务发现?</h3><h3 id="📃Eureka"><a href="#📃Eureka" class="headerlink" title="📃Eureka"></a>📃Eureka</h3><h3 id="📃Eureka-如何实现集群?"><a href="#📃Eureka-如何实现集群?" class="headerlink" title="📃Eureka 如何实现集群?"></a>📃Eureka 如何实现集群?</h3><h3 id="📃聊聊-Eureka-缓存机制?"><a href="#📃聊聊-Eureka-缓存机制?" class="headerlink" title="📃聊聊 Eureka 缓存机制?"></a>📃聊聊 Eureka 缓存机制?</h3><h3 id="📃什么是-Eureka-自我保护机制?"><a href="#📃什么是-Eureka-自我保护机制?" class="headerlink" title="📃什么是 Eureka 自我保护机制?"></a>📃什么是 Eureka 自我保护机制?</h3><h3 id="📃负载均衡"><a href="#📃负载均衡" class="headerlink" title="📃负载均衡"></a>📃负载均衡</h3><h3 id="📃为什么要负载均衡?"><a href="#📃为什么要负载均衡?" class="headerlink" title="📃为什么要负载均衡?"></a>📃为什么要负载均衡?</h3><h3 id="📃Ribbon"><a href="#📃Ribbon" class="headerlink" title="📃Ribbon"></a>📃Ribbon</h3><h3 id="📃Ribbon-有哪些负载均衡算法?"><a href="#📃Ribbon-有哪些负载均衡算法?" class="headerlink" title="📃Ribbon 有哪些负载均衡算法?"></a>📃Ribbon 有哪些负载均衡算法?</h3><h3 id="📃聊聊-Ribbon-缓存机制?"><a href="#📃聊聊-Ribbon-缓存机制?" class="headerlink" title="📃聊聊 Ribbon 缓存机制?"></a>📃聊聊 Ribbon 缓存机制?</h3><h3 id="📃聊聊-Ribbon-重试机制?"><a href="#📃聊聊-Ribbon-重试机制?" class="headerlink" title="📃聊聊 Ribbon 重试机制?"></a>📃聊聊 Ribbon 重试机制?</h3><h3 id="📃Ribbon-是怎么和-Eureka-整合的?"><a href="#📃Ribbon-是怎么和-Eureka-整合的?" class="headerlink" title="📃Ribbon 是怎么和 Eureka 整合的?"></a>📃Ribbon 是怎么和 Eureka 整合的?</h3><h3 id="📃声明式调用"><a href="#📃声明式调用" class="headerlink" title="📃声明式调用"></a>📃声明式调用</h3><h3 id="📃Feign"><a href="#📃Feign" class="headerlink" title="📃Feign"></a>📃Feign</h3><h3 id="📃Feign-实现原理?"><a href="#📃Feign-实现原理?" class="headerlink" title="📃Feign 实现原理?"></a>📃Feign 实现原理?</h3><h3 id="📃Feign-和-Ribbon-的区别?"><a href="#📃Feign-和-Ribbon-的区别?" class="headerlink" title="📃Feign 和 Ribbon 的区别?"></a>📃Feign 和 Ribbon 的区别?</h3><h3 id="📃Feign-是怎么和-Ribbon、Eureka-整合的?"><a href="#📃Feign-是怎么和-Ribbon、Eureka-整合的?" class="headerlink" title="📃Feign 是怎么和 Ribbon、Eureka 整合的?"></a>📃Feign 是怎么和 Ribbon、Eureka 整合的?</h3><h3 id="📃聊聊-Feign-重试机制?"><a href="#📃聊聊-Feign-重试机制?" class="headerlink" title="📃聊聊 Feign 重试机制?"></a>📃聊聊 Feign 重试机制?</h3><h3 id="📃服务保障"><a href="#📃服务保障" class="headerlink" title="📃服务保障"></a>📃服务保障</h3><h3 id="📃为什么要使用服务保障?"><a href="#📃为什么要使用服务保障?" class="headerlink" title="📃为什么要使用服务保障?"></a>📃为什么要使用服务保障?</h3><h3 id="📃Hystrix"><a href="#📃Hystrix" class="headerlink" title="📃Hystrix"></a>📃Hystrix</h3><h3 id="📃Hystrix-隔离策略?"><a href="#📃Hystrix-隔离策略?" class="headerlink" title="📃Hystrix 隔离策略?"></a>📃Hystrix 隔离策略?</h3><h3 id="📃聊聊-Hystrix-缓存机制?"><a href="#📃聊聊-Hystrix-缓存机制?" class="headerlink" title="📃聊聊 Hystrix 缓存机制?"></a>📃聊聊 Hystrix 缓存机制?</h3><h3 id="📃什么是-Hystrix-断路器?"><a href="#📃什么是-Hystrix-断路器?" class="headerlink" title="📃什么是 Hystrix 断路器?"></a>📃什么是 Hystrix 断路器?</h3><h3 id="📃什么是-Hystrix-服务降级?"><a href="#📃什么是-Hystrix-服务降级?" class="headerlink" title="📃什么是 Hystrix 服务降级?"></a>📃什么是 Hystrix 服务降级?</h3><h3 id="📃网关服务"><a href="#📃网关服务" class="headerlink" title="📃网关服务"></a>📃网关服务</h3><h3 id="📃为什么要网关服务?"><a href="#📃为什么要网关服务?" class="headerlink" title="📃为什么要网关服务?"></a>📃为什么要网关服务?</h3><h3 id="📃Zuul"><a href="#📃Zuul" class="headerlink" title="📃Zuul"></a>📃Zuul</h3><h3 id="📃Spring-Cloud-Gateway"><a href="#📃Spring-Cloud-Gateway" class="headerlink" title="📃Spring Cloud Gateway"></a>📃Spring Cloud Gateway</h3><h3 id="📃配置中心"><a href="#📃配置中心" class="headerlink" title="📃配置中心"></a>📃配置中心</h3><h3 id="📃Spring-Cloud-Config"><a href="#📃Spring-Cloud-Config" class="headerlink" title="📃Spring Cloud Config"></a>📃Spring Cloud Config</h3><h3 id="📃Apollo"><a href="#📃Apollo" class="headerlink" title="📃Apollo"></a>📃Apollo</h3><h3 id="📃链路追踪"><a href="#📃链路追踪" class="headerlink" title="📃链路追踪"></a>📃链路追踪</h3><h3 id="📃SkyWalking"><a href="#📃SkyWalking" class="headerlink" title="📃SkyWalking"></a>📃SkyWalking</h3><h3 id="📃Spring-Cloud-Sleuth"><a href="#📃Spring-Cloud-Sleuth" class="headerlink" title="📃Spring Cloud Sleuth"></a>📃Spring Cloud Sleuth</h3><hr><blockquote><h2 id="📚Dubbo"><a href="#📚Dubbo" class="headerlink" title="📚Dubbo"></a>📚Dubbo</h2></blockquote><h3 id="📃什么是-Dubbo"><a href="#📃什么是-Dubbo" class="headerlink" title="📃什么是 Dubbo"></a>📃什么是 Dubbo</h3><h3 id="📃什么是-RPC-RPC原理是什么"><a href="#📃什么是-RPC-RPC原理是什么" class="headerlink" title="📃什么是 RPC?RPC原理是什么"></a>📃什么是 RPC?RPC原理是什么</h3><h3 id="📃为什么要用-Dubbo"><a href="#📃为什么要用-Dubbo" class="headerlink" title="📃为什么要用 Dubbo"></a>📃为什么要用 Dubbo</h3><h3 id="📃Dubbo-的架构和工作原理"><a href="#📃Dubbo-的架构和工作原理" class="headerlink" title="📃Dubbo 的架构和工作原理"></a>📃Dubbo 的架构和工作原理</h3><h3 id="📃什么是SPI机制"><a href="#📃什么是SPI机制" class="headerlink" title="📃什么是SPI机制"></a>📃什么是SPI机制</h3><h3 id="📃Dubbo-的负载均衡策略"><a href="#📃Dubbo-的负载均衡策略" class="headerlink" title="📃Dubbo 的负载均衡策略"></a>📃Dubbo 的负载均衡策略</h3><h3 id="📃zookeeper宕机与dubbo直连的情况"><a href="#📃zookeeper宕机与dubbo直连的情况" class="headerlink" title="📃zookeeper宕机与dubbo直连的情况"></a>📃zookeeper宕机与dubbo直连的情况</h3><h3 id="📃dubbo的健壮性表现"><a href="#📃dubbo的健壮性表现" class="headerlink" title="📃dubbo的健壮性表现"></a>📃dubbo的健壮性表现</h3><hr><blockquote><h2 id="📚Redis"><a href="#📚Redis" class="headerlink" title="📚Redis"></a>📚Redis</h2></blockquote><h3 id="📃Redis-有什么优点"><a href="#📃Redis-有什么优点" class="headerlink" title="📃Redis 有什么优点"></a>📃Redis 有什么优点</h3><h3 id="📃Redis-有什么缺点"><a href="#📃Redis-有什么缺点" class="headerlink" title="📃Redis 有什么缺点"></a>📃Redis 有什么缺点</h3><h3 id="📃Redis-和-Memcached-的区别有哪些"><a href="#📃Redis-和-Memcached-的区别有哪些" class="headerlink" title="📃Redis 和 Memcached 的区别有哪些"></a>📃Redis 和 Memcached 的区别有哪些</h3><h3 id="📃请说说-Redis-的线程模型"><a href="#📃请说说-Redis-的线程模型" class="headerlink" title="📃请说说 Redis 的线程模型"></a>📃请说说 Redis 的线程模型</h3><h3 id="📃为什么-Redis-单线程模型也能效率这么高"><a href="#📃为什么-Redis-单线程模型也能效率这么高" class="headerlink" title="📃为什么 Redis 单线程模型也能效率这么高"></a>📃为什么 Redis 单线程模型也能效率这么高</h3><h3 id="📃Redis-是单线程的,如何提高多核-CPU-的利用率"><a href="#📃Redis-是单线程的,如何提高多核-CPU-的利用率" class="headerlink" title="📃Redis 是单线程的,如何提高多核 CPU 的利用率"></a>📃Redis 是单线程的,如何提高多核 CPU 的利用率</h3><h3 id="📃Redis-有几种持久化方式"><a href="#📃Redis-有几种持久化方式" class="headerlink" title="📃Redis 有几种持久化方式"></a>📃Redis 有几种持久化方式</h3><h3 id="📃Redis-有几种数据“过期”策略"><a href="#📃Redis-有几种数据“过期”策略" class="headerlink" title="📃Redis 有几种数据“过期”策略"></a>📃Redis 有几种数据“过期”策略</h3><h3 id="📃Redis-有哪几种数据“淘汰”策略"><a href="#📃Redis-有哪几种数据“淘汰”策略" class="headerlink" title="📃Redis 有哪几种数据“淘汰”策略"></a>📃Redis 有哪几种数据“淘汰”策略</h3><h3 id="📃如果有大量的-key-需要设置同一时间过期,一般需要注意什么"><a href="#📃如果有大量的-key-需要设置同一时间过期,一般需要注意什么" class="headerlink" title="📃如果有大量的 key 需要设置同一时间过期,一般需要注意什么"></a>📃如果有大量的 key 需要设置同一时间过期,一般需要注意什么</h3><h3 id="📃Redis-有哪些数据结构"><a href="#📃Redis-有哪些数据结构" class="headerlink" title="📃Redis 有哪些数据结构"></a>📃Redis 有哪些数据结构</h3><h3 id="📃聊聊-Redis-使用场景"><a href="#📃聊聊-Redis-使用场景" class="headerlink" title="📃聊聊 Redis 使用场景"></a>📃聊聊 Redis 使用场景</h3><h3 id="📃Redis-支持的-Java-客户端都有哪些"><a href="#📃Redis-支持的-Java-客户端都有哪些" class="headerlink" title="📃Redis 支持的 Java 客户端都有哪些"></a>📃Redis 支持的 Java 客户端都有哪些</h3><h3 id="📃如何使用-Redis-实现分布式锁"><a href="#📃如何使用-Redis-实现分布式锁" class="headerlink" title="📃如何使用 Redis 实现分布式锁"></a>📃如何使用 Redis 实现分布式锁</h3><h3 id="📃如何使用-Redis-实现分布式限流"><a href="#📃如何使用-Redis-实现分布式限流" class="headerlink" title="📃如何使用 Redis 实现分布式限流"></a>📃如何使用 Redis 实现分布式限流</h3><h3 id="📃如何使用-Redis-实现消息队列"><a href="#📃如何使用-Redis-实现消息队列" class="headerlink" title="📃如何使用 Redis 实现消息队列"></a>📃如何使用 Redis 实现消息队列</h3><h3 id="📃什么是-Redis-Pipelining"><a href="#📃什么是-Redis-Pipelining" class="headerlink" title="📃什么是 Redis Pipelining"></a>📃什么是 Redis Pipelining</h3><h3 id="📃什么是-Redis-事务"><a href="#📃什么是-Redis-事务" class="headerlink" title="📃什么是 Redis 事务"></a>📃什么是 Redis 事务</h3><h3 id="📃Redis-集群都有哪些方案"><a href="#📃Redis-集群都有哪些方案" class="headerlink" title="📃Redis 集群都有哪些方案"></a>📃Redis 集群都有哪些方案</h3><h3 id="📃什么是-Redis-主从同步"><a href="#📃什么是-Redis-主从同步" class="headerlink" title="📃什么是 Redis 主从同步"></a>📃什么是 Redis 主从同步</h3><h3 id="📃如何使用-Redis-Sentinel-实现高可用"><a href="#📃如何使用-Redis-Sentinel-实现高可用" class="headerlink" title="📃如何使用 Redis Sentinel 实现高可用"></a>📃如何使用 Redis Sentinel 实现高可用</h3><h3 id="📃如果使用-Redis-Cluster-实现高可用"><a href="#📃如果使用-Redis-Cluster-实现高可用" class="headerlink" title="📃如果使用 Redis Cluster 实现高可用"></a>📃如果使用 Redis Cluster 实现高可用</h3><h3 id="📃什么是-Redis-分区"><a href="#📃什么是-Redis-分区" class="headerlink" title="📃什么是 Redis 分区"></a>📃什么是 Redis 分区</h3><h3 id="📃Redis-有哪些重要的健康指标"><a href="#📃Redis-有哪些重要的健康指标" class="headerlink" title="📃Redis 有哪些重要的健康指标"></a>📃Redis 有哪些重要的健康指标</h3><h3 id="📃怎么优化-Redis-的内存占用"><a href="#📃怎么优化-Redis-的内存占用" class="headerlink" title="📃怎么优化 Redis 的内存占用"></a>📃怎么优化 Redis 的内存占用</h3><h3 id="📃Redis-常见的性能问题都有哪些?如何解决"><a href="#📃Redis-常见的性能问题都有哪些?如何解决" class="headerlink" title="📃Redis 常见的性能问题都有哪些?如何解决"></a>📃Redis 常见的性能问题都有哪些?如何解决</h3><h3 id="📃修改配置不重启-Redis-会实时生效吗"><a href="#📃修改配置不重启-Redis-会实时生效吗" class="headerlink" title="📃修改配置不重启 Redis 会实时生效吗"></a>📃修改配置不重启 Redis 会实时生效吗</h3><h3 id="📃缓存雪崩和缓存穿透问题解决方案"><a href="#📃缓存雪崩和缓存穿透问题解决方案" class="headerlink" title="📃缓存雪崩和缓存穿透问题解决方案"></a>📃缓存雪崩和缓存穿透问题解决方案</h3><h3 id="📃如何解决-Redis-的并发竞争-Key-问题"><a href="#📃如何解决-Redis-的并发竞争-Key-问题" class="headerlink" title="📃如何解决 Redis 的并发竞争 Key 问题"></a>📃如何解决 Redis 的并发竞争 Key 问题</h3><h3 id="📃如何保证缓存与数据库双写时的数据一致性"><a href="#📃如何保证缓存与数据库双写时的数据一致性" class="headerlink" title="📃如何保证缓存与数据库双写时的数据一致性"></a>📃如何保证缓存与数据库双写时的数据一致性</h3><hr><blockquote><h2 id="📚Netty"><a href="#📚Netty" class="headerlink" title="📚Netty"></a>📚Netty</h2></blockquote><h3 id="📃BIO-是什么"><a href="#📃BIO-是什么" class="headerlink" title="📃BIO 是什么"></a>📃BIO 是什么</h3><h3 id="📃NIO-是什么"><a href="#📃NIO-是什么" class="headerlink" title="📃NIO 是什么"></a>📃NIO 是什么</h3><h3 id="📃AIO-是什么"><a href="#📃AIO-是什么" class="headerlink" title="📃AIO 是什么"></a>📃AIO 是什么</h3><h3 id="📃BIO、NIO-有什么区别"><a href="#📃BIO、NIO-有什么区别" class="headerlink" title="📃BIO、NIO 有什么区别"></a>📃BIO、NIO 有什么区别</h3><h3 id="📃什么是-Netty"><a href="#📃什么是-Netty" class="headerlink" title="📃什么是 Netty"></a>📃什么是 Netty</h3><h3 id="📃为什么选择-Netty"><a href="#📃为什么选择-Netty" class="headerlink" title="📃为什么选择 Netty"></a>📃为什么选择 Netty</h3><h3 id="📃为什么说-Netty-使用简单"><a href="#📃为什么说-Netty-使用简单" class="headerlink" title="📃为什么说 Netty 使用简单"></a>📃为什么说 Netty 使用简单</h3><h3 id="📃说说业务中-Netty-的使用场景"><a href="#📃说说业务中-Netty-的使用场景" class="headerlink" title="📃说说业务中 Netty 的使用场景"></a>📃说说业务中 Netty 的使用场景</h3><h3 id="📃说说-Netty-如何实现高性能"><a href="#📃说说-Netty-如何实现高性能" class="headerlink" title="📃说说 Netty 如何实现高性能"></a>📃说说 Netty 如何实现高性能</h3><h3 id="📃Netty-的高性能如何体现"><a href="#📃Netty-的高性能如何体现" class="headerlink" title="📃Netty 的高性能如何体现"></a>📃Netty 的高性能如何体现</h3><h3 id="📃Netty-的高可靠如何体现"><a href="#📃Netty-的高可靠如何体现" class="headerlink" title="📃Netty 的高可靠如何体现"></a>📃Netty 的高可靠如何体现</h3><h3 id="📃Netty-的可扩展如何体现"><a href="#📃Netty-的可扩展如何体现" class="headerlink" title="📃Netty 的可扩展如何体现"></a>📃Netty 的可扩展如何体现</h3><h3 id="📃简单介绍-Netty-的核心组件"><a href="#📃简单介绍-Netty-的核心组件" class="headerlink" title="📃简单介绍 Netty 的核心组件"></a>📃简单介绍 Netty 的核心组件</h3><h3 id="📃说说-Netty-的逻辑架构"><a href="#📃说说-Netty-的逻辑架构" class="headerlink" title="📃说说 Netty 的逻辑架构"></a>📃说说 Netty 的逻辑架构</h3><h3 id="📃什么是-Reactor-模型"><a href="#📃什么是-Reactor-模型" class="headerlink" title="📃什么是 Reactor 模型"></a>📃什么是 Reactor 模型</h3><h3 id="📃请介绍-Netty-的线程模型"><a href="#📃请介绍-Netty-的线程模型" class="headerlink" title="📃请介绍 Netty 的线程模型"></a>📃请介绍 Netty 的线程模型</h3><h3 id="📃什么是业务线程池"><a href="#📃什么是业务线程池" class="headerlink" title="📃什么是业务线程池"></a>📃什么是业务线程池</h3><h3 id="📃TCP-粘包-拆包的原因?应该这么解决"><a href="#📃TCP-粘包-拆包的原因?应该这么解决" class="headerlink" title="📃TCP 粘包 / 拆包的原因?应该这么解决"></a>📃TCP 粘包 / 拆包的原因?应该这么解决</h3><h3 id="📃了解哪几种序列化协议"><a href="#📃了解哪几种序列化协议" class="headerlink" title="📃了解哪几种序列化协议"></a>📃了解哪几种序列化协议</h3><h3 id="📃Netty-的零拷贝实现"><a href="#📃Netty-的零拷贝实现" class="headerlink" title="📃Netty 的零拷贝实现"></a>📃Netty 的零拷贝实现</h3><h3 id="📃原生的-NIO-存在-Epoll-Bug-是什么?Netty-是怎么解决的"><a href="#📃原生的-NIO-存在-Epoll-Bug-是什么?Netty-是怎么解决的" class="headerlink" title="📃原生的 NIO 存在 Epoll Bug 是什么?Netty 是怎么解决的"></a>📃原生的 NIO 存在 Epoll Bug 是什么?Netty 是怎么解决的</h3><h3 id="📃什么是-Netty-空闲检测"><a href="#📃什么是-Netty-空闲检测" class="headerlink" title="📃什么是 Netty 空闲检测"></a>📃什么是 Netty 空闲检测</h3><h3 id="📃Netty-如何实现重连"><a href="#📃Netty-如何实现重连" class="headerlink" title="📃Netty 如何实现重连"></a>📃Netty 如何实现重连</h3><h3 id="📃Netty-自己实现的-ByteBuf-有什么优点"><a href="#📃Netty-自己实现的-ByteBuf-有什么优点" class="headerlink" title="📃Netty 自己实现的 ByteBuf 有什么优点"></a>📃Netty 自己实现的 ByteBuf 有什么优点</h3><h3 id="📃Netty-为什么要实现内存管理"><a href="#📃Netty-为什么要实现内存管理" class="headerlink" title="📃Netty 为什么要实现内存管理"></a>📃Netty 为什么要实现内存管理</h3><h3 id="📃Netty-如何实心内存管理"><a href="#📃Netty-如何实心内存管理" class="headerlink" title="📃Netty 如何实心内存管理"></a>📃Netty 如何实心内存管理</h3><h3 id="📃什么是-Netty-的内存泄露检测?是如何进行实现的"><a href="#📃什么是-Netty-的内存泄露检测?是如何进行实现的" class="headerlink" title="📃什么是 Netty 的内存泄露检测?是如何进行实现的"></a>📃什么是 Netty 的内存泄露检测?是如何进行实现的</h3><hr><blockquote><h2 id="📚高并发架构"><a href="#📚高并发架构" class="headerlink" title="📚高并发架构"></a>📚高并发架构</h2></blockquote><h3 id="📘消息队列"><a href="#📘消息队列" class="headerlink" title="📘消息队列"></a>📘消息队列</h3><h4 id="📃为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ-都有什么优点和缺点?"><a href="#📃为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ-都有什么优点和缺点?" class="headerlink" title="📃为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?"></a>📃为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?</h4><h4 id="📃如何保证消息队列的高可用?"><a href="#📃如何保证消息队列的高可用?" class="headerlink" title="📃如何保证消息队列的高可用?"></a>📃如何保证消息队列的高可用?</h4><h4 id="📃如何保证消息不被重复消费?(如何保证消息消费的幂等性)"><a href="#📃如何保证消息不被重复消费?(如何保证消息消费的幂等性)" class="headerlink" title="📃如何保证消息不被重复消费?(如何保证消息消费的幂等性)"></a>📃如何保证消息不被重复消费?(如何保证消息消费的幂等性)</h4><h4 id="📃如何保证消息的可靠性传输?(如何处理消息丢失的问题)"><a href="#📃如何保证消息的可靠性传输?(如何处理消息丢失的问题)" class="headerlink" title="📃如何保证消息的可靠性传输?(如何处理消息丢失的问题)"></a>📃如何保证消息的可靠性传输?(如何处理消息丢失的问题)</h4><h4 id="📃如何保证消息的顺序性?"><a href="#📃如何保证消息的顺序性?" class="headerlink" title="📃如何保证消息的顺序性?"></a>📃如何保证消息的顺序性?</h4><h4 id="📃如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?"><a href="#📃如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?" class="headerlink" title="📃如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?"></a>📃如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?</h4><h4 id="📃如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。"><a href="#📃如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。" class="headerlink" title="📃如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。"></a>📃如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。</h4><h3 id="📘搜索引擎"><a href="#📘搜索引擎" class="headerlink" title="📘搜索引擎"></a>📘搜索引擎</h3><h4 id="📃es-的分布式架构原理能说一下么(es-是如何实现分布式的啊)?"><a href="#📃es-的分布式架构原理能说一下么(es-是如何实现分布式的啊)?" class="headerlink" title="📃es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)?"></a>📃es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)?</h4><h4 id="📃es-写入数据的工作原理是什么啊?es-查询数据的工作原理是什么啊?底层的-lucene-介绍一下呗?倒排索引了解吗?"><a href="#📃es-写入数据的工作原理是什么啊?es-查询数据的工作原理是什么啊?底层的-lucene-介绍一下呗?倒排索引了解吗?" class="headerlink" title="📃es 写入数据的工作原理是什么啊?es 查询数据的工作原理是什么啊?底层的 lucene 介绍一下呗?倒排索引了解吗?"></a>📃es 写入数据的工作原理是什么啊?es 查询数据的工作原理是什么啊?底层的 lucene 介绍一下呗?倒排索引了解吗?</h4><h4 id="📃es-在数据量很大的情况下(数十亿级别)如何提高查询效率啊?"><a href="#📃es-在数据量很大的情况下(数十亿级别)如何提高查询效率啊?" class="headerlink" title="📃es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?"></a>📃es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?</h4><h4 id="📃es-生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?"><a href="#📃es-生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?" class="headerlink" title="📃es 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?"></a>📃es 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?</h4><h3 id="📘缓存"><a href="#📘缓存" class="headerlink" title="📘缓存"></a>📘缓存</h3><h4 id="📃在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?"><a href="#📃在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?" class="headerlink" title="📃在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?"></a>📃在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?</h4><h4 id="📃Redis-和-Memcached-有什么区别?Redis-的线程模型是什么?为什么单线程的-Redis-比多线程的-Memcached-效率要高得多?"><a href="#📃Redis-和-Memcached-有什么区别?Redis-的线程模型是什么?为什么单线程的-Redis-比多线程的-Memcached-效率要高得多?" class="headerlink" title="📃Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?"></a>📃Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?</h4><h4 id="📃Redis-都有哪些数据类型?分别在哪些场景下使用比较合适?"><a href="#📃Redis-都有哪些数据类型?分别在哪些场景下使用比较合适?" class="headerlink" title="📃Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?"></a>📃Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?</h4><h4 id="📃Redis-的过期策略都有哪些?手写一下-LRU-代码实现?"><a href="#📃Redis-的过期策略都有哪些?手写一下-LRU-代码实现?" class="headerlink" title="📃Redis 的过期策略都有哪些?手写一下 LRU 代码实现?"></a>📃Redis 的过期策略都有哪些?手写一下 LRU 代码实现?</h4><h4 id="📃如何保证-Redis-高并发、高可用?Redis-的主从复制原理能介绍一下么?Redis-的哨兵原理能介绍一下么?"><a href="#📃如何保证-Redis-高并发、高可用?Redis-的主从复制原理能介绍一下么?Redis-的哨兵原理能介绍一下么?" class="headerlink" title="📃如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?"></a>📃如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?</h4><h4 id="📃Redis-的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?"><a href="#📃Redis-的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?" class="headerlink" title="📃Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?"></a>📃Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?</h4><h4 id="📃Redis-集群模式的工作原理能说一下么?在集群模式下,Redis-的-key-是如何寻址的?分布式寻址都有哪些算法?了解一致性-hash-算法吗?如何动态增加和删除一个节点?"><a href="#📃Redis-集群模式的工作原理能说一下么?在集群模式下,Redis-的-key-是如何寻址的?分布式寻址都有哪些算法?了解一致性-hash-算法吗?如何动态增加和删除一个节点?" class="headerlink" title="📃Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?"></a>📃Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?</h4><h4 id="📃了解什么是-redis-的雪崩、穿透和击穿?Redis-崩溃之后会怎么样?系统该如何应对这种情况?如何处理-Redis-的穿透?"><a href="#📃了解什么是-redis-的雪崩、穿透和击穿?Redis-崩溃之后会怎么样?系统该如何应对这种情况?如何处理-Redis-的穿透?" class="headerlink" title="📃了解什么是 redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?"></a>📃了解什么是 redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?</h4><h4 id="📃如何保证缓存与数据库的双写一致性?"><a href="#📃如何保证缓存与数据库的双写一致性?" class="headerlink" title="📃如何保证缓存与数据库的双写一致性?"></a>📃如何保证缓存与数据库的双写一致性?</h4><h4 id="📃Redis-的并发竞争问题是什么?如何解决这个问题?了解-Redis-事务的-CAS-方案吗?"><a href="#📃Redis-的并发竞争问题是什么?如何解决这个问题?了解-Redis-事务的-CAS-方案吗?" class="headerlink" title="📃Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?"></a>📃Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?</h4><h4 id="📃生产环境中的-Redis-是怎么部署的?"><a href="#📃生产环境中的-Redis-是怎么部署的?" class="headerlink" title="📃生产环境中的 Redis 是怎么部署的?"></a>📃生产环境中的 Redis 是怎么部署的?</h4><h3 id="📘分库分表"><a href="#📘分库分表" class="headerlink" title="📘分库分表"></a>📘分库分表</h3><h4 id="📃为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?"><a href="#📃为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?" class="headerlink" title="📃为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?"></a>📃为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?</h4><h4 id="📃现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?"><a href="#📃现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?" class="headerlink" title="📃现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?"></a>📃现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?</h4><h4 id="📃如何设计可以动态扩容缩容的分库分表方案?"><a href="#📃如何设计可以动态扩容缩容的分库分表方案?" class="headerlink" title="📃如何设计可以动态扩容缩容的分库分表方案?"></a>📃如何设计可以动态扩容缩容的分库分表方案?</h4><h4 id="📃分库分表之后,id-主键如何处理?"><a href="#📃分库分表之后,id-主键如何处理?" class="headerlink" title="📃分库分表之后,id 主键如何处理?"></a>📃分库分表之后,id 主键如何处理?</h4><h3 id="📘读写分离"><a href="#📘读写分离" class="headerlink" title="📘读写分离"></a>📘读写分离</h3><h4 id="📃如何实现-MySQL-的读写分离?MySQL-主从复制原理是啥?如何解决-MySQL-主从同步的延时问题?"><a href="#📃如何实现-MySQL-的读写分离?MySQL-主从复制原理是啥?如何解决-MySQL-主从同步的延时问题?" class="headerlink" title="📃如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?"></a>📃如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?</h4><h3 id="📘高并发系统"><a href="#📘高并发系统" class="headerlink" title="📘高并发系统"></a>📘高并发系统</h3><h4 id="📃如何设计一个高并发系统?"><a href="#📃如何设计一个高并发系统?" class="headerlink" title="📃如何设计一个高并发系统?"></a>📃如何设计一个高并发系统?</h4><hr><blockquote><h2 id="📚分布式架构"><a href="#📚分布式架构" class="headerlink" title="📚分布式架构"></a>📚分布式架构</h2></blockquote><h3 id="📘分布式服务框架"><a href="#📘分布式服务框架" class="headerlink" title="📘分布式服务框架"></a>📘分布式服务框架</h3><h4 id="📃说一下-Dubbo-的工作原理?注册中心挂了可以继续通信吗?"><a href="#📃说一下-Dubbo-的工作原理?注册中心挂了可以继续通信吗?" class="headerlink" title="📃说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?"></a>📃说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?</h4><h4 id="📃Dubbo-支持哪些序列化协议?说一下-Hessian-的数据结构?PB-知道吗?为什么-PB-的效率是最高的?"><a href="#📃Dubbo-支持哪些序列化协议?说一下-Hessian-的数据结构?PB-知道吗?为什么-PB-的效率是最高的?" class="headerlink" title="📃Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?"></a>📃Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?</h4><h4 id="📃Dubbo-负载均衡策略和集群容错策略都有哪些?动态代理策略呢?"><a href="#📃Dubbo-负载均衡策略和集群容错策略都有哪些?动态代理策略呢?" class="headerlink" title="📃Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?"></a>📃Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?</h4><h4 id="📃Dubbo-的-spi-思想是什么?"><a href="#📃Dubbo-的-spi-思想是什么?" class="headerlink" title="📃Dubbo 的 spi 思想是什么?"></a>📃Dubbo 的 spi 思想是什么?</h4><h4 id="📃如何基于-Dubbo-进行服务治理、服务降级、失败重试以及超时重试?"><a href="#📃如何基于-Dubbo-进行服务治理、服务降级、失败重试以及超时重试?" class="headerlink" title="📃如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?"></a>📃如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?</h4><h4 id="📃分布式服务接口的幂等性如何设计(比如不能重复扣款)?"><a href="#📃分布式服务接口的幂等性如何设计(比如不能重复扣款)?" class="headerlink" title="📃分布式服务接口的幂等性如何设计(比如不能重复扣款)?"></a>📃分布式服务接口的幂等性如何设计(比如不能重复扣款)?</h4><h4 id="📃分布式服务接口请求的顺序性如何保证?"><a href="#📃分布式服务接口请求的顺序性如何保证?" class="headerlink" title="📃分布式服务接口请求的顺序性如何保证?"></a>📃分布式服务接口请求的顺序性如何保证?</h4><h4 id="📃如何自己设计一个类似-Dubbo-的-RPC-框架?"><a href="#📃如何自己设计一个类似-Dubbo-的-RPC-框架?" class="headerlink" title="📃如何自己设计一个类似 Dubbo 的 RPC 框架?"></a>📃如何自己设计一个类似 Dubbo 的 RPC 框架?</h4><h3 id="📘分布式锁"><a href="#📘分布式锁" class="headerlink" title="📘分布式锁"></a>📘分布式锁</h3><h4 id="📃Zookeeper-都有哪些应用场景?"><a href="#📃Zookeeper-都有哪些应用场景?" class="headerlink" title="📃Zookeeper 都有哪些应用场景?"></a>📃Zookeeper 都有哪些应用场景?</h4><h4 id="📃使用-Redis-如何设计分布式锁?使用-Zookeeper-来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?"><a href="#📃使用-Redis-如何设计分布式锁?使用-Zookeeper-来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?" class="headerlink" title="📃使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?"></a>📃使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?</h4><h3 id="📘分布式事务"><a href="#📘分布式事务" class="headerlink" title="📘分布式事务"></a>📘分布式事务</h3><h4 id="📃分布式事务了解吗?你们如何解决分布式事务问题的?TCC-如果出现网络连不通怎么办?XA-的一致性如何保证?"><a href="#📃分布式事务了解吗?你们如何解决分布式事务问题的?TCC-如果出现网络连不通怎么办?XA-的一致性如何保证?" class="headerlink" title="📃分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?"></a>📃分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?</h4><h3 id="📘分布式会话"><a href="#📘分布式会话" class="headerlink" title="📘分布式会话"></a>📘分布式会话</h3><h4 id="📃集群部署时的分布式-Session-如何实现?"><a href="#📃集群部署时的分布式-Session-如何实现?" class="headerlink" title="📃集群部署时的分布式 Session 如何实现?"></a>📃集群部署时的分布式 Session 如何实现?</h4><hr><blockquote><h2 id="📚高可用架构"><a href="#📚高可用架构" class="headerlink" title="📚高可用架构"></a>📚高可用架构</h2></blockquote><h3 id="📃Hystrix-介绍"><a href="#📃Hystrix-介绍" class="headerlink" title="📃Hystrix 介绍"></a>📃Hystrix 介绍</h3><h3 id="📃电商网站详情页系统架构"><a href="#📃电商网站详情页系统架构" class="headerlink" title="📃电商网站详情页系统架构"></a>📃电商网站详情页系统架构</h3><h3 id="📃Hystrix-线程池技术实现资源隔离"><a href="#📃Hystrix-线程池技术实现资源隔离" class="headerlink" title="📃Hystrix 线程池技术实现资源隔离"></a>📃Hystrix 线程池技术实现资源隔离</h3><h3 id="📃Hystrix-信号量机制实现资源隔离"><a href="#📃Hystrix-信号量机制实现资源隔离" class="headerlink" title="📃Hystrix 信号量机制实现资源隔离"></a>📃Hystrix 信号量机制实现资源隔离</h3><h3 id="📃Hystrix-隔离策略细粒度控制"><a href="#📃Hystrix-隔离策略细粒度控制" class="headerlink" title="📃Hystrix 隔离策略细粒度控制"></a>📃Hystrix 隔离策略细粒度控制</h3><h3 id="📃深入-Hystrix-执行时内部原理"><a href="#📃深入-Hystrix-执行时内部原理" class="headerlink" title="📃深入 Hystrix 执行时内部原理"></a>📃深入 Hystrix 执行时内部原理</h3><h3 id="📃基于-request-cache-请求缓存技术优化批量商品数据查询接口"><a href="#📃基于-request-cache-请求缓存技术优化批量商品数据查询接口" class="headerlink" title="📃基于 request cache 请求缓存技术优化批量商品数据查询接口"></a>📃基于 request cache 请求缓存技术优化批量商品数据查询接口</h3><h3 id="📃基于本地缓存的-fallback-降级机制"><a href="#📃基于本地缓存的-fallback-降级机制" class="headerlink" title="📃基于本地缓存的 fallback 降级机制"></a>📃基于本地缓存的 fallback 降级机制</h3><h3 id="📃深入-Hystrix-断路器执行原理"><a href="#📃深入-Hystrix-断路器执行原理" class="headerlink" title="📃深入 Hystrix 断路器执行原理"></a>📃深入 Hystrix 断路器执行原理</h3><h3 id="📃深入-Hystrix-线程池隔离与接口限流"><a href="#📃深入-Hystrix-线程池隔离与接口限流" class="headerlink" title="📃深入 Hystrix 线程池隔离与接口限流"></a>📃深入 Hystrix 线程池隔离与接口限流</h3><h3 id="📃基于-timeout-机制为服务接口调用超时提供安全保护"><a href="#📃基于-timeout-机制为服务接口调用超时提供安全保护" class="headerlink" title="📃基于 timeout 机制为服务接口调用超时提供安全保护"></a>📃基于 timeout 机制为服务接口调用超时提供安全保护</h3><h3 id="📃如何设计一个高可用系统?"><a href="#📃如何设计一个高可用系统?" class="headerlink" title="📃如何设计一个高可用系统?"></a>📃如何设计一个高可用系统?</h3><h3 id="📃如何限流?在工作中是怎么做的?说一下具体的实现?"><a href="#📃如何限流?在工作中是怎么做的?说一下具体的实现?" class="headerlink" title="📃如何限流?在工作中是怎么做的?说一下具体的实现?"></a>📃如何限流?在工作中是怎么做的?说一下具体的实现?</h3><h3 id="📃如何进行熔断?"><a href="#📃如何进行熔断?" class="headerlink" title="📃如何进行熔断?"></a>📃如何进行熔断?</h3><h3 id="📃熔断框架都有哪些?具体实现原理知道吗?"><a href="#📃熔断框架都有哪些?具体实现原理知道吗?" class="headerlink" title="📃熔断框架都有哪些?具体实现原理知道吗?"></a>📃熔断框架都有哪些?具体实现原理知道吗?</h3><h3 id="📃熔断框架如何做技术选型?选用-Sentinel-还是-Hystrix?"><a href="#📃熔断框架如何做技术选型?选用-Sentinel-还是-Hystrix?" class="headerlink" title="📃熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?"></a>📃熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?</h3><h3 id="📃如何进行降级?"><a href="#📃如何进行降级?" class="headerlink" title="📃如何进行降级?"></a>📃如何进行降级?</h3><hr><blockquote><h2 id="📚微服务架构"><a href="#📚微服务架构" class="headerlink" title="📚微服务架构"></a>📚微服务架构</h2></blockquote><h3 id="📃关于微服务架构的描述"><a href="#📃关于微服务架构的描述" class="headerlink" title="📃关于微服务架构的描述"></a>📃关于微服务架构的描述</h3><h3 id="📃从单体式架构迁移到微服务架构"><a href="#📃从单体式架构迁移到微服务架构" class="headerlink" title="📃从单体式架构迁移到微服务架构"></a>📃从单体式架构迁移到微服务架构</h3><h3 id="📃微服务的事件驱动数据管理"><a href="#📃微服务的事件驱动数据管理" class="headerlink" title="📃微服务的事件驱动数据管理"></a>📃微服务的事件驱动数据管理</h3><h3 id="📃选择微服务部署策略"><a href="#📃选择微服务部署策略" class="headerlink" title="📃选择微服务部署策略"></a>📃选择微服务部署策略</h3><h3 id="📃什么是微服务?微服务之间是如何独立通讯的?"><a href="#📃什么是微服务?微服务之间是如何独立通讯的?" class="headerlink" title="📃什么是微服务?微服务之间是如何独立通讯的?"></a>📃什么是微服务?微服务之间是如何独立通讯的?</h3><h3 id="📃Spring-Cloud-和-Dubbo-有哪些区别?"><a href="#📃Spring-Cloud-和-Dubbo-有哪些区别?" class="headerlink" title="📃Spring Cloud 和 Dubbo 有哪些区别?"></a>📃Spring Cloud 和 Dubbo 有哪些区别?</h3><h3 id="📃Spring-Boot-和-Spring-Cloud,谈谈你对它们的理解?"><a href="#📃Spring-Boot-和-Spring-Cloud,谈谈你对它们的理解?" class="headerlink" title="📃Spring Boot 和 Spring Cloud,谈谈你对它们的理解?"></a>📃Spring Boot 和 Spring Cloud,谈谈你对它们的理解?</h3><h3 id="📃什么是服务熔断?什么是服务降级?"><a href="#📃什么是服务熔断?什么是服务降级?" class="headerlink" title="📃什么是服务熔断?什么是服务降级?"></a>📃什么是服务熔断?什么是服务降级?</h3><h3 id="📃微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑?"><a href="#📃微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑?" class="headerlink" title="📃微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑?"></a>📃微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑?</h3><h3 id="📃你所知道的微服务技术栈都有哪些?"><a href="#📃你所知道的微服务技术栈都有哪些?" class="headerlink" title="📃你所知道的微服务技术栈都有哪些?"></a>📃你所知道的微服务技术栈都有哪些?</h3><h3 id="📃微服务治理策略"><a href="#📃微服务治理策略" class="headerlink" title="📃微服务治理策略"></a>📃微服务治理策略</h3><h3 id="📃Eureka-和-Zookeeper-都可以提供服务注册与发现的功能,它们有什么区别?"><a href="#📃Eureka-和-Zookeeper-都可以提供服务注册与发现的功能,它们有什么区别?" class="headerlink" title="📃Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别?"></a>📃Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别?</h3><hr><blockquote><h2 id="📚微服务架构-1"><a href="#📚微服务架构-1" class="headerlink" title="📚微服务架构"></a>📚微服务架构</h2></blockquote><h3 id="📃如何从大量的-URL-中找出相同的-URL?"><a href="#📃如何从大量的-URL-中找出相同的-URL?" class="headerlink" title="📃如何从大量的 URL 中找出相同的 URL?"></a>📃如何从大量的 URL 中找出相同的 URL?</h3><h3 id="📃如何从大量数据中找出高频词?"><a href="#📃如何从大量数据中找出高频词?" class="headerlink" title="📃如何从大量数据中找出高频词?"></a>📃如何从大量数据中找出高频词?</h3><h3 id="📃如何找出某一天访问百度网站最多的-IP?"><a href="#📃如何找出某一天访问百度网站最多的-IP?" class="headerlink" title="📃如何找出某一天访问百度网站最多的 IP?"></a>📃如何找出某一天访问百度网站最多的 IP?</h3><h3 id="📃如何在大量的数据中找出不重复的整数?"><a href="#📃如何在大量的数据中找出不重复的整数?" class="headerlink" title="📃如何在大量的数据中找出不重复的整数?"></a>📃如何在大量的数据中找出不重复的整数?</h3><h3 id="📃如何在大量的数据中判断一个数是否存在?"><a href="#📃如何在大量的数据中判断一个数是否存在?" class="headerlink" title="📃如何在大量的数据中判断一个数是否存在?"></a>📃如何在大量的数据中判断一个数是否存在?</h3><h3 id="📃如何查询最热门的查询串?"><a href="#📃如何查询最热门的查询串?" class="headerlink" title="📃如何查询最热门的查询串?"></a>📃如何查询最热门的查询串?</h3><h3 id="📃如何统计不同电话号码的个数?"><a href="#📃如何统计不同电话号码的个数?" class="headerlink" title="📃如何统计不同电话号码的个数?"></a>📃如何统计不同电话号码的个数?</h3><h3 id="📃如何从-5-亿个数中找出中位数?"><a href="#📃如何从-5-亿个数中找出中位数?" class="headerlink" title="📃如何从 5 亿个数中找出中位数?"></a>📃如何从 5 亿个数中找出中位数?</h3><h3 id="📃如何按照-query-的频度排序?"><a href="#📃如何按照-query-的频度排序?" class="headerlink" title="📃如何按照 query 的频度排序?"></a>📃如何按照 query 的频度排序?</h3><h3 id="📃如何找出排名前-500-的数?"><a href="#📃如何找出排名前-500-的数?" class="headerlink" title="📃如何找出排名前 500 的数?"></a>📃如何找出排名前 500 的数?</h3><hr><blockquote><h2 id="📚算法"><a href="#📚算法" class="headerlink" title="📚算法"></a>📚算法</h2></blockquote><hr><blockquote><h2 id="📚计算机网络"><a href="#📚计算机网络" class="headerlink" title="📚计算机网络"></a>📚计算机网络</h2></blockquote><h3 id="📃TCP、UDP-协议的区别"><a href="#📃TCP、UDP-协议的区别" class="headerlink" title="📃TCP、UDP 协议的区别"></a>📃TCP、UDP 协议的区别</h3><h3 id="📃在浏览器中输入url地址到显示页面的过程"><a href="#📃在浏览器中输入url地址到显示页面的过程" class="headerlink" title="📃在浏览器中输入url地址到显示页面的过程"></a>📃在浏览器中输入url地址到显示页面的过程</h3><h3 id="📃HTTP长连接、短连接"><a href="#📃HTTP长连接、短连接" class="headerlink" title="📃HTTP长连接、短连接"></a>📃HTTP长连接、短连接</h3><h3 id="📃TCP-三次握手和四次挥手"><a href="#📃TCP-三次握手和四次挥手" class="headerlink" title="📃TCP 三次握手和四次挥手"></a>📃TCP 三次握手和四次挥手</h3><h3 id="📃TCP窗口滑动和流量控制"><a href="#📃TCP窗口滑动和流量控制" class="headerlink" title="📃TCP窗口滑动和流量控制"></a>📃TCP窗口滑动和流量控制</h3><hr><blockquote><h2 id="📚设计模式"><a href="#📚设计模式" class="headerlink" title="📚设计模式"></a>📚设计模式</h2></blockquote><hr><blockquote><h2 id="📚生产实践"><a href="#📚生产实践" class="headerlink" title="📚生产实践"></a>📚生产实践</h2></blockquote>]]></content>
<categories>
<category> Java </category>
<category> 面试 </category>
</categories>
<tags>
<tag> Java </tag>
<tag> 面试 </tag>
</tags>
</entry>
</search>