-
Notifications
You must be signed in to change notification settings - Fork 2
/
search.xml
2103 lines (2061 loc) · 254 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>2019 年终总结</title>
<url>/final2019/</url>
<content><![CDATA[<p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20200104204559.jpg" class="full-class"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>很久不见,甚是想念。</p>
<p>解释下没更新的原因,一是秋招找工作,从深圳回来后就准备秋招然后也变懒了;二是因为没有 Offer,也便没有了更新的心情。</p>
<a id="more"></a>
<h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><h2 id="工作"><a href="#工作" class="headerlink" title="工作"></a>工作</h2><p>如果掐点算的话,在 <code>2019-12-31 24:00:00</code> 之前我只有京东的 Offer,有道的 Offer 在 <code>2020-1-3</code> 才给我。</p>
<p>大体来讲,几乎一整年在准备未来,找实习、复习、准备挑战杯等等……</p>
<p>春招惨淡无光,面试简直是傻白甜,问啥啥不会,双非渣本没有项目经验,谁都不要……最后感谢随手科技选择了我,让我学到了许多东西。之后八月底告别了一起实习小伙伴,独自踏上了秋招的路。</p>
<p>整个秋招不是很顺利,九月底面试了很多,有名的诸如京东、58 安居客、顺丰科技,没名的顺网科技、贝贝、连连支付等等……有些给了 Offer,也有些没给,拒掉的多半是薪资劝退,名气太小,接受的也只有京东。</p>
<p>灰暗的第三季和第四季,也终于在 2020 年初迎来了曙光。</p>
<h2 id="生活"><a href="#生活" class="headerlink" title="生活"></a>生活</h2><p>似乎除了求职,其他并没有什么可以说的。</p>
<p>哦对了,年初定投的指数基金,已经投进去 700 多,收益 100+,我也不知道是赚了亏了,来年且看吧。</p>
<p>攒下来的钱倒有不少,实习打拼的,父母给的,项目报销的余款,勤工俭学赚的等。不过也就塞一下牙缝……<br>计划再贴些钱三月份买个 Mac2020 吧</p>
<h2 id="学习"><a href="#学习" class="headerlink" title="学习"></a>学习</h2><p>大三下学期差点挂科,感谢云计算老师在关键时刻拉了我一把 61 分飘过。</p>
<p>差点挂科原因就很简单了,天天准备面试,既没 Offer,成绩又不好,同时还要准备挑战杯省,心力憔悴。</p>
<p>说到挑战杯省赛,真的是坑。看的是创意,还有证明报道。那些证明报道从来哪呢,你们应该可以猜到。但是我就是一个打工的,我有什么办法呢,也只好照做。所以至今贴进去的 1800 元还没报销下来……如果再给我一次机会,我的头一定会摇的跟拨浪鼓一样。</p>
<h1 id="展望"><a href="#展望" class="headerlink" title="展望"></a>展望</h1><p>去年的年终总结说输出博客每周两到三篇,手动滑稽……</p>
<p>不立什么 flag 了</p>
<ul>
<li>未来不出意外会开一个微信公众号</li>
<li>博客每周一到两篇吧哈哈哈哈</li>
</ul>
]]></content>
<categories>
<category>总结</category>
</categories>
<tags>
<tag>总结</tag>
<tag>收获</tag>
<tag>未来</tag>
</tags>
</entry>
<entry>
<title>Linux 下 IDEA 的 Ctrl+Alt+S</title>
<url>/idea-ctrl-alt-s/</url>
<content><![CDATA[<p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190917175139.jpg" class="full-class"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>这是个困扰我一年多的问题,今天终于解决了……<br><a id="more"></a></p>
<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p>一年前将主系统换成 Arch Linux 后,其他一切正常就是 IDEA 的打开设置的快捷键 ctrl+alt+s 失效,让我很是头疼。虽然不是很重要,但是对于我这种强迫症来说别提多难受了……</p>
<p>我曾多次在设置里的快捷键查找 Ctrl+Alt+S,每次无功而返。</p>
<h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>今天在群里闲聊到 Linux 下 IDEA 的快捷键问题,一位大佬就发了一张解决方案的截图给了我新的思路。</p>
<p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190917172104.jpg" alt></p>
<p>Linux 万物皆是文件</p>
<p>倾向于系统文件快捷键的占用,所以我下载了 dconf-editor 去更改快捷键的文件。不幸的是看上去并没有什么问题,文件显示层叠窗口的快捷键并没有被设置。打开搜狗输入法以及 Konsole 也都没有发现 Ctrl+Alt+S 的痕迹,那为什么会被占用呢?百思不得其解……</p>
<p>想起了之前加入 TG 上的 Arch Linux 官方群组,就去上面将问题描述了一遍。一分钟后,大佬告诉我是因为 fcitx 的全局快捷键,Ctrl+Alt+S 被设置成保存所有设置和历史。</p>
<p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190917173543.png" alt></p>
<p>收到回复后,我一想那简单啊,修改配置文件不就完了……<br>天真的把 S 改成 Q,重新登录发现并没有什么卵用。定睛一看前面还有 # 号(吐血.jpg)……改成下面这样重启登录就解决了。</p>
<p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190917174122.png" alt></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><ol>
<li>gnome 可以下载 dconf-editor 去查找快捷键有没有被默认系统设置占用,kde 只需在设置里查找是否有重复的快捷键即可</li>
<li>看看是不是因为输入法的框架是 fctix,是的话修改 fctix 的配置文件,将保存所有设置的快捷键改成其他键位</li>
<li>直接改 IDEA 的快键键不好么???</li>
</ol>
<p>这个快捷键终于解决了,让我心情很舒畅!!!希望今后能帮助到其他人。</p>
]]></content>
<categories>
<category>日常记录</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>排错</tag>
<tag>踩坑</tag>
<tag>IDEA</tag>
</tags>
</entry>
<entry>
<title>第一次线上 Bug 献给了 ThreadLocal</title>
<url>/threadloacl/</url>
<content><![CDATA[<p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190901142031.jpeg
" class="full-class"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>捂脸.jpg</p>
<a id="more"></a>
<h2 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h2><p><a href="https://yi-yun.github.io/Mybatis-Interceptor/">这篇博文</a>说到的用了 Mybatis 做拦截器来记录产品以及运营变更后台内容的操作信息。本来直接在后台管理的模块操作就可以了,但是有个要求是记录操作前后的信息……因为公司大都是微服务采用的单数据源,操作人信息是在 A 服务,变更前后的信息是在 B 服务。</p>
<p>一开始接到任务的时候就感觉不好搞,这不是坑爹嘛直接拦截 Controller 的日志多好(小声)</p>
<p>经过与大佬的深入探讨,有两个技术方案。这里为了长话短说,就只讲最终实现的技术方案。</p>
<p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190901132722.png" alt></p>
<p>我需要在 RPC API 中加个字段来传递操作人的真实信息以及客户端 IP,B 服务接收到后通过 ThreadLocal 传递到 DAO 层,最后拦截器先去数据库查询出旧值,然后执行原来的方法,最后拼接旧值以及新值,日志入库。</p>
<p>这个方案很完美有没有,嗯如果没有 Bug 就很完美。</p>
<h2 id="开发"><a href="#开发" class="headerlink" title="开发"></a>开发</h2><p>经过几天的开发、提测、测试通过、上线了。</p>
<p>上线半小时,导师通过 kibana 观察线上的日志发现并没有什么问题。看一眼线上的数据库,卧槽记录了几张不用记录的表,操作人信息怎么都是一样的,功能倒是写的没问题,就是似乎将所有业务的增删改特定的方法都记录了……</p>
<h2 id="排错"><a href="#排错" class="headerlink" title="排错"></a>排错</h2><p>下面是段很有意思的对话</p>
<p>我:为什么能获取到操作人的信息,如果 A 系统没带过来的话,B 中心服务所有的操作为什么会带有脏信息……<br>导师:你这写的有问题啊?<br>我:是啊,OS:代码不都给你 review 过了么(逃)<br>导师:你是不是用了 ThreadLocal<br>我小鸡啄米似的点头<br>导师:讲道理线程调用结束了 ThreadLocal 不就被回收了么?<br>我:是啊是啊</p>
<p>随后导师看着逐渐增加的日志记录表陷入了沉思,我也陷入了思考……</p>
<p>突然灵光乍现,因为没有在拦截器的拦截方法里 remove 掉 ThreadLocal,肯定有个线程池调用了,那为什么有线程池呢?哦艹,Dubbo 默认有线程池……我没有 remove 掉,管理操作后台如果有操作可能会污染到所有线程。</p>
<h2 id="复现"><a href="#复现" class="headerlink" title="复现"></a>复现</h2><p>因为只是增加了记录日志数量,所以大佬们似乎并不急于修复数据让我先自己在本地复现一下确定原因。<br>我把 Dubbo 线程池的数目调成 1, DeBug 模拟登录复现了场景。Dubbo 通过线程池来处理提供 provider 的服务,如果我没有 remove 掉的话会导致相关信息一直在,GC 回收时会产生内存泄漏</p>
<h2 id="修复"><a href="#修复" class="headerlink" title="修复"></a>修复</h2><p>ThreadLocal remove 掉需要用 finally 代码块,侵入性太强,经过短暂的讨论决定新版本用注解add 以及 remove 掉 ThreadLocal,暂时的解决方案是注释掉拦截器。</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>那天加班到了九点,第一次遇到线上的 bug 有点猝不及防。</p>
<p>虽然我知道 ThreadLocal 需要 remove,但是想当然以为没有线程池调用就不会有问题。<br>是啊没有线程池调用是没啥问题,但最骚的是忽略了 Dubbo 内部有个默认的线程池去提供服务。有了理论基础还是要有实践经验,不然容易出问题。</p>
<p>庆幸我是实习生,不然绩效就是 C 了(手动狗头)</p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>实习</tag>
<tag>排错</tag>
<tag>第一次</tag>
<tag>Bug</tag>
</tags>
</entry>
<entry>
<title>人人都能拥有的广告位</title>
<url>/google-ads/</url>
<content><![CDATA[<p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190813211435.jpg" class="full-class"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>此篇是本博客引入 Google 广告的过程<br>算是教程吧<br>开通完之后记得把广告插件关了看下效果<br><a id="more"></a></p>
<h2 id="准备"><a href="#准备" class="headerlink" title="准备"></a>准备</h2><ul>
<li>一个稳定的 VPN<br>不稳定也行,注册卡顿你不介意就行……</li>
<li>一个博客<br>要原创几篇文章,我猜是人工审核吧</li>
<li>一个 Google 账号</li>
</ul>
<h2 id="申请开通"><a href="#申请开通" class="headerlink" title="申请开通"></a>申请开通</h2><ol>
<li><a href="https://www.google.cn/adsense/start/#/?modal_active=none" target="_blank" rel="noopener">传送门</a></li>
<li>将谷歌提供的代码扔在 head 里,因为我的博客是 <code>hexo v6.0</code>,所以将验证代码扔在了 <code>themes/next/layout/_custom/head.swig</code> 里面,这样之后主题升级会更加平滑</li>
<li>验证完后,等两三天,审核通过就可以了</li>
</ol>
<p>友情提醒:新站不容易过审</p>
<h2 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h2><h3 id="自动广告"><a href="#自动广告" class="headerlink" title="自动广告"></a>自动广告</h3><p>没玩过,据说是 Google 爸爸根据网站长宽比投放的,投放率很低。</p>
<h3 id="广告单元"><a href="#广告单元" class="headerlink" title="广告单元"></a>广告单元</h3><p>这是今天要讲的关键部分,点击想要投放的广告样式后会获得相应的代码。</p>
<p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190813201757.png" alt></p>
<h4 id="展示广告"><a href="#展示广告" class="headerlink" title="展示广告"></a>展示广告</h4><p>将代码插入到 <code>themes/next/layout/_macro/sidebar.swig</code> 文件中 <code><div class=”sidebar-inner”> </div></code> 标签包裹着的最下部。</p>
<h4 id="信息流广告"><a href="#信息流广告" class="headerlink" title="信息流广告"></a>信息流广告</h4><p>类似知乎推荐、QQ 空间信息流式中的广告,扔太多地方不好就没研究了。</p>
<h4 id="文章内嵌广告"><a href="#文章内嵌广告" class="headerlink" title="文章内嵌广告"></a>文章内嵌广告</h4><p>可以放在文章尾部,代码往 <code>themes/next/layout/_macro/post.swig</code> 一扔就行</p>
<p>PS:不过得注意位置我扔在这里,大佬们可根据自己博客在浏览器 F12 选位置嵌代码。<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/TIM%E6%88%AA%E5%9B%BE20190814092129.png" alt></p>
<p>后来发现内嵌广告太大,就改成了展示广告的横幅版了……</p>
<h2 id="最后"><a href="#最后" class="headerlink" title="最后"></a>最后</h2><p>一般 Chrome 或者 FireFox 都会装广告屏蔽插件,手机浏览器应该不会被屏蔽,所以一般也不会有人点。(那为啥要装?<del>人总要有梦想,万一有人问了呢</del>)</p>
<p>游客点一下根据广告质量来算钱,有点一下 0.14 刀的也有 0.07 刀的,广告点满一百刀才能提现。不过别想着薅羊毛,容易被封号。据大佬们说广告点满十刀后还会又自检,还是希望不要舍本逐末吧。</p>
<p>最后,大佬们,关掉广告插件帮我点个广告可好~</p>
]]></content>
<categories>
<category>博客搭建</category>
</categories>
<tags>
<tag>博客</tag>
<tag>广告</tag>
<tag>Google</tag>
<tag>钱</tag>
</tags>
</entry>
<entry>
<title>一次愉快但被完爆的面试</title>
<url>/interview-ebay/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190810152950.jpeg" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>一个月前的实习生面试,面试过程很愉快,面试官很和蔼。但一个月后复盘,发现并没有回答到点子上,如果我是面试官,我也不会要这么一个人。</p>
<a id="more"></a>
<h2 id="红黑树与-AVL-树的区别"><a href="#红黑树与-AVL-树的区别" class="headerlink" title="红黑树与 AVL 树的区别"></a>红黑树与 AVL 树的区别</h2><h3 id="红黑树的定义"><a href="#红黑树的定义" class="headerlink" title="红黑树的定义"></a>红黑树的定义</h3><ul>
<li>两个节点颜色只有红黑两种</li>
<li>根和叶子节点都为黑色</li>
<li>两个红节点不相连</li>
<li>路径上的黑节点数一致</li>
</ul>
<p>AVL 强制左右子树高度相差为 1,平衡代价比红黑树大</p>
<h2 id="LinkedList-与-ArrayList-的区别"><a href="#LinkedList-与-ArrayList-的区别" class="headerlink" title="LinkedList 与 ArrayList 的区别"></a>LinkedList 与 ArrayList 的区别</h2><p>(也就是数组与链表的区别)</p>
<ul>
<li>数组需要连续的地址空间</li>
<li>数组支持随机访问下标</li>
<li>还问了插入的话哪个快</li>
</ul>
<h2 id="Spring-代理"><a href="#Spring-代理" class="headerlink" title="Spring 代理"></a>Spring 代理</h2><h3 id="如何实现-JDK-代理"><a href="#如何实现-JDK-代理" class="headerlink" title="如何实现 JDK 代理"></a>如何实现 JDK 代理</h3><h3 id="Spring-五种隔离级别"><a href="#Spring-五种隔离级别" class="headerlink" title="Spring 五种隔离级别"></a>Spring 五种隔离级别</h3><blockquote>
<p>这一块答上来了,但是都是错的,春天的面试太失败了</p>
</blockquote>
<ul>
<li>数据库的四种级别</li>
<li>后端数据库默认的事务<br>Mysql 默认采用的 <code>REPEATABLE_READ</code> 隔离级别 Oracle 默认采用的 <code>READ_COMMITTED</code> 隔离级别.</li>
</ul>
<h3 id="不可重复读"><a href="#不可重复读" class="headerlink" title="不可重复读"></a>不可重复读</h3><p>这一块面试官应该想问,可重复读隔离级别如何消除不可重复读,但被我糊弄过去了。另外,RR 级别可以消除当前读的幻读。当然这些都是之后才学习到。</p>
<h3 id="如何实现事务"><a href="#如何实现事务" class="headerlink" title="如何实现事务"></a>如何实现事务</h3><p>底层采用的还是 JDBC 的事务,只不过用动态代理以及注解的方式代理,抽出来往下看的话就是 TransactionManager 提供的 commit、rollback、close 的方法。</p>
<h2 id="单点登录的流程"><a href="#单点登录的流程" class="headerlink" title="单点登录的流程"></a>单点登录的流程</h2><h2 id="AQS"><a href="#AQS" class="headerlink" title="AQS"></a>AQS</h2><p>底层的结构是 FIFO 队列。线程进来先去竞争锁,竞争不到将线程扔到队尾自旋。一旦锁释放,若非公平锁,头结点后面的节点会通过自旋获得锁。</p>
<h2 id="软链接与硬链接的区别"><a href="#软链接与硬链接的区别" class="headerlink" title="软链接与硬链接的区别"></a>软链接与硬链接的区别</h2><ul>
<li>软链接<br>快捷方式</li>
<li>硬链接<br>复制一份相同的 inode 号以及权限,并且计数器 +1,另外硬链接的文件必须存在无法对目录硬链接。硬链接不能在不同文件系统中使用。</li>
</ul>
<h2 id="Maven-依赖命令行查看"><a href="#Maven-依赖命令行查看" class="headerlink" title="Maven 依赖命令行查看"></a>Maven 依赖命令行查看</h2><p>我应该答,可以通过 <code>mvn -h</code> 的方式看看</p>
]]></content>
<categories>
<category>面试</category>
</categories>
<tags>
<tag>未来</tag>
<tag>记录</tag>
<tag>面试</tag>
</tags>
</entry>
<entry>
<title>Mybatis 拦截器的简单实现</title>
<url>/Mybatis-Interceptor/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190804164802.jpg
" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>需求驱动学习,最近一周组长让我在业务模块里加日志,经过与导师以及组长讨论决定用拦截器记录日志。周五下班前已经发了提测邮件。</p>
<p>虽然我知道 MyBatis 有这东西,但是没在实际情况中用过,心里有点虚2333……所以才有了此文的理解。</p>
<a id="more"></a>
<h2 id="前世今生"><a href="#前世今生" class="headerlink" title="前世今生"></a>前世今生</h2><p>它的本质就是 JDK 的动态代理。首先先来复习一下动态代理我贴了一段最常见的 JDK 动态代理的代码<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//服务员的接口</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Waiter</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//服务员的实现</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">WaiterImpl</span> <span class="keyword">implements</span> <span class="title">Waiter</span> </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">void</span> <span class="title">serve</span><span class="params">()</span> </span>{</span><br><span class="line"> System.out.println(<span class="string">"服务中..."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="comment">//需要代理的对象处理器</span></span><br><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">WaitInvocationHandler</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Waiter waiter;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">WaitInvocationHandler</span><span class="params">(Waiter waiter1)</span> </span>{</span><br><span class="line"> waiter = waiter1;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>{</span><br><span class="line"> System.out.println(<span class="string">"你好"</span>);</span><br><span class="line"> Object invoke = method.invoke(waiter, args);</span><br><span class="line"> System.out.println(<span class="string">"再见"</span>);</span><br><span class="line"> <span class="keyword">return</span> invoke;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">App</span> </span>{</span><br><span class="line"> <span class="comment">//普通的实现</span></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun</span><span class="params">()</span> </span>{</span><br><span class="line"> Waiter waiter = <span class="keyword">new</span> WaiterImpl();</span><br><span class="line"> waiter.serve();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Test</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">fun1</span><span class="params">()</span> </span>{</span><br><span class="line"> Waiter a = <span class="keyword">new</span> WaiterImpl();</span><br><span class="line"> ClassLoader classLoader = getClass().getClassLoader();</span><br><span class="line"> Class[] classes = {Waiter<span class="class">.<span class="keyword">class</span>}</span>;</span><br><span class="line"> <span class="comment">//生成代理对象</span></span><br><span class="line"> Waiter waiterproxy = (Waiter) Proxy.newProxyInstance(classLoader, classes, <span class="keyword">new</span> WaitInvocationHandler(a));</span><br><span class="line"> waiterproxy.serve();</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h2 id="拦截器"><a href="#拦截器" class="headerlink" title="拦截器"></a>拦截器</h2><h3 id="V1"><a href="#V1" class="headerlink" title="V1"></a>V1</h3><p>我现在要在函数执行前后记录日志操作,考虑需要在代理方法那里定义个拦截器的接口,如下代码所示<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">//拦截器 V1 版本</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyInterceptorV1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">interceptor</span><span class="params">()</span></span>;</span><br><span class="line">}</span><br><span class="line"><span class="comment">//代理对象变成这个</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TargetProxyV1</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> Target target;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> MyInterceptorV1 myInterceptor;</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="title">TargetProxyV1</span><span class="params">(Target target, MyInterceptorV1 myInterceptor)</span> </span>{</span><br><span class="line"> <span class="keyword">this</span>.target = target;</span><br><span class="line"> <span class="keyword">this</span>.myInterceptor = myInterceptor;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>{</span><br><span class="line"> myInterceptor.interceptor();</span><br><span class="line"> <span class="keyword">return</span> method.invoke(target, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>这是最简单的版本,但是我们很多时候需要拦截参数等根据参数判断拦不拦截等,代码更新如下<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">MyInterceptorV1</span> </span>{</span><br><span class="line"> <span class="function"><span class="keyword">void</span> <span class="title">interceptor</span><span class="params">(Method method, Object[] args)</span></span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>{</span><br><span class="line"> myInterceptor.interceptor(method, args);</span><br><span class="line"> <span class="keyword">return</span> method.invoke(target, args);</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="V2"><a href="#V2" class="headerlink" title="V2"></a>V2</h3><p>似乎上面的方案很完美 <del>废话肯定不完美,不然怎么会有这段</del></p>
<p>没错,第二段代码并不是很优雅,有方法参数重复,可以考虑将三者抽出来,直接在拦截器的实现里写上<code>method.invoke(target, args);</code>,如下代码所示<br><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">@Getter</span><br><span class="line">@Setter</span><br><span class="line">@AllArgsConstructor</span><br><span class="line">public class MyInvocation {</span><br><span class="line"> private Object target;</span><br><span class="line"> private Method method;</span><br><span class="line"> private Object[] args;</span><br><span class="line"></span><br><span class="line"> public Object proceed() throws InvocationTargetException, IllegalAccessException {</span><br><span class="line"> return method.invoke(target, args);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line">//没错这就是 V2 版本</span><br><span class="line">public interface MyInterceptorV2 {</span><br><span class="line"> Object interceptor(MyInvocation invocation) throws Throwable;</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>Mybatis 的拦截器就是像我上面这么写的,<del>名字也跟我取得一样,</del>只是它更加复杂,能够通过注解区分拦截 <code>update</code> 操作和 <code>query</code> 等操作。</p>
<p>既完成了任务又巩固了原来的知识,这种感觉很棒,最关键的是还有钱拿……</p>
<p><a href="https://github.com/yi-yun/JavaExercise/blob/master/java_se/src/main/java/com/yiyun/proxy/mybatis/App.java" target="_blank" rel="noopener">本文代码</a></p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>学习</tag>
<tag>Mybatis</tag>
<tag>Interceptor</tag>
<tag>框架</tag>
</tags>
</entry>
<entry>
<title>01 背包</title>
<url>/ZeroOnePack/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721194301.jpeg" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>异常有名的背包问题,终于有勇气面对它了。<br>三年前学数据结构算法的时候,那时候也不懂,参考的很多博客文章没有例子,都是数学公式生硬地出来,而且写法各种各样,导致一直没有勇气去接触这些。</p>
<a id="more"></a>
<h2 id="题目描述"><a href="#题目描述" class="headerlink" title="题目描述"></a>题目描述</h2><blockquote>
<p>在 n 个物品中挑选若干物品装入背包,最多能装多满?假设背包的大小为 w,每个物品的大小为 A[i]</p>
</blockquote>
<h3 id="样例"><a href="#样例" class="headerlink" title="样例"></a>样例</h3><figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">样例 1:</span><br><span class="line"> 输入: [3,4,8,5], backpack size=10</span><br><span class="line"> 输出: 9</span><br><span class="line"></span><br><span class="line">样例 2:</span><br><span class="line"> 输入: [2,3,5,7], backpack size=12</span><br><span class="line"> 输出: 12</span><br></pre></td></tr></table></figure>
<h2 id="动态规划"><a href="#动态规划" class="headerlink" title="动态规划"></a>动态规划</h2><p>最简单的动态规划做法是将过程分为 n 个阶段,每个阶段决策是否将物品放入背包中。记住,动态规划的本质就是通过数组存储状态。</p>
<p>请看下面的例子,这是现在我拥有的东西以及条件<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span>[] weight = {<span class="number">2</span>,<span class="number">2</span>,<span class="number">4</span>,<span class="number">6</span>,<span class="number">3</span>};<span class="comment">// 物品重量</span></span><br><span class="line"><span class="keyword">int</span> w = <span class="number">9</span>; <span class="comment">// 背包承受的最大重量</span></span><br></pre></td></tr></table></figure></p>
<p>我们需要通过这些来构建出一个二维数组 <code>states[n][w+1]</code> 记录状态。states[i][j] 表示第 i 个做完决策后,背包容量 j 能放多少价值。这道题目物品的价值与物品的重量相等。</p>
<ul>
<li>为什么数组是 w+1?<br>数组边界可以取到 w 意味着 <code>states[][w]</code> 可以表示装满背包时的总价值是多大。</li>
</ul>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">backPack2D</span><span class="params">(<span class="keyword">int</span> m, <span class="keyword">int</span>[] A)</span> </span>{</span><br><span class="line"> <span class="comment">//求出物品个数</span></span><br><span class="line"> <span class="keyword">int</span> n = A.length;</span><br><span class="line"> <span class="keyword">int</span>[][] states = <span class="keyword">new</span> <span class="keyword">int</span>[n][m + <span class="number">1</span>];</span><br><span class="line"> <span class="comment">//初始化 states[0][]</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = A[<span class="number">0</span>]; i <= m; i++) {</span><br><span class="line"> states[<span class="number">0</span>][i] = A[<span class="number">0</span>];</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = m; j >= <span class="number">0</span>; j--) {</span><br><span class="line"> <span class="comment">//当不把物品放入背包,将上一层的数值拷贝过来</span></span><br><span class="line"> <span class="keyword">if</span> (states[i - <span class="number">1</span>][j] > <span class="number">0</span>) {</span><br><span class="line"> states[i][j] = states[i - <span class="number">1</span>][j];</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">//注意这里 j 的范围</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = <span class="number">0</span>; j >= <span class="number">0</span>; j--) {</span><br><span class="line"> states[i][j + A[i]] = Math.max(states[i][j + A[i]], states[i][j] + A[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> states[n - <span class="number">1</span>][m];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
<ol>
<li><p>重量数组<code>{2,2,4,6,3}</code>,代码更新数组如下<br>new 数组时的状态</p>
<p> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721184105.png" alt></p>
</li>
<li><p>初始化数组,第 0 个物品决策<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721184752.png" alt></p>
</li>
<li>第(i=1)个物品决策完后数组状态<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721185037.png" alt></li>
<li>第(i=2)个物品决策完后数组状态<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721185234.png" alt></li>
<li>第(i=3)个物品决策完后数组状态<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721185545.png" alt></li>
<li>第(i=4)个物品决策完后数组状态<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721185834.png" alt></li>
</ol>
<p><code>states[i][j]</code> 表示第 i 个物品决策完后,容量为 j 的背包里最多能放多少价值的物品,所以最后返回 <code>states[n-1][m]</code> 即可</p>
<h2 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h2><p>上述解法用到了一个二维数组,其实我们还能进一步地优化空间<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">backPack</span><span class="params">(<span class="keyword">int</span> m, <span class="keyword">int</span>[] A)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> n = A.length;</span><br><span class="line"> <span class="keyword">int</span>[] states = <span class="keyword">new</span> <span class="keyword">int</span>[m + <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="comment">//注意这里倒着遍历</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = m - A[i]; j >= <span class="number">0</span>; j--) {</span><br><span class="line"> states[A[i] + j] = Math.max(states[A[i] + j], states[j] + A[i]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> states[m];</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<p>解释一下倒着遍历的那里以及 j 的范围</p>
<ul>
<li>如果正序遍历,后面的值有可能直接被前面的覆盖了,当遍历到覆盖的值的时候,此时当前数组元素的值并不是从上面一行数组 copy 下来的,而是通过 max 计算出来的</li>
<li>j 的范围有两种,第一种是 m 到 A[i],可以理解为要更新的数组状态;第二种是 m-A[i] 到 0,可以理解为遍历前序数组,更新尾部的数组。虽然两种理解代码不一样,但是结果一致。<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721191918.png" alt></li>
</ul>
<h2 id="01-背包升级版"><a href="#01-背包升级版" class="headerlink" title="01 背包升级版"></a>01 背包升级版</h2><p>加上了 value 数组,我将链接以及 AC 代码贴在这里,希望对你有所帮助</p>
<ul>
<li><a href="https://www.lintcode.com/problem/backpack-ii/" target="_blank" rel="noopener">题目链接</a></li>
<li>代码 <figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">backPackII2</span><span class="params">(<span class="keyword">int</span> m, <span class="keyword">int</span>[] A, <span class="keyword">int</span>[] V)</span> </span>{</span><br><span class="line"> <span class="keyword">int</span> n = A.length;</span><br><span class="line"> <span class="keyword">int</span>[] states = <span class="keyword">new</span> <span class="keyword">int</span>[m + <span class="number">1</span>];</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i < n; i++) {</span><br><span class="line"> <span class="keyword">for</span> (<span class="keyword">int</span> j = m - A[i]; j >= <span class="number">0</span>; j--) {</span><br><span class="line"> states[j + A[i]] = Math.max(states[j] + V[i], states[j + A[i]]);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> states[m];</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="小技巧"><a href="#小技巧" class="headerlink" title="小技巧"></a>小技巧</h2><ul>
<li>恰好装满与尽量装满<ul>
<li>恰好装满需要将数组初始化为 0,-1,-1,-1,-1……</li>
<li>尽量装满只需要 0,0,0,0……</li>
</ul>
</li>
</ul>
<p>原因的话偷个懒,上一个背包九讲的图<br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190721192914.png" alt></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>01 背包是动态规划的入门,需要静下心来仔细想一步步 DeBug,收获会很大。很多题目都是基于 01 背包的变种。<br>江湖艰险,希望此文会对你有所帮助!</p>
]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>LintCode</tag>
<tag>背包</tag>
<tag>动态规划</tag>
</tags>
</entry>
<entry>
<title>实习杂谈</title>
<url>/Intern/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190630203324.jpeg" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>现在正在大学城的图书馆敲着文字,周围是北大清华哈工大的研究生,让我这个双非本科的瑟瑟发抖……</p>
<a id="more"></a>
<h2 id="体验"><a href="#体验" class="headerlink" title="体验"></a>体验</h2><h3 id="城市"><a href="#城市" class="headerlink" title="城市"></a>城市</h3><p>首先说说深圳这座城市给我带来的最大感受吧</p>
<ul>
<li>热<br>刚下火车扑面而来的是一阵热风,让我这个南方人体验到了真正的潮热</li>
<li>多<br>在这个 2000 平方公里的城市,居住人口超过 2000 万,报道的那天就让我感受到了拥挤,几乎是一站一辆公交车都满足不了出行,加上上下班地铁限流,简直是要人命</li>
<li>新<br>建筑大都很现代化,像是杭州滨江</li>
</ul>
<h3 id="公司"><a href="#公司" class="headerlink" title="公司"></a>公司</h3><p>随手科技在著名的南山区金蝶软件园 B 幢,大概有 4、5、6、7、8 楼吧<del>(萌新入职才一周,不是很清楚,见谅)</del></p>
<p>新人入职两周不让碰源码,要看两周文档,下周培训。不过文档内容和规范真的丰富,同事沟通、请假以及项目管理都有内部的软件。</p>
<p>周二、周四有下午茶,晚上加班到十点能打车,每个月有生(qiang)日(dan)会(gao),福利比杭州某公司多了一点……<del>,除了钱给的稍微不够了点。</del></p>
<p>导师待我还不错,带我逛周围的饭店介绍周边的环境给我开文档的权限什么的,还会撺掇我去拿吃的2333。</p>
<p>随手算是暑期镀金的好地方了,不用像很多实习生那样担心租房问题,大城市租房是真的贵啊。加上在异地,看房也是问题。公司分配宿舍,溜的时候退租就好了。</p>
<p>这里要吐槽下 HR,emmmm 工牌在上班后两天才拿到,结果发现还要去开门禁权限……我至今仍然不能自由出入……</p>
<h2 id="闲聊"><a href="#闲聊" class="headerlink" title="闲聊"></a>闲聊</h2><p>随手算比较大的了,对新人很友好,文档很丰富,我们组有活干,起码之后不会带薪摸鱼。</p>
<p>来深圳其实父母不是很支持,担心我的安全,因为这件事我向他们哭诉了很多次了,也影响了春招后来的状态。再后来父母也拿我没办法,只能妥协。互联网的信息差对我们这代以及我们的父母影响还是很大的。当然也有观念的问题,父母想一直把我限制在浙江,甚至最好在村里找份工作,这样会安生许多。可是……</p>
<p>我真的不想一直在父母的庇护下成长,父母是农村人加上家境又不是很殷实,下半年加油吧!</p>
]]></content>
<categories>
<category>日常记录</category>
</categories>
<tags>
<tag>随手科技</tag>
<tag>实习</tag>
</tags>
</entry>
<entry>
<title>春耕,</title>
<url>/spring-plowing/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190618112410.jpeg" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><blockquote>
<p>我胡汉三又回来了</p>
</blockquote>
<p>考完最后一门马克思主义原理,就意味着三月份自己制定的春招计划画上了逗号。</p>
<a id="more"></a>
<h2 id="金三银四"><a href="#金三银四" class="headerlink" title="金三银四"></a>金三银四</h2><p>这里我只想提醒一句,每个人的一生中不出意外的话只有一次金三银四,也就是大三下的这一段时间。虽然可能你的未来不取决于这段时间,但如果这段时间状态良好无疑会给你未来的职业生涯中添加上浓墨重彩的一笔。</p>
<p>很遗憾,我并没有把握住这些机会,复盘原因:</p>
<ul>
<li>简历准备不充分<br>在期间,我听取他人的建议更换了一次简历,这里感谢亚信科技老哥提供的建议。他的建议是,既然找 Java 后台实习,你的简历上要单独开发的模块,要让人家清楚招你进来你是能干活的,而不是吹吹牛皮。</li>
<li>挑战杯事宜<br>这是个无比巨大的坑,虽然我是负责人,但是真的很累。你每礼拜需要花费一小时地铁上的时间区评委家中更改文档,不止一次!!!临近比赛,还要去准备答辩事宜……拿的钱却跟同等级别比赛的钱是一样的,这也太坑了!<br><del>为什么还要参加?去翻我前面的文章吧</del></li>
<li>基础不牢,地动山摇<br>基本上我的三四月份是在投简历-笔试-投简历中度过,根本没有电话,注意一个都没有!意思是我笔试没通过呗,加上上一条原因,金三银四就过去了……</li>
</ul>
<h2 id="五月重新起航"><a href="#五月重新起航" class="headerlink" title="五月重新起航"></a>五月重新起航</h2><p>其实四月底已经开始着急了,开始在 Boss 直聘上找小公司练面试。有幸的是,经过三四月份魔鬼训练,小公司的面试题都比较简单,收到了几家不错的 Offer,但由于不是很甘心(想去稍微大一点的公司),所以一直吊着,至今还没拒绝……</p>
<p><strong>这里重点提醒一下,在春招前最好要先找小公司沉淀一下(大牛当我没说),问问面试题项目啊都是极好的,而且过了有个保底 Offer,心里也不慌了。</strong><br>实话说,我当初看到这条前人的经验了,但当时头铁啊,实习面试我这种水平应该还行吧,哪知道水这么深……</p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>虽然收到了还算满意的 Offer,但这家公司在深圳(不是你们想的某讯)……离杭州太远了,属实不方便。</p>
<h3 id="经验"><a href="#经验" class="headerlink" title="经验"></a>经验</h3><p>所谓经验,给秋天的我和未来的你们看吧</p>
<ul>
<li>看到招聘信息请立刻投简历<br>别像我这样攒着攒着,人招满了,连面试机会都没有</li>
<li>打好基础,想进大厂实习需要计算机深厚的功底<br>菜鸡能做的是刷题,搞懂知识点 </li>
<li>找小公司试水(大牛绕道)</li>
<li>寒假就需要准备了<br>甚至在期末考试结束后就要准备了,金三银四想要上岸,真的一点都不夸张,像我三月份才开始准备真的太晚了。</li>
</ul>
<p>最后,期待秋收。</p>
]]></content>
<categories>
<category>总结</category>
</categories>
<tags>
<tag>春招</tag>
<tag>记录</tag>
<tag>面试</tag>
</tags>
</entry>
<entry>
<title>Java 8 实战</title>
<url>/java-8-in-action/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190609220916.png" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>很早就想仔细学了,终于有机会记一下笔记……</p>
<a id="more"></a>
<h2 id="Lambda-表达式"><a href="#Lambda-表达式" class="headerlink" title="Lambda 表达式"></a>Lambda 表达式</h2><h3 id="函数式接口"><a href="#函数式接口" class="headerlink" title="函数式接口"></a>函数式接口</h3><p>只定义了一个<strong>抽象</strong>方法的的接口,值得注意的是,Java 8 引入了 stream 等方法,但是原先的 Collection 里没有。为了提高效率,接口的设计者就引入了 default 关键字来扩充接口。可用 @FunctionalInterface 标记为函数式接口,类似 @Override。</p>
<h3 id="常用的接口"><a href="#常用的接口" class="headerlink" title="常用的接口"></a>常用的接口</h3><ul>
<li>Predicate<br>返回 boolean</li>
<li>Consumer<br>void,适用于 <code>sout</code></li>
<li>Function<br>可以将 T 转化为 R</li>
</ul>
<h3 id="感觉"><a href="#感觉" class="headerlink" title="感觉"></a>感觉</h3><p>其实 Java 中就是一个接口实现,如果要扯到函数式编程的话就要扯到 lambda 演算,主要为三条规则:</p>
<ul>
<li>函数定义</li>
<li>标识符引用</li>
<li>函数应用</li>
</ul>
<p><del>说人话</del></p>
<p>我的理解是这三条规则为定义一个变量和函数,然后告诉你定义完了怎么去使用它</p>
<p>举个难一点的栗子(PS:为什么要举难一点的例子……<del>答:装逼</del>)<br><figure class="highlight lisp"><table><tr><td class="code"><pre><span class="line">(<span class="name">lambda</span> x y. x y) (<span class="name">lambda</span> z . z * z) 3</span><br></pre></td></tr></table></figure></p>
<h2 id="流"><a href="#流" class="headerlink" title="流"></a>流</h2><blockquote>
<p>从支持数据处理操作的源生成的元素序列</p>
</blockquote>
<p>用过的人都说好……</p>
<h3 id="定义"><a href="#定义" class="headerlink" title="定义"></a>定义</h3><ul>
<li><p>内部迭代<br>将迭代封装在内部,例如</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">Dish.menu.stream().map(Dish::toString).collect(Collectors.toList());</span><br><span class="line">Dish.menu.stream().forEach(System.out::println);</span><br></pre></td></tr></table></figure>
</li>
<li><p>使用规则</p>
<ul>
<li>数据源(例如集合)</li>
<li>中间操作链</li>
<li>终端操作</li>
</ul>
</li>
<li>流只能遍历一次,只能消费一次</li>
</ul>
<h3 id="创建"><a href="#创建" class="headerlink" title="创建"></a>创建</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="comment">// Stream.of</span></span><br><span class="line">Stream.of(<span class="string">"Java 8"</span>, <span class="string">"Lambdas"</span>, <span class="string">"In"</span>, <span class="string">"Action"</span>).map(String::toUpperCase).forEach(System.out::println);</span><br><span class="line"><span class="comment">// Stream.empty</span></span><br><span class="line">Stream<String> emptyStream = Stream.empty();</span><br><span class="line"><span class="comment">// Arrays.stream</span></span><br><span class="line"><span class="keyword">int</span>[] numbers = {<span class="number">2</span>, <span class="number">3</span>, <span class="number">5</span>, <span class="number">7</span>, <span class="number">11</span>, <span class="number">13</span>};</span><br><span class="line">System.out.println(Arrays.stream(numbers).sum());</span><br></pre></td></tr></table></figure>
<h3 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h3><h4 id="筛选和切片"><a href="#筛选和切片" class="headerlink" title="筛选和切片"></a>筛选和切片</h4><ul>
<li>filter</li>
<li>distinct<br>筛选互异元素</li>
<li>limit<br>取前几个元素</li>
<li>skip<br>跳过前几个元素</li>
</ul>
<h4 id="映射"><a href="#映射" class="headerlink" title="映射"></a>映射</h4><ul>
<li>map</li>
<li><p>flatMap<br>将流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流,个人理解为将流里的值继续转换为子流然后连接。</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line">List<Integer> list1 = Arrays.asList(<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>);</span><br><span class="line">List<Integer> list2 = Arrays.asList(<span class="number">4</span>,<span class="number">5</span>);</span><br><span class="line">list1.stream().flatMap(i-></span><br><span class="line"> list2.stream().map(j-><span class="keyword">new</span> <span class="keyword">int</span>[]{i,j})</span><br><span class="line"> ).forEach(t-> System.out.println(t[<span class="number">0</span>]+<span class="string">","</span>+t[<span class="number">1</span>]));</span><br></pre></td></tr></table></figure>
</li>
<li><p>mapToInt</p>
</li>
</ul>
<h4 id="查找和匹配"><a href="#查找和匹配" class="headerlink" title="查找和匹配"></a>查找和匹配</h4><p>短路操作,找到一个符合条件的立即返回</p>
<ul>
<li>anyMatch<br>至少匹配一个</li>
<li>allMatch<br>都匹配</li>
<li>noneMatch<br>没有匹配的</li>
<li>findAny</li>
<li>findFirst<br>与楼上有并行的区别,findAny 不一定是返回第一个</li>
</ul>
<h4 id="规约"><a href="#规约" class="headerlink" title="规约"></a>规约</h4><p>使用 reduce,第一个参数为初始值,第二个为执行函数直到规约到一个数</p>
<h3 id="细节"><a href="#细节" class="headerlink" title="细节"></a>细节</h3><ul>
<li><p>数值流以及对象流相互的转化</p>
<ul>
<li>IntStream</li>
<li>LongStream</li>
<li>DoubleStream<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">int</span> calories = menu.stream().mapToInt(Dish::getCalories).sum();</span><br><span class="line">menu.stream().mapToInt(Dish::getCalories).boxed();</span><br></pre></td></tr></table></figure>
</li>
</ul>
</li>
<li><p>数值范围</p>
<ul>
<li><p>rangeClosed</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">long</span> count = IntStream.rangeClosed(<span class="number">1</span>, <span class="number">100</span>).filter(d -> d % <span class="number">2</span> == <span class="number">0</span>).count();</span><br></pre></td></tr></table></figure>
</li>
<li><p>range<br>不包括结束值</p>
</li>
</ul>
</li>
</ul>
<h3 id="收集器"><a href="#收集器" class="headerlink" title="收集器"></a>收集器</h3><blockquote>
<p>前面的都是小儿科,在开发人员的代码里很多都是收集器</p>
</blockquote>
<h4 id="规约与汇总"><a href="#规约与汇总" class="headerlink" title="规约与汇总"></a>规约与汇总</h4><ul>
<li>counting</li>
<li>maxBy<br>需要实现 Comparator</li>
<li>summingInt/summingLong/summingDouble</li>
<li>averagingInt/averagingLong/averagingDouble</li>
<li>summarizingInt/summarizingLong/summarizingDouble</li>
<li>joining</li>
</ul>
<h5 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h5><p>通过 reducing() 实现,需要三参数,单参数为三参数的特殊情况,起点为第一个项目,转换函数为恒等函数,第三个为函数计算<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line">menu.stream().map(Dish::getName).collect(joining());</span><br><span class="line">menu.stream().map(Dish::getName).collect(reducing((s1,s2)->s1+s2)).get();</span><br><span class="line">menu.stream().collect(reducing(<span class="string">" "</span>,Dish::getName,(s1,s2)->s1+s2));</span><br></pre></td></tr></table></figure></p>
<h4 id="分组"><a href="#分组" class="headerlink" title="分组"></a>分组</h4><blockquote>
<p>groupingBy </p>
</blockquote>
<ul>
<li>单参数 groupingBy(f) 实际是 groupingBy(f,toList()) </li>
<li>双参数,第二个参数为任意类型的收集器,也可为 groupingBy(f)</li>
<li>常用的联合使用收集器为 summingInt,counting,mapping 等</li>
<li>隐含参数可为 toSet()</li>
</ul>
<h4 id="分区"><a href="#分区" class="headerlink" title="分区"></a>分区</h4><blockquote>
<p>特殊的分组,分区函数返回 boolean</p>
</blockquote>
<h4 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h4><ul>
<li><code>Supplier<A> supplier()</code></li>
<li><code>BiConsumer<A, T> accumulator()</code></li>
<li><code>Function<A, List<T>>()</code></li>
<li><code>BinaryOperator<A> combiner()</code></li>
<li><code>Set<Characteristics> characteristics()</code></li>
</ul>
<h4 id="自定义收集器"><a href="#自定义收集器" class="headerlink" title="自定义收集器"></a>自定义收集器</h4><p>单纯的能看懂……</p>
<h3 id="并行"><a href="#并行" class="headerlink" title="并行"></a>并行</h3><ul>
<li>避免共享状态</li>
<li>留意装箱</li>
<li>limit 和 findFirst 依赖元素顺序</li>
</ul>
<p>PS:如果想提高效率,自行实现 Spliterator 接口<br><del>为什么就一句话,因为我不太会</del></p>
<h2 id="默认方法"><a href="#默认方法" class="headerlink" title="默认方法"></a>默认方法</h2><blockquote>
<p>Ootional说下个人理解,接口中引入了 default 关键字,使接口更新更加平滑,不需要更改已经编译出来的客户端 clas 文件,只需在上游添加默认方法即可。<br><del>其实官方就是为了方便引入 stream,防止升级之后出现客户端代码崩溃的问题</del> </p>
</blockquote>
<h2 id="Optional"><a href="#Optional" class="headerlink" title="Optional"></a>Optional</h2><blockquote>
<p>这个竟然在面试中被问到了,1.8 之后处理异常有什么改进。虽然有了解过,但是竟然被问懵了,还有区别???后来经过提醒才意识到原来他问的是空指针处理的 Optional……</p>
</blockquote>
<h3 id="他山之石"><a href="#他山之石" class="headerlink" title="他山之石"></a>他山之石</h3><p>在很早之前<del>好像是《七周七语言》里(具体我忘了哪本书)</del>看到的说语言的设计者很痛恨引入空指针这个概念,因为程序员在业务中需要去进行繁琐的判断,后来才设计出 Haskell 的 Maybe 类型。<br>像 Groovy 处理就直接引入安全导航操作符,若引用链中有空指针传递下去,返回一个 null。</p>
<h3 id="可以攻玉"><a href="#可以攻玉" class="headerlink" title="可以攻玉"></a>可以攻玉</h3><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getCarInsuranceName</span><span class="params">(Optional<Person> person)</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> person.flatMap(Person::getCar)</span><br><span class="line"> .flatMap(Car::getInsurance)</span><br><span class="line"> .map(Insurance::getName)</span><br><span class="line"> .orElse(<span class="string">"Unknown"</span>);</span><br><span class="line"> }</span><br></pre></td></tr></table></figure>
<h3 id="细节-1"><a href="#细节-1" class="headerlink" title="细节"></a>细节</h3><p>在设计时没有考虑将其作为类的字段使用,没有实现 Serializable 接口,无法序列化<br>替代方案如下<br><figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Car</span> </span>{</span><br><span class="line"> <span class="keyword">private</span> Insurance insurance;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> Optional<Insurance> <span class="title">getInsuranceAsOptional</span><span class="params">()</span> </span>{</span><br><span class="line"> <span class="keyword">return</span> insurance;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p>
<h3 id="个人感受"><a href="#个人感受" class="headerlink" title="个人感受"></a>个人感受</h3><p>有点类似流,但不同于流的是它只是个对象,如 filter 是对对象属性的操作</p>
<h2 id="CompletableFuture"><a href="#CompletableFuture" class="headerlink" title="CompletableFuture"></a>CompletableFuture</h2><p>工厂方法<br>CompletabelFuture.supplyAsync();</p>
<ul>
<li>异步操作,相比于并行的 stream 可以自定义线程池,适用于 I/O 密集型任务</li>
<li>管理异常</li>
<li>可以将异步任务合并<br><code>thenCombine</code></li>
<li>注册回调函数<br><code>thenAcecpt</code></li>
<li>决定程序运行<br><code>allOf</code> <code>anyOf</code></li>
</ul>
<h2 id="时间"><a href="#时间" class="headerlink" title="时间"></a>时间</h2><ul>
<li>LocalDate</li>
<li>LocalTime</li>
<li>LocalDateTime</li>
</ul>
<p>未完待续……</p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>学习</tag>
<tag>代码</tag>
</tags>
</entry>
<entry>
<title>面试一二事</title>
<url>/interview-question/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190515233124.jpeg
" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>整理录音的时候才发现自己有多菜,这都回答的啥呀……</p>
<a id="more"></a>
<h2 id="面试题"><a href="#面试题" class="headerlink" title="面试题"></a>面试题</h2><ul>
<li>Java 八大基本类型<ul>
<li>short 变量 +1,真的细,还好好久之前瞄了一眼</li>
</ul>
</li>
<li>New String(“123”) new 了几个对象</li>
<li>equals 与 ==</li>
<li>HashMap 原理</li>
<li>红黑树定义、优点与普通二叉树的区别,效率</li>
<li>ConcurrentHashMap</li>
<li>Synchronized<ol>
<li>普通同步方法,锁是当前实例对象</li>
<li>静态同步方法,锁是当前类的class对象</li>
<li>同步方法块,锁是括号里面的对象</li>
</ol>
</li>
<li>volatile</li>
<li>反射</li>
<li>IOC 原理以及好处</li>
<li>AOP<ul>
<li>JDK 原生</li>
<li>CGLib</li>
</ul>
</li>
<li>Spring 事务级别</li>
<li>SpringBoot 自动化</li>
<li>垃圾回收<ul>
<li>引用计数</li>
<li>root 节点</li>
</ul>
</li>
<li>Mybatis 执行流程</li>
<li>Mybatis 与 JDBC 的区别</li>
<li>NIO</li>
<li>TCP 与 UDP 区别</li>
<li>TCP 三次握手</li>
<li>MySQL 索引</li>
<li>MySQL 死锁</li>
<li>MySQL 乐观锁以及悲观锁</li>
<li>查看日志命令</li>
</ul>
<h3 id="人生"><a href="#人生" class="headerlink" title="人生"></a>人生</h3><ul>
<li>未来一年的规划</li>
<li>理想的工作环境</li>
</ul>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>记录</tag>
<tag>面试</tag>
</tags>
</entry>
<entry>
<title>真的早就是优势</title>
<url>/spring-will-end/</url>
<content><![CDATA[<p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190426211604.jpg" class="full-class"><br></p>
<h2 id="提要"><a href="#提要" class="headerlink" title="提要"></a>提要</h2><p>总说春江水暖,但只有体验过才知道今年的水让我瑟瑟发抖。我就是死也不会考研?</p>
<a id="more"></a>
<h2 id="感悟"><a href="#感悟" class="headerlink" title="感悟"></a>感悟</h2><p>四月快走了,仍然没有春招 Offer。不过最近的感悟倒是获得挺多,当然还有血淋淋的教训。</p>
<h3 id="早"><a href="#早" class="headerlink" title="早"></a>早</h3><blockquote>
<p>早就是优势。</p>
</blockquote>
<p>投简历越早投越好,就是知道内推信息就得立刻马上投。不要像我这样收藏着一大波招聘内推消息,过了几礼拜才投,hc 早没了……加上自身学校没有 Buffer 加成,我也不知道两个月前哪来的自信<del>(不要跟我扯招聘时间,真的是越早投机会越大,因为我就是看了招聘时间,结果很难受,我挺后悔的)</del>不举例子了,因为排队的人太多,我已经被简历劝退了两三次了,真的是血淋林的教训啊。</p>
<p>不过从另一方面来讲,春天为秋天积攒了经验,总比秋天结束的时候才知道好,毕竟大目标还是秋天,只是夏天缺乏了漂亮光鲜的履历罢了,但说实话挺难受的。</p>
<h3 id="革命尚未成功"><a href="#革命尚未成功" class="headerlink" title="革命尚未成功"></a>革命尚未成功</h3><p>有人说可以准备秋天了,但我并不认同。因为还有收官战,虽然金三银四转瞬即逝,但春天还没结束,拿起武器继续战斗吧!</p>
<p>未完,待续……</p>
]]></content>
<categories>
<category>随笔</category>
</categories>
<tags>
<tag>学习</tag>
<tag>春招</tag>
<tag>扯淡</tag>
<tag>经验</tag>
</tags>
</entry>
<entry>
<title>Java 并发入门</title>
<url>/thread/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190411120437.jpg " class="full-image"><br></p>
<h2 id="碎碎念"><a href="#碎碎念" class="headerlink" title="碎碎念"></a>碎碎念</h2><blockquote>
<p><del>拖更一时爽,一直拖更一直爽</del></p>
</blockquote>
<p>最近忙于找实习以及挑战杯省赛,两者聚在一起当然就忙得不可开交。关于省赛,前几篇文章也有提到,其实我是不太愿意花时间搞的,但是命运使然,只好寻找某一平衡点喽。<br><a id="more"></a></p>
<h2 id="概念"><a href="#概念" class="headerlink" title="概念"></a>概念</h2><blockquote>
<p>介绍一些概念,当然也为了使自己印象深刻</p>
</blockquote>
<h3 id="线程"><a href="#线程" class="headerlink" title="线程"></a>线程</h3><p>操作系统调度的最小单元,一个进程中的所有的线程都有完全一样的地址空间,意味着共享同样的全局变量。</p>
<h3 id="上下文切换"><a href="#上下文切换" class="headerlink" title="上下文切换"></a>上下文切换</h3><p>CPU 分配给各个线程时间片,但因为时间片很短,所以 CPU 不停的切换线程。但是 CPU 切换前会保存上一个任务的状态(进程状态、优先级、程序 I/O 的状态、文件描述符等)到内存,以便下次切换回这个状态。</p>
<h4 id="解决方案"><a href="#解决方案" class="headerlink" title="解决方案"></a>解决方案</h4><blockquote>
<p>多次上下文切换会影响多线程执行速度</p>
</blockquote>
<ul>
<li>无锁并发编程</li>
<li>CAS 算法</li>
<li>使用最少线程</li>
<li>协程</li>
</ul>
<h2 id="线程间通信"><a href="#线程间通信" class="headerlink" title="线程间通信"></a>线程间通信</h2><blockquote>
<p>等待/通知的经典范式</p>
</blockquote>
<ul>
<li><p>等待方</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(对象){</span><br><span class="line"> <span class="keyword">while</span>(条件不满足){</span><br><span class="line"> 对象.wait();</span><br><span class="line"> }</span><br><span class="line"> 对应的处理逻辑</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
<li><p>通知方</p>
<figure class="highlight java"><table><tr><td class="code"><pre><span class="line"><span class="keyword">synchronized</span>(对象){</span><br><span class="line"> 改变对象</span><br><span class="line"> 对象.notifyAll();</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ul>
<h2 id="Thread-join"><a href="#Thread-join" class="headerlink" title="Thread.join()"></a>Thread.join()</h2><blockquote>
<p>线程 A 执行了 thread.join() 语句时表示,当前线程 A 等待 thread 线程终止之后才从 thread.join() 返回。</p>
</blockquote>
<h2 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h2><blockquote>
<p>个人看源码理解就是在虚拟机栈中存着引用,真正存值的是 ThreadLocalMap。而 ThreadLocalMap 内部用 Entry 存放 K-V,哈希冲突则采用的是开放寻址法。<br>另外,ThreadLocal 在线程池里容易存在内存泄漏,因为只要线程被 GC 回收,即使弱引用 Key 的值为 null,一般不会内存泄漏。就怕线程池回收利用,Key 为 null 了,value 则还有值。解决方法就是调用 remove() 方法,将值设置为 null。</p>
</blockquote>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>Java</tag>
<tag>春招</tag>
<tag>面试</tag>
<tag>多线程</tag>
</tags>
</entry>
<entry>
<title>深入理解 Java 虚拟机</title>
<url>/jvm/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190331132452.png" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>有输入肯定要有输出。</p>
<a id="more"></a>
<h2 id="内存区域划分"><a href="#内存区域划分" class="headerlink" title="内存区域划分"></a>内存区域划分</h2><p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190331103031.png" alt></p>
<ul>
<li>程序计数器<br>唯一一个没有规定 OOME 的地方。执行 Java 方法时记录当前方法的 JVM 指令地址;执行 Native 方法时,计数器为空。</li>
<li>Java 虚拟机栈</li>
<li>本地方法栈</li>
<li>堆<br>内存管理的核心区域,分为新生代和老年代,再细致一点分为 Eden 空间、From Survivor、To Survivor 等</li>
<li>方法区<br>所有线程共享的内存区域,存储元数据,如类结构信息、字段、方法等。无法满足内存分配需求时,抛出 OOME。<ul>
<li>运行时常量池<br>方法区的一部分,存放编译期生成的各种字变量,还有运行时的符号引用等。例如 String.intern() 后放置的地方。</li>
</ul>
</li>
<li>直接内存<br>JDK 1.4 引入 NIO 类,它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。</li>
<li>Code Cache<br>JIT Compiler 在运行时对热点方法的编译;GC 运行时部分需要占用的空间等,但 JVM 规范中并没有涉及。</li>
</ul>
<h2 id="OutOfMemoryError"><a href="#OutOfMemoryError" class="headerlink" title="OutOfMemoryError"></a>OutOfMemoryError</h2><h3 id="堆溢出"><a href="#堆溢出" class="headerlink" title="堆溢出"></a>堆溢出</h3><p>不断创建对象并且无法回收</p>
<h3 id="栈溢出"><a href="#栈溢出" class="headerlink" title="栈溢出"></a>栈溢出</h3><p>在单线程下,当内存无法分配时,虚拟机抛出通常是 StackOverflowError 异常。</p>
<h3 id="方法区运行时常量池溢出"><a href="#方法区运行时常量池溢出" class="headerlink" title="方法区运行时常量池溢出"></a>方法区运行时常量池溢出</h3><p>JVM 对于方法区的回收非常不积极,例如老版本的 JDK 处理 String.Intern() 时占用太多空间。随着元数据区的移除永久代,类元数据只受本地内存影响。</p>
<h3 id="本机直接内存溢出"><a href="#本机直接内存溢出" class="headerlink" title="本机直接内存溢出"></a>本机直接内存溢出</h3><p>垃圾回收不会主动收集 Direct Buffer,需要自己手动调 System.gc()。另外。不会在 Heap Dump 中看见。</p>
<h2 id="垃圾回收"><a href="#垃圾回收" class="headerlink" title="垃圾回收"></a>垃圾回收</h2><p>判断对象是否存活,引用计数法很难解决循环引用的问题,所以才有了可达性分析</p>
<p>GC Roots 的对象包括以下几种:</p>
<ul>
<li>虚拟机栈中引用的对象</li>
<li>方法去类静态属性引用的对象</li>
<li>方法去常量引用的对象</li>
<li>Native 方法引用的对象</li>
</ul>
<h3 id="可达性分析算法"><a href="#可达性分析算法" class="headerlink" title="可达性分析算法"></a>可达性分析算法</h3><p>至少两次标记过程,第一次标记筛选出有必要执行的 finalize() 方法的对象,对象可在 finalize() 中自救一次,因为 finalize() 方法只会被系统自动调用一次。</p>
<h3 id="回收算法"><a href="#回收算法" class="headerlink" title="回收算法"></a>回收算法</h3><ul>
<li>标记-清除算法<br>效率不高,会产生大量不连续的内存碎片</li>
<li>复制算法<br>新生代采用复制算法收集内存,大对象通过分配担保机制进入老年代</li>
<li>标记-整理算法<br>将存活的对象移至一端,减少内存碎片</li>
<li>分代收集算法<br>根据年代特点采用最适当的算法,需要上述算法支持</li>
</ul>
<h3 id="内存分配"><a href="#内存分配" class="headerlink" title="内存分配"></a>内存分配</h3><blockquote>
<p>都可通过参数设定</p>
</blockquote>
<ul>
<li>对象优先在 Eden 中分配</li>
<li>大对象直接进入老年代</li>
<li>长期存活的对象将进入老年代<br>年龄计数器</li>
<li>动态对象年龄判断<br>Survivor 空间中相同年龄所有对象大小总合大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就直接进入老年代</li>
<li>空间分配担保<br>需要检查老年代的空间是否满足新生代所有对象空间,不够的话还要查看设置的值是否允许冒险,以决定 FullGC 是否有必要</li>
</ul>
<h2 id="类加载"><a href="#类加载" class="headerlink" title="类加载"></a>类加载</h2><ul>
<li>加载<br>获取字节流,生成对象,提供数据访问入口</li>
<li>验证<br>是否符合虚拟机规范</li>
<li>准备<br>为变量分配值</li>
<li>解析<br>将符号引用替换为直接引用</li>
<li>初始化<br>执行类构造器 <clinit>() 方法</clinit></li>
</ul>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>Java 内存模型与 volatile</title>
<url>/jmm-volatile/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/coffee-1580595_960_720.jpg" class="full-image" width="60%"><br></p>
<h2 id="感悟"><a href="#感悟" class="headerlink" title="感悟"></a>感悟</h2><p>最近看《深入理解 Java 虚拟机》的一些笔记,又是一本相见恨晚的书,强烈推荐前几章和后面几章。</p>
<a id="more"></a>
<h2 id="内存模型"><a href="#内存模型" class="headerlink" title="内存模型"></a>内存模型</h2><p><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/test.png" alt="image"></p>
<p>此图来自《深入理解 Java 虚拟机》,看完以后感觉这个知识水平都提高了2333。这里的主内存不是内存条,而是虚拟机的内存的一部分。不同的线程通过刷新主内存中的值来进行同步。如果没有线程并发的考虑,闭着眼睛就能想到数据的不一致。</p>
<p>内存模型定义了以下 8 种操作来完成主内存与工作内存同步的细节,除去特殊情况,每一个操作是原子不可再分的</p>
<ul>
<li>lock</li>
<li>unlock</li>
<li>read</li>
<li>load</li>
<li>use</li>
<li>assign</li>
<li>store</li>
</ul>
<p>另外还定义了一些规则,太多了没咋记住……不过也以此引出了最为常见的先行发生的原则,用于确定访问是否线程安全。</p>
<h2 id="happen-before-规则"><a href="#happen-before-规则" class="headerlink" title="happen-before 规则"></a>happen-before 规则</h2><p>中文名叫先行发生规则,含义是Java 内存模型下天然存在一些关系,无需同步器去实现,可以在编码中直接使用。换句话说,不在先行发生规则的两个操作,虚拟机可以对它们进行重排序,也就是线程不安全了。</p>
<p>规则有八条:</p>
<ul>
<li>程序次序规则<br>同一线程按照控制流顺序</li>
<li>管程锁定规则<br>unlock 指令操作先于 lock 操作</li>
<li>volatile 变量规则、<br>写操作先于读操作</li>
<li>线程启动规则<br>start 最先发生</li>
<li>线程终止规则<br>终止检测最后发生</li>
<li>线程中断规则<br>interrupt() 先行发生于代码检测中断</li>
<li>对象终结规则<br>初始化先于 finalize</li>
<li>传递性<br>A 先于 B,B 先于 C</li>
</ul>
<p>需要注意的一点是,时间先后顺序与先行发生顺序没有太大的关系,一切以先行发生的原则为准。</p>
<h2 id="volatile"><a href="#volatile" class="headerlink" title="volatile"></a>volatile</h2><blockquote>
<p>有了内存模型的概念,对 volatile 又有了几分理解<br>Java 虚拟机提供的最轻量的同步机制,当一个变量被定义为 volatile 时有一下两种语义</p>
</blockquote>
<h3 id="可见性"><a href="#可见性" class="headerlink" title="可见性"></a>可见性</h3><p>volatile 变量对所有线程是立即可见的,对 volatitle 变量所有写操作都能立即反映到其他线程中。但注意他并不是安全的,因为该操作不是原子性的。所谓原子性,就是该变量执行如运算等操作只有等它运算完写入主内存中,其他线程才能操作该变量。没错,保证原子性你可以理解为加个锁。</p>
<h3 id="禁止指令重排序"><a href="#禁止指令重排序" class="headerlink" title="禁止指令重排序"></a>禁止指令重排序</h3><blockquote>
<p>指令重排序指操为了采用流水线机制加快指令的处理速度<br>重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境。重排序的前提是需要满足以下条件</p>
<ol>
<li>在单线程环境下不能改变程序运行的结果; </li>
<li>存在数据依赖关系的不允许重排序</li>
</ol>
</blockquote>
<p>普通变量仅仅保证在方法执行过程中所有依赖赋值结果的地方能获取正确结果,而不能保证赋值操作和代码执行顺序一样</p>
<h3 id="如何实现"><a href="#如何实现" class="headerlink" title="如何实现"></a>如何实现</h3><ul>
<li>在该变量的写操作之前编译器插入一个写屏障</li>
<li>在该变量的读操作之前编译器插入一个读屏障</li>
</ul>
<p>翻译到汇编代码层面 <code>lock addl $0x0,(%esp)</code> 就是将 ESP 寄存器的值加 0,使本 CPU 的 Cache 写入内存,该写入操作会引起别的 CPU 或者别的内核无效化其 Cache。通过该空操作让前面对 volatile 变量的修改对其他 CPU 立即可见。</p>
<p>重排序为了优化,至于禁止重排序,也是将该变量的值强制刷出缓存,将修改同步到主内存,意味着所有之前的操作已经完成,也就达到了无法跨越内存屏障的效果了。这里要仔细体会。</p>
<h3 id="注意点"><a href="#注意点" class="headerlink" title="注意点"></a>注意点</h3><ul>
<li>volatile 不保证原子性</li>
<li>屏蔽指令重排序操作 JDK 1.5 中才被修复,此前不可完全避免重排序</li>
</ul>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>强烈推荐《深入理解 Java 虚拟机》,看目录你会发现那些曾几何时听说过晦涩难懂的名字都会在此书中讲到。</p>
]]></content>
<categories>
<category>Java</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title>几道面试题</title>
<url>/interview/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190321105440.png" class="full-image"><br></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><blockquote>
<p>复习的时候就想写了,为自己做点笔记,加深印象理解原理吧。</p>
</blockquote>
<a id="more"></a>
<h2 id="题目"><a href="#题目" class="headerlink" title="题目"></a>题目</h2><blockquote>
<p>又一个我敬佩的人 <a href="https://www.zhihu.com/question/19596615/answer/12327310" target="_blank" rel="noopener">CaoZ 老师</a>分享在知识星球的片段</p>
</blockquote>
<ol>
<li>从你浏览器输入网址,到网页打开。中间都经历了什么。</li>
<li>如果现在有用户反馈你的网站打开很慢,或者说打不开,你考虑的判断和排查步骤是什么,以及为什么。</li>
<li>现在数据库出现了 too many connections 错误,请问排查思路和后续动作是什么。</li>
</ol>
<h2 id="理解"><a href="#理解" class="headerlink" title="理解"></a>理解</h2><h3 id="第一题"><a href="#第一题" class="headerlink" title="第一题"></a>第一题</h3><p>乍一看像 DNS 题,定睛一看,还是一道 DNS 题。其实不尽然。说下我看完曹老师文章后的理解。</p>
<p>从输入网址,浏览器会检查域名是否在缓存当中,若是国内第三方“良心”浏览器会触发钩子,会跳转微软搜索页面。然后才是本地 host 文件的判断。这个文件映射的是键值对,在 GFW 没有升高之前,我通过更改 hosts 文件还去看了一下世界。当然那时候也不懂什么 hosts,到后来才慢慢接触了解到。</p>
<p>如若本地客户端仍没有完成解析,就会真正请求域名服务器来解析这个域名。首先从网络配置中获取本地 DNS 解析服务器地址,一般不会离得太远,而且性能极好,能完成 80% 的工作。缓存时间根据 TTL 值控制。</p>
<p>若本地 DNS 仍没有命中,需根据本地 DNS 设置(是否含有转发器进行查询)。如果没有转发模式,直接查找根服务器,要求查找该 URL 中顶级域名服务器(gTLD)。然后依次查找权威 DNS 服务器,例如 <code>github.com</code> 的权威服务器。之所以叫他权威服务器是因为管理着众多二级域名。他将给本地 DNS 服务器返回一个具体的 IP 地址。本地 DNS 服务器将缓存结果的同时发送给客户端。当然有很多权威服务器做了全局均衡代理,权威服务器将返回众多 IP。客户端 DNS 解析器缓存结果并通过随机或者轮询等机制进行访问。</p>
<p>如果用的是转发模式,本地 DNS 则会将请求转发至上一级 DNS 服务器。上一级则会将请求转发上上一级或者寻找根 DNS。</p>
<h2 id="第二题"><a href="#第二题" class="headerlink" title="第二题"></a>第二题</h2><p>场景题,虽然还是学生,但是我认为很真实。</p>
<p>首先当然自己打开网站试试喽。如果正常,考虑全国测速,并进行 CDN 全国加速(CDN 部署时个人认为就要加上)。如果慢,一种特殊的情况是 DNS 解析出问题了,直接 IP 访问试试。还可以用 Chrome 开发者工具进行相应的抓包等。</p>
<h2 id="第三题"><a href="#第三题" class="headerlink" title="第三题"></a>第三题</h2><p>查看连接池日志,当然我也会优先考虑数据库连接有没有 close 的问题,其次是高并发下出现阻塞,导致大量连接被阻塞。然后再查看数据库相关的连接配置。</p>
<h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><ul>
<li><a href="https://github.com/alex/what-happens-when" target="_blank" rel="noopener">what-happens-when</a></li>
<li><a href="https://mp.weixin.qq.com/s?__biz=MzI0MjA1Mjg2Ng==&mid=209679438&idx=1&sn=d68c1512ad23f6e164f69bd351a18c62&scene=7&ascene=0&devicetype=android-27&version=2607033a&nettype=WIFI&abtest_cookie=BAABAAoACwASABQABAAmlx4AV5keAJuZHgCgmR4AAAA%3D&lang=zh_CN&pass_ticket=IwU%2BrHnkJALzgEGVy5PIkB2lrT7AmStPIpUk58wRR6g%3D&wx_header=1" target="_blank" rel="noopener">caoz的梦呓</a></li>
<li><a href="https://www.percona.com/blog/2013/11/28/mysql-error-too-many-connections/" target="_blank" rel="noopener">mysql-error-too-many-connections</a></li>
</ul>
]]></content>
<categories>
<category>面试</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>面试</tag>
<tag>知识星球</tag>
</tags>
</entry>
<entry>
<title>空谷幽兰,心如皓月</title>
<url>/for-interview/</url>
<content><![CDATA[<p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190317191958.png" class="full-image"><br></p>
<h2 id="杂谈"><a href="#杂谈" class="headerlink" title="杂谈"></a>杂谈</h2><p><a href="https://yi-yun.github.io/final2018/">2018 年终总结</a>给自己立的每周输出两三篇博客的 flag 快倒了……此篇就当这几天为春招奋战的总结了。</p>
<a id="more"></a>
<h2 id="现状"><a href="#现状" class="headerlink" title="现状"></a>现状</h2><p>很不幸的是,在今天之前只投了两份简历,一份被拒了,还有一份内推到的笔试。然而这笔试什么玩意,分两场笔试,</p>
<p>一场 30 分钟的逻辑推理。这尼玛真的有病,浪费我感情。我看了几道根本看不出来规律,就开始乱选了。还有一场正规的笔试,没发挥好,也可以说第一次没经验,菜。很多基本的选择题没有复习,点了下一题后还不能改,三道算法题一道没写出来。不过唯一的好处就是,知道了 笔试的形式,也为以后做了准备23333。</p>
<h2 id="笔试之后"><a href="#笔试之后" class="headerlink" title="笔试之后"></a>笔试之后</h2><p>当然是倍受打击了,至于能不能像小说主人公那样在后面逆转我就不知道了。</p>
<h3 id="选择"><a href="#选择" class="headerlink" title="选择"></a>选择</h3><p>上篇博文提到了希望杯比赛,可能很多人不知道。如果换个名字,挑战杯就会很熟悉了。上回说到,我为了校赛答辩准备很久,也牺牲了一部分准备春招的时间。天真的以为过了校赛答辩就可以松一口气了,但实验室的老师明显是想让我拼一拼从省一进国赛。我提出了接下来我的想法,老师不置可否。。</p>
<h3 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h3><blockquote>
<p>我当然是想准备春招了,一生只有一次。</p>
</blockquote>
<p>指导老师嘛总是忽悠我去努力争取一下省一,还提出了有奖金啊啥的,实习的事可以放一放,暑假的事又不急。</p>
<p>我当时心里一万个 mmp,终于体会到了什么叫做身不由己。首先,我很明确的想过,春招和挑战杯的事情,以春招占大头。因为我想进大厂,甚至想直接转正。这是乌鸡变凤凰的最好时机,而老师却认为暑期小公司实习就差不多了。</p>
<p>其次,跟我说奖金和报销经费。他们竟然认为我是为了钱才去实习的。拜托,搞清楚,这些小钱我根本不放在眼里。你确定 10000 块钱跟阿里、头条等大厂的实习 Offer 比起来算事么???我当时就差点甩出一句,现在你给我两万块钱现金,我眉头都不会皱一下地离开去准备春招。</p>
<p>当然上面的话都是我后面的心理活动,并没有在表面上与老师撕破脸皮,只是隐晦的表达我还是要准备面试的意思。但那天我真的很气。气自己没敢说,气老师信息获取滞后。其实,跟我们学院的总体环境有关系。我隐约认为他们根本没有意识到春招秋招的重要性,或者,他们太为自己、学院的名誉着想了,并不在意学生的前途。</p>
<h2 id="理想"><a href="#理想" class="headerlink" title="理想"></a>理想</h2><blockquote>
<p>上面那些话窝在肚子里很久了,讲出来也舒服点。</p>
</blockquote>
<p>最近在网络上发现了不少优秀大佬的博客笔记等</p>
<ul>
<li><a href="https://coolshell.cn/" target="_blank" rel="noopener">左耳朵耗子</a><br>本文文章名也取自他的座右铭。其实,寒假的时候他的博客就在收藏夹里了,也订阅了他的极客专栏。这尼玛简直是程序员的偶像,也是我未来奋斗的目标。<br>我一直想把博客做成他那样子,游客点进一篇文章,便被他的作者吸引得浏览全站。随后又发现了更多有意思的文章,就像酒香何必在意巷深那样,越品越有味道。我特别喜欢这种感觉,如若能交流一下交个朋友定是极好的,比如下面这位。</li>
<li><a href="https://github.com/Kuangcp/" target="_blank" rel="noopener">Kuangcp</a><br>我 <a href="https://github.com/yi-yun/" target="_blank" rel="noopener">GitHub</a> 上唯一关注的人,他的笔记仓库让我叹为观止。</li>
</ul>
]]></content>
<categories>
<category>日常记录</category>
</categories>
<tags>
<tag>个人</tag>
<tag>春招</tag>
<tag>未来</tag>
<tag>思考</tag>
<tag>记录</tag>
</tags>
</entry>
<entry>
<title>魔鬼藏在细节中</title>
<url>/details/</url>
<content><![CDATA[<p></p><p align="center"><br><img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190310211820.png" class="full-image"><br></p><p></p>
<h2 id="碎碎念"><a href="#碎碎念" class="headerlink" title="碎碎念"></a>碎碎念</h2><blockquote>
<p> The devil is in the details.</p>
</blockquote>
<p>被拒了简历,心情低落…</p>
<a id="more"></a>
<h2 id="答辩"><a href="#答辩" class="headerlink" title="答辩"></a>答辩</h2><p>本来也没啥,就是整个团队去拿着项目参加比赛,我只是该项目总负责人以及后端开发。但是很不幸的是,团队里考研的考研,划水的划水,也就只剩我去演讲……</p>
<p>那么问题就来了,一写代码的让我分享技术啥的我倒还可以凑活,这尼玛直接介绍项目让我很难受啊……</p>
<p>以上纯属牢骚,有点偏题了,但是在金三银四的黄金校招周中,每分每秒都十分宝贵。然而我还是不敢跟老师明说,不过我已经说明,忙完希望杯就不干活了,就当这几天为以后收利息了吧,虽然付出的代价也挺大的。</p>
<h2 id="细节"><a href="#细节" class="headerlink" title="细节"></a>细节</h2><blockquote>
<p>我在这立个 flag,能进省赛<br>答辩时的细节</p>
</blockquote>
<ul>
<li>微笑面对评委老师<br>不过他们没怎么看我2333</li>
<li>在答辩结束后竟然还能询问<br>真的是细节,我没有想到。这次比赛主要是给专家看有哪几个项目可以参加省赛的,有指导意义,也是老师不找演讲人的理由。所以,辅导员在结束后带着我们又找了一下三位和蔼可亲的评委老师。虽然已经评完分了,但我认为真的很有必要。</li>
</ul>
<h2 id="差距"><a href="#差距" class="headerlink" title="差距"></a>差距</h2><p>我们学院还有一组是关于图像的科技创新作品,但是在论文学术类以及科技发明类摇摆不定,被评委建议目标应该明确。项目中有几篇是在 SCI (大概是叫这个名字吧,不了解)发表的,但评委说不在二区一文不值。一旦出校在省内比拼,浙大的论文水平绝对碾压我们学校,根本没有可比性。这时,我才意识到学校差距的存在。</p>
<p>我也加了很多内推实习群,当看到那些 985/211 的 ID,感慨竞争对手的强大,绝对不亚于高考。</p>
<p>高考我已经输过一次了,没有人想输第二次。</p>
<h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><blockquote>
<p>古代剑客们在与对手狭路相逢时,无论对手有多么强大,就算对方是天下第一剑客,明知不敌,也要亮出自己的宝剑,即使倒在对手的剑下,也虽败尤荣。</p>
</blockquote>
<p>杀入春招。</p>
]]></content>
<categories>
<category>日常记录</category>
</categories>
<tags>
<tag>个人</tag>
<tag>学习</tag>
<tag>项目</tag>
<tag>春招</tag>
</tags>
</entry>
<entry>
<title>一个热点玩转树莓派</title>
<url>/raspberry-setting/</url>
<content><![CDATA[<p></p><p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190227154346.png" class="full-class"><br></p><br><!--[TOC]--><p></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>前几天<a href="https://blog.asucreyau.xyz" target="_blank" rel="noopener">千魂剑</a>问我关于树莓派的问题,好久不用了,感觉有点遗忘,就有了此篇文章。</p>
<a id="more"></a>
<h2 id="安装系统"><a href="#安装系统" class="headerlink" title="安装系统"></a>安装系统</h2><ul>
<li><a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank" rel="noopener">官方下载地址</a><br>对是压缩包,所以 Windows 下的 <a href="https://sourceforge.net/projects/win32diskimager/files/latest/download" target="_blank" rel="noopener">Win32 Disk Imager</a> 可以直接刻录 zip 到 TF 卡</li>
</ul>
<h3 id="工具推荐"><a href="#工具推荐" class="headerlink" title="工具推荐"></a>工具推荐</h3><ul>
<li>读卡器<br>虽然 SD 卡也可以,但现在很多电脑没有 SD 卡槽</li>
<li>镜像烧录<ul>
<li>Win<ul>
<li><a href="http://rufus.ie/" target="_blank" rel="noopener">Rufus</a></li>
</ul>
</li>
<li>Mac<br>买不起,没用过</li>
<li>Linux<ul>
<li>dd 命令</li>
</ul>
</li>
</ul>
</li>
</ul>
<h2 id="ssh"><a href="#ssh" class="headerlink" title="ssh"></a>ssh</h2><blockquote>
<p>两种方法,网线,热点,但两者需要在一个局域网内 。<br>拥有屏幕的用户请路过…</p>
</blockquote>
<h3 id="网线"><a href="#网线" class="headerlink" title="网线"></a>网线</h3><p>连一根网线到路由器,在路由器后台查看 IP 撒花完结。</p>
<h3 id="热点"><a href="#热点" class="headerlink" title="热点"></a>热点</h3><blockquote>
<p>其实,树莓派基金会为了达成这个需求, 2017-2018 年逐渐在改善系统来适应这种优雅的方式,所以此方法只适用于新版系统。</p>
</blockquote>
<ol>
<li>打开烧录好的内存卡文件夹</li>
<li>找到 <code>/boot</code> 分区</li>
<li>建立一个空的 <code>ssh</code> 文件以及 <code>wpa_supplicant.conf</code> <figure class="highlight plain"><table><tr><td class="code"><pre><span class="line">country=GB</span><br><span class="line">ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev</span><br><span class="line">update_config=1</span><br><span class="line">network={</span><br><span class="line"> ssid="你的Wifi名称,注意大小写"</span><br><span class="line"> psk="你的Wifi密码"</span><br><span class="line">}</span><br></pre></td></tr></table></figure>
</li>
</ol>
<p>说明:空的 ssh 文件是为了开启 ssh 服务,系统默认不开启;wpa_supplicant.conf 是为了自动连接热点,ssid 支持中文。开机会将会删除以上两个文件。</p>
<h2 id="raspi-config"><a href="#raspi-config" class="headerlink" title="raspi-config"></a>raspi-config</h2><blockquote>
<p>默认管理员用户为 pi,密码为 raspberry</p>
</blockquote>
<ul>
<li>设置时间</li>
<li>将 tf 卡填充满<br>默认系统只占很少的空间</li>
</ul>
<h2 id="镜像源更改"><a href="#镜像源更改" class="headerlink" title="镜像源更改"></a>镜像源更改</h2><blockquote>
<p>树莓派源分为两种,一种为树莓派基金会提供,另一种由独立开发者提供</p>
</blockquote>
<ul>
<li>查询版本号<br><code>lsb_release -a</code> 不一样的版本更改源的地址不一样,版本号有 Stretch、Jessie 等,一般最新的是 <code>Stretch</code></li>
<li><p>官方源修改<br>这个软件源相关资料比较少,修改树莓派基金会单独提供的源</p>
<figure class="highlight plain"><figcaption><span>/etc/apt/sources.list.d/raspi.list</span></figcaption><table><tr><td class="code"><pre><span class="line">deb https://mirrors.tuna.tsinghua.edu.cn/raspberrypi/ stretch main ui</span><br></pre></td></tr></table></figure>
</li>
<li><p>开发源修改</p>
<figure class="highlight plain"><figcaption><span>/etc/apt/sources.list</span></figcaption><table><tr><td class="code"><pre><span class="line">deb http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi</span><br><span class="line">deb-src http://mirrors.tuna.tsinghua.edu.cn/raspbian/raspbian/ stretch main contrib non-free rpi</span><br></pre></td></tr></table></figure>
</li>
</ul>
<p>最后别忘了 <code>sudo apt-get update</code> 更新系统</p>
<h2 id="个人体验"><a href="#个人体验" class="headerlink" title="个人体验"></a>个人体验</h2><blockquote>
<p>我是拿树莓派当本地服务器的</p>
</blockquote>
<ul>
<li>喜欢纯命令行,不喜欢 VNC,而且感觉有点卡顿</li>
<li>风扇有点响,据说要买那种悬浮的,然而我是一套</li>
<li>散热片、亚克力壳,就是好看</li>
<li>不下片的话,8G TF 卡够了</li>
</ul>
<h2 id="参考链接"><a href="#参考链接" class="headerlink" title="参考链接"></a>参考链接</h2><ul>
<li><a href="https://www.jianshu.com/p/67b9e6ebf8a0" target="_blank" rel="noopener">树莓派—raspbian软件源(全)</a></li>
<li><a href="https://www.jianshu.com/p/f260967aefb1" target="_blank" rel="noopener">树莓派如何完全无头(无屏无网线无键盘鼠标)安装</a></li>
</ul>
]]></content>
<categories>
<category>树莓派</category>
</categories>
<tags>
<tag>笔记</tag>
<tag>树莓派</tag>
<tag>设置</tag>
</tags>
</entry>
<entry>
<title>清除 Git 敏感信息</title>
<url>/clean-git-passwd/</url>
<content><![CDATA[<p></p><p align="center"><br> <img src="https://yiyun-1253940215.cos.ap-shanghai.myqcloud.com/20190221203616.png" class="full-class"><br></p><p></p>
<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>算是 Git 的奇淫怪技</p>
<a id="more"></a>
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>偶然在水群时看到一条消息,有人将服务器密码提交到了 Git 记录上。众所周知,公有仓库的 Git 记录是所有人可见的。所以一旦有敏感信息,不法分子就可以从你的 commit 记录中寻找突破口。</p>
<h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><h3 id="Git-命令行"><a href="#Git-命令行" class="headerlink" title="Git 命令行"></a>Git 命令行</h3><figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git filter-branch --force --index-filter <span class="string">'git rm --cached --ignore-unmatch sensitive-data.py'</span> --prune-empty --tag-name-filter cat -- --all</span><br><span class="line">git push origin --force –all</span><br></pre></td></tr></table></figure>
<p>这是我谷歌的命令,大概是在 Git 记录中删除带有敏感信息的文件,然后强制 push</p>
<h3 id="BFG"><a href="#BFG" class="headerlink" title="BFG"></a>BFG</h3><p>那么有没有更优雅的方法呢,答案是肯定的。</p>
<p>如标题所言,<a href="https://rtyley.github.io/bfg-repo-cleaner/" target="_blank" rel="noopener">BFG Repo Cleaner</a> 能帮到我们。该工具是用 Scala 写的,专门为清除 Git 提交记录中带有敏感信息而产生的。</p>
<h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h4><blockquote>
<p>需要 Java 7 以上版本</p>
</blockquote>
<ul>
<li>安装以及使用<ul>
<li>点<a href="https://mvnrepository.com/artifact/com.madgag/bfg" target="_blank" rel="noopener">此</a>下载 jar 包<br><code>java -jar bfg.jar 命令参数</code></li>
<li>yay -S bfg<br><code>bfg 命令参数</code></li>
</ul>
</li>
</ul>
<p>如上所示,有两种安装方式,第一种是通用的运行下载的 jar 包,另一种是为 Arch 用户准备的…<del>(这时候就要喊出“Arch 牛逼”)</del>因为我是 Arch 忠实粉丝,所以就以 Arch 中的命令作为示范…</p>
<h4 id="测试"><a href="#测试" class="headerlink" title="测试"></a>测试</h4><p>在 GitHub 仓库中创建一个专门来测试的仓库(我学 Git 的时候就已经有一个专门用来测试 Git 的仓库),将密码假装不小心上传到 GitHub。</p>
<p>当发现后,重新将密码去除后重新提交到 GitHub。此时,如果不看 commit 记录就不会知道历史版本,bfg 这个工具就为了防止有心人通过你的 commit 记录捕获你的敏感信息</p>
<ul>
<li><p>克隆仓库的 .git 文件夹</p>
<figure class="highlight bash"><table><tr><td class="code"><pre><span class="line">git <span class="built_in">clone</span> --mirror [email protected]:yi-yun/git777github-learn.git</span><br></pre></td></tr></table></figure>
</li>
<li><p>在本地创建 replace.txt<br>文本名字是任意的,文本内容需要将密码填上,默认替换成 <code>***REMOVED***</code>,也可以将其替换成自己想要的字符,规则如下所示</p>