├── .gitattributes
├── EssentialContentForInterview
├── BATJrealInterviewExperience
│ └── 5面阿里,终获offer.md
├── MostCommonJavaInterviewQuestions
│ ├── 第一周(2018-8-7).md
│ ├── 第二周(2018-8-13).md
│ └── 第四周(2018-8-30).md
├── PreparingForInterview
│ ├── JavaInterviewLibrary.md
│ ├── JavaProgrammerNeedKnow.md
│ ├── books.md
│ ├── interviewPrepare.md
│ ├── 如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md
│ ├── 程序员的简历之道.md
│ └── 美团面试常见问题总结.md
├── 手把手教你用Markdown写一份高质量的简历.md
├── 简历模板.md
└── 面试必备之乐观锁与悲观锁.md
├── Java
├── ArrayList-Grow.md
├── ArrayList.md
├── BIO,NIO,AIO summary.md
├── HashMap.md
├── J2EE基础知识.md
├── Java IO与NIO.md
├── Java基础知识.md
├── Java虚拟机(jvm).md
├── Java集合框架常见面试题总结.md
├── LinkedList.md
├── Multithread
│ ├── AQS.md
│ ├── Atomic.md
│ ├── BATJ都爱问的多线程面试题.md
│ └── 并发容器总结.md
├── What's New in JDK8
│ ├── JDK8接口规范-静态、默认方法.md
│ ├── Java8Tutorial.md
│ ├── Lambda表达式.md
│ ├── README.md
│ ├── 改进的类型推断.md
│ └── 通过反射获得方法的参数信息.md
├── final、static、this、super.md
├── synchronized.md
├── 可能是把Java内存区域讲的最清楚的一篇文章.md
├── 多线程系列.md
├── 搞定JVM垃圾回收就是这么简单.md
├── 设计模式.md
└── 这几道Java集合框架面试题几乎必问.md
├── README.md
├── 主流框架
├── SpringBean.md
├── SpringMVC 工作原理详解.md
├── Spring学习与面试.md
├── ZooKeeper.md
└── ZooKeeper数据模型和常见命令.md
├── 操作系统
├── Shell.md
└── 后端程序员必备的Linux基础知识.md
├── 数据存储
├── MySQL Index.md
├── MySQL.md
└── Redis
│ ├── Redis.md
│ ├── Redis持久化.md
│ ├── Redlock分布式锁.md
│ └── 如何做可靠的分布式锁,Redlock真的可行么.md
├── 数据结构与算法
├── Leetcode-LinkList1.md
├── source code
│ └── securityAlgorithm
│ │ ├── .classpath
│ │ ├── .gitignore
│ │ ├── .project
│ │ ├── .settings
│ │ ├── org.eclipse.core.resources.prefs
│ │ ├── org.eclipse.jdt.core.prefs
│ │ └── org.eclipse.m2e.core.prefs
│ │ ├── pom.xml
│ │ └── src
│ │ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── snailclimb
│ │ │ └── ks
│ │ │ └── securityAlgorithm
│ │ │ ├── Base64Demo.java
│ │ │ ├── DesDemo.java
│ │ │ ├── IDEADemo.java
│ │ │ ├── MD5.java
│ │ │ ├── MD5Demo.java
│ │ │ ├── RSADemo.java
│ │ │ ├── SHA1Demo.java
│ │ │ └── readme
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── snailclimb
│ │ └── ks
│ │ └── securityAlgorithm
│ │ └── AppTest.java
├── 常见安全算法(MD5、SHA1、Base64等等)总结.md
├── 搞定BAT面试——几道常见的子符串算法题.md
├── 数据结构.md
├── 算法.md
└── 算法题解析
│ ├── 公司真题
│ └── 网易2018校招编程题1-3.md
│ └── 剑指offer
│ ├── (1)斐波那契数列问题和跳台阶问题.md
│ ├── (2)二维数组查找和替换空格问题.md
│ ├── (3)数值的整数次方和调整数组元素顺序.md
│ ├── (4)链表相关编程题.md
│ └── (5)栈变队列和栈的压入、弹出序列.md
├── 架构
├── 8 张图读懂大型网站技术架构.md
├── 【面试精选】关于大型网站系统架构你不得不懂的10个问题.md
└── 分布式.md
├── 计算机网络与数据通信
├── HTTPS中的TLS.md
├── dubbo.md
├── message-queue.md
├── rabbitmq.md
├── 干货:计算机网络知识总结.md
├── 数据通信(RESTful、RPC、消息队列).md
└── 计算机网络.md
└── 闲谈
├── 2018 summary.md
├── 2018 秋招.md
├── JavaGithubTrending
├── 2018-12.md
├── 2019-1.md
├── 2019-2.md
└── JavaGithubTrending.md
├── 个人阅读书籍清单.md
└── 选择技术方向都要考虑哪些因素.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 | *.js linguist-language=java
4 | *.css linguist-language=java
5 | *.html linguist-language=java
--------------------------------------------------------------------------------
/EssentialContentForInterview/BATJrealInterviewExperience/5面阿里,终获offer.md:
--------------------------------------------------------------------------------
1 | > 作者:ppxyn。本文来自读者投稿,同时也欢迎各位投稿,**对于不错的原创文章我根据你的选择给予现金(50-200)、付费专栏或者任选书籍进行奖励!所以,快提 pr 或者邮件的方式(邮件地址在主页)给我投稿吧!** 当然,我觉得奖励是次要的,最重要的是你可以从自己整理知识点的过程中学习到很多知识。
2 |
3 | **目录**
4 |
5 |
6 |
7 | - [前言](#前言)
8 | - [一面\(技术面\)](#一面技术面)
9 | - [二面\(技术面\)](#二面技术面)
10 | - [三面\(技术面\)](#三面技术面)
11 | - [四面\(半个技术面\)](#四面半个技术面)
12 | - [五面\(HR面\)](#五面hr面)
13 | - [总结](#总结)
14 |
15 |
16 |
17 | ### 前言
18 |
19 | 在接触 Java 之前我接触的比较多的是硬件方面,用的比较多的语言就是C和C++。到了大三我才正式选择 Java 方向,到目前为止使用Java到现在大概有一年多的时间,所以Java算不上很好。刚开始投递的时候,实习刚辞职,也没准备笔试面试,很多东西都忘记了。所以,刚开始我并没有直接就投递阿里,毕竟心里还是有一点点小害怕的。于是,我就先投递了几个不算大的公司来练手,就是想着刷刷经验而已或者说是练练手(ps:还是挺对不起那些公司的)。面了一个月其他公司后,我找了我实验室的学长内推我,后面就有了这5次面试。
20 |
21 | 下面简单的说一下我的这5次面试:4次技术面+1次HR面,希望我的经历能对你有所帮助。
22 |
23 | ### 一面(技术面)
24 |
25 | 1. 自我介绍(主要讲自己会的技术细节,项目经验,经历那些就一语带过,后面面试官会问你的)。
26 | 2. 聊聊项目(就是一个很普通的分布式商城,自己做了一些改进),让我画了整个项目的架构图,然后针对项目抛了一系列的提高性能的问题,还问了我做项目的过程中遇到了那些问题,如何解决的,差不读就这些吧。
27 | 3. 可能是我前面说了我会数据库优化,然后面试官就开始问索引、事务隔离级别、悲观锁和乐观锁、索引、ACID、MVVC这些问题。
28 | 4. 浏览器输入URL发生了什么? TCP和UDP区别? TCP如何保证传输可靠性?
29 | 5. 讲下跳表怎么实现的?哈夫曼编码是怎么回事?非递归且不用额外空间(不用栈),如何遍历二叉树
30 | 6. 后面又问了很多JVM方面的问题,比如Java内存模型、常见的垃圾回收器、双亲委派模型这些
31 | 7. 你有什么问题要问吗?
32 |
33 | ### 二面(技术面)
34 |
35 | 1. 自我介绍(主要讲自己会的技术细节,项目经验,经历那些就一语带过,后面面试官会问你的)。
36 | 2. 操作系统的内存管理机制
37 | 3. 进程和线程的区别
38 | 4. 说下你对线程安全的理解
39 | 5. volatile 有什么作用 ,sychronized和lock有什么区别
40 | 6. ReentrantLock实现原理
41 | 7. 用过CountDownLatch么?什么场景下用的?
42 | 8. AQS底层原理。
43 | 9. 造成死锁的原因有哪些,如何预防?
44 | 10. 加锁会带来哪些性能问题。如何解决?
45 | 11. HashMap、ConcurrentHashMap源码。HashMap是线程安全的吗?Hashtable呢?ConcurrentHashMap有了解吗?
46 | 12. 是否可以实习?
47 | 13. 你有什么问题要问吗?
48 |
49 | ### 三面(技术面)
50 |
51 | 1. 有没有参加过 ACM 或者他竞赛,有没有拿过什么奖?( 我说我没参加过ACM,本科参加过数学建模竞赛,名次并不好,没拿过什么奖。面试官好像有点失望,然后我又赶紧补充说我和老师一起做过一个项目,目前已经投入使用。面试官还比较感兴趣,后面又和他聊了一下这个项目。)
52 | 2. 研究生期间,做过什么项目,发过论文吗?有什么成果吗?
53 | 3. 你觉得你有什么优点和缺点?你觉得你相比于那些比你更优秀的人欠缺什么?
54 | 4. 有读过什么源码吗?(我说我读过 Java 集合框架和 Netty 的,面试官说 Java 集合前几面一定问的差不多,就不问了,然后就问我 Netty的,我当时很慌啊!)
55 | 5. 介绍一下自己对 Netty 的认识,为什么要用。说说业务中,Netty 的使用场景。什么是TCP 粘包/拆包,解决办法。Netty线程模型。Dubbo 在使用 Netty 作为网络通讯时候是如何避免粘包与半包问题?讲讲Netty的零拷贝?巴拉巴拉问了好多,我记得有好几个我都没回答上来,心里想着凉凉了啊。
56 | 6. 用到了那些开源技术、在开源领域做过贡献吗?
57 | 7. 常见的排序算法及其复杂度,现场写了快排。
58 | 8. 红黑树,B树的一些问题。
59 | 9. 讲讲算法及数据结构在实习项目中的用处。
60 | 10. 自己的未来规划(就简单描述了一下自己未来的设想啊,说的还挺诚恳,面试官好像还挺满意的)
61 | 11. 你有什么问题要问吗?
62 |
63 | ### 四面(半个技术面)
64 |
65 | 三面面完当天,晚上9点接到面试电话,感觉像是部门或者项目主管。 这个和之前的面试不大相同,感觉面试官主要考察的是你解决问题的能力、学习能力和团队协作能力。
66 |
67 | 1. 让我讲一个自己觉得最不错的项目。然后就巴拉巴拉的聊,我记得主要是问了项目是如何进行协作的、遇到问题是如何解决的、与他人发生冲突是如何解决的这些。感觉聊了挺久。
68 | 2. 出现 OOM 后你会怎么排查问题?
69 | 3. 自己平时是如何学习新技术的?除了 Java 还回去了解其他技术吗?
70 | 4. 上一段实习经历的收获。
71 | 5. NginX如何做负载均衡、常见的负载均衡算法有哪些、一致性哈希的一致性是什么意思、一致性哈希是如何做哈希的
72 | 6. 你有什么问题问我吗?
73 | 7. 还有一些其他的,想不起来了,感觉这一面不是偏向技术来问。
74 |
75 | ## 五面(HR面)
76 |
77 | 1. 自我介绍(主要讲能突出自己的经历,会的编程技术一语带过)。
78 | 2. 你觉得你有什么优点和缺点?如何克服这些缺点?
79 | 3. 说一件大学里你自己比较有成就感的一件事情,为此付出了那些努力。
80 | 4. 你前面跟其他面试官讲过一些你做的项目吧?可以给我讲讲吗?你要考虑到我不是一个做技术的人,怎么让我也听得懂。项目中有什么问题,你怎么解决的?你最大的收获是什么?
81 | 5. 你目前有面试过其他公司吗?如果让你选,这些公司和阿里,你选哪个?(送分题,回答不好可能送命)
82 | 6. 你期望的工作地点是哪里?
83 | 7. 你有什么问题吗?
84 |
85 | ### 总结
86 |
87 | 1. 可以看出面试官问我的很多问题都是比较常见的问题,所以记得一定要提前准备,还要深入准备,不要回答的太皮毛。很多时候一个问题可能会牵扯出很多问题,遇到不会的问题不要慌,冷静分析,如果你真的回答不上来,也不要担心自己是不是就要挂了,很可能这个问题本身就比较难。
88 | 2. 表达能力和沟通能力太重要了,一定要提前练一下,我自身就是一个不太会说话的人,所以,面试前我对于自我介绍、项目介绍和一些常见问题都在脑子里练了好久,确保面试的时候能够很清晰和简洁的说出来。
89 | 3. 等待面试的过程和面试的过程真的好熬人,那段时间我压力也比较大,好在我私下找到学长聊了很多,心情也好了很多。
90 | 4. 面试之后及时总结,面的好的话,不要得意,尽快准备下一场面试吧!
91 |
92 | 我觉得我还算是比较幸运的,最后也祝大家都能获得心仪的Offer。
93 |
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/MostCommonJavaInterviewQuestions/第一周(2018-8-7).md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## 一 为什么 Java 中只有值传递?
4 |
5 |
6 | 首先回顾一下在程序设计语言中有关将参数传递给方法(或函数)的一些专业术语。**按值调用(call by value)表示方法接收的是调用者提供的值,而按引用调用(call by reference)表示方法接收的是调用者提供的变量地址。一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。** 它用来描述各种程序设计语言(不只是Java)中方法参数传递方式。
7 |
8 | **Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个拷贝,也就是说,方法不能修改传递给它的任何参数变量的内容。**
9 |
10 | **下面通过 3 个例子来给大家说明**
11 |
12 | ### example 1
13 |
14 |
15 | ```java
16 | public static void main(String[] args) {
17 | int num1 = 10;
18 | int num2 = 20;
19 |
20 | swap(num1, num2);
21 |
22 | System.out.println("num1 = " + num1);
23 | System.out.println("num2 = " + num2);
24 | }
25 |
26 | public static void swap(int a, int b) {
27 | int temp = a;
28 | a = b;
29 | b = temp;
30 |
31 | System.out.println("a = " + a);
32 | System.out.println("b = " + b);
33 | }
34 | ```
35 |
36 | **结果:**
37 |
38 | ```
39 | a = 20
40 | b = 10
41 | num1 = 10
42 | num2 = 20
43 | ```
44 |
45 | **解析:**
46 |
47 | 
48 |
49 | 在swap方法中,a、b的值进行交换,并不会影响到 num1、num2。因为,a、b中的值,只是从 num1、num2 的复制过来的。也就是说,a、b相当于num1、num2 的副本,副本的内容无论怎么修改,都不会影响到原件本身。
50 |
51 | **通过上面例子,我们已经知道了一个方法不能修改一个基本数据类型的参数,而对象引用作为参数就不一样,请看 example2.**
52 |
53 |
54 | ### example 2
55 |
56 | ```java
57 | public static void main(String[] args) {
58 | int[] arr = { 1, 2, 3, 4, 5 };
59 | System.out.println(arr[0]);
60 | change(arr);
61 | System.out.println(arr[0]);
62 | }
63 |
64 | public static void change(int[] array) {
65 | // 将数组的第一个元素变为0
66 | array[0] = 0;
67 | }
68 | ```
69 |
70 | **结果:**
71 |
72 | ```
73 | 1
74 | 0
75 | ```
76 |
77 | **解析:**
78 |
79 | 
80 |
81 | array 被初始化 arr 的拷贝也就是一个对象的引用,也就是说 array 和 arr 指向的时同一个数组对象。 因此,外部对引用对象的改变会反映到所对应的对象上。
82 |
83 |
84 | **通过 example2 我们已经看到,实现一个改变对象参数状态的方法并不是一件难事。理由很简单,方法得到的是对象引用的拷贝,对象引用及其他的拷贝同时引用同一个对象。**
85 |
86 | **很多程序设计语言(特别是,C++和Pascal)提供了两种参数传递的方式:值调用和引用调用。有些程序员(甚至本书的作者)认为Java程序设计语言对对象采用的是引用调用,实际上,这种理解是不对的。由于这种误解具有一定的普遍性,所以下面给出一个反例来详细地阐述一下这个问题。**
87 |
88 |
89 | ### example 3
90 |
91 | ```java
92 | public class Test {
93 |
94 | public static void main(String[] args) {
95 | // TODO Auto-generated method stub
96 | Student s1 = new Student("小张");
97 | Student s2 = new Student("小李");
98 | Test.swap(s1, s2);
99 | System.out.println("s1:" + s1.getName());
100 | System.out.println("s2:" + s2.getName());
101 | }
102 |
103 | public static void swap(Student x, Student y) {
104 | Student temp = x;
105 | x = y;
106 | y = temp;
107 | System.out.println("x:" + x.getName());
108 | System.out.println("y:" + y.getName());
109 | }
110 | }
111 | ```
112 |
113 | **结果:**
114 |
115 | ```
116 | x:小李
117 | y:小张
118 | s1:小张
119 | s2:小李
120 | ```
121 |
122 | **解析:**
123 |
124 | 交换之前:
125 |
126 | 
127 |
128 | 交换之后:
129 |
130 | 
131 |
132 |
133 | 通过上面两张图可以很清晰的看出: **方法并没有改变存储在变量 s1 和 s2 中的对象引用。swap方法的参数x和y被初始化为两个对象引用的拷贝,这个方法交换的是这两个拷贝**
134 |
135 | ### 总结
136 |
137 | Java程序设计语言对对象采用的不是引用调用,实际上,对象引用是按
138 | 值传递的。
139 |
140 | 下面再总结一下Java中方法参数的使用情况:
141 |
142 | - 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
143 | - 一个方法可以改变一个对象参数的状态。
144 | - 一个方法不能让对象参数引用一个新的对象。
145 |
146 |
147 | ### 参考:
148 |
149 | 《Java核心技术卷Ⅰ》基础知识第十版第四章4.5小节
150 |
151 | ## 二 ==与equals(重要)
152 |
153 | **==** : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
154 |
155 | **equals()** : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
156 |
157 | - 情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
158 | - 情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
159 |
160 |
161 | **举个例子:**
162 |
163 | ```java
164 | public class test1 {
165 | public static void main(String[] args) {
166 | String a = new String("ab"); // a 为一个引用
167 | String b = new String("ab"); // b为另一个引用,对象的内容一样
168 | String aa = "ab"; // 放在常量池中
169 | String bb = "ab"; // 从常量池中查找
170 | if (aa == bb) // true
171 | System.out.println("aa==bb");
172 | if (a == b) // false,非同一对象
173 | System.out.println("a==b");
174 | if (a.equals(b)) // true
175 | System.out.println("aEQb");
176 | if (42 == 42.0) { // true
177 | System.out.println("true");
178 | }
179 | }
180 | }
181 | ```
182 |
183 | **说明:**
184 |
185 | - String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
186 | - 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
187 |
188 |
189 |
190 | ## 三 hashCode与equals(重要)
191 |
192 | 面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”
193 |
194 | ### hashCode()介绍
195 | hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。另外需要注意的是: Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法通常用来将对象的 内存地址 转换为整数之后返回。
196 |
197 | ```java
198 | /**
199 | * Returns a hash code value for the object. This method is
200 | * supported for the benefit of hash tables such as those provided by
201 | * {@link java.util.HashMap}.
202 | *
203 | * As much as is reasonably practical, the hashCode method defined by
204 | * class {@code Object} does return distinct integers for distinct
205 | * objects. (This is typically implemented by converting the internal
206 | * address of the object into an integer, but this implementation
207 | * technique is not required by the
208 | * Java™ programming language.)
209 | *
210 | * @return a hash code value for this object.
211 | * @see java.lang.Object#equals(java.lang.Object)
212 | * @see java.lang.System#identityHashCode
213 | */
214 | public native int hashCode();
215 | ```
216 |
217 | 散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
218 |
219 | ### 为什么要有hashCode
220 |
221 |
222 | **我们以“HashSet如何检查重复”为例子来说明为什么要有hashCode:**
223 |
224 | 当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head fist java》第二版)。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。
225 |
226 |
227 |
228 | ### hashCode()与equals()的相关规定
229 |
230 | 1. 如果两个对象相等,则hashcode一定也是相同的
231 | 2. 两个对象相等,对两个对象分别调用equals方法都返回true
232 | 3. 两个对象有相同的hashcode值,它们也不一定是相等的
233 | 4. **因此,equals方法被覆盖过,则hashCode方法也必须被覆盖**
234 | 5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
235 |
236 | ### 为什么两个对象有相同的hashcode值,它们也不一定是相等的?
237 |
238 | 在这里解释一位小伙伴的问题。以下内容摘自《Head Fisrt Java》。
239 |
240 | 因为hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode)。
241 |
242 | 我们刚刚也提到了 HashSet,如果 HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。
243 |
244 | 参考:
245 |
246 | [https://blog.csdn.net/zhzhao999/article/details/53449504](https://blog.csdn.net/zhzhao999/article/details/53449504)
247 |
248 | [https://www.cnblogs.com/skywang12345/p/3324958.html](https://www.cnblogs.com/skywang12345/p/3324958.html)
249 |
250 | [https://www.cnblogs.com/skywang12345/p/3324958.html](https://www.cnblogs.com/skywang12345/p/3324958.html)
251 |
252 | [https://www.cnblogs.com/Eason-S/p/5524837.html](https://www.cnblogs.com/Eason-S/p/5524837.html)
253 |
254 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/MostCommonJavaInterviewQuestions/第二周(2018-8-13).md:
--------------------------------------------------------------------------------
1 |
2 | ### String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?
3 |
4 | #### String和StringBuffer、StringBuilder的区别
5 |
6 | **可变性**
7 |
8 |
9 | 简单的来说:String 类中使用 final 关键字字符数组保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串`char[]value` 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
10 |
11 | StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以自行查阅源码。
12 |
13 | AbstractStringBuilder.java
14 |
15 | ```java
16 | abstract class AbstractStringBuilder implements Appendable, CharSequence {
17 | char[] value;
18 | int count;
19 | AbstractStringBuilder() {
20 | }
21 | AbstractStringBuilder(int capacity) {
22 | value = new char[capacity];
23 | }
24 | ```
25 |
26 |
27 | **线程安全性**
28 |
29 | String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
30 |
31 |
32 | **性能**
33 |
34 | 每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
35 |
36 | **对于三者使用的总结:**
37 | 1. 操作少量的数据 = String
38 | 2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
39 | 3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
40 |
41 | #### String为什么是不可变的吗?
42 | 简单来说就是String类利用了final修饰的char类型数组存储字符,源码如下图所以:
43 |
44 | ```java
45 | /** The value is used for character storage. */
46 | private final char value[];
47 | ```
48 |
49 | #### String真的是不可变的吗?
50 | 我觉得如果别人问这个问题的话,回答不可变就可以了。
51 | 下面只是给大家看两个有代表性的例子:
52 |
53 | **1) String不可变但不代表引用不可以变**
54 | ```java
55 | String str = "Hello";
56 | str = str + " World";
57 | System.out.println("str=" + str);
58 | ```
59 | 结果:
60 | ```
61 | str=Hello World
62 | ```
63 | 解析:
64 |
65 | 实际上,原来String的内容是不变的,只是str由原来指向"Hello"的内存地址转为指向"Hello World"的内存地址而已,也就是说多开辟了一块内存区域给"Hello World"字符串。
66 |
67 | **2) 通过反射是可以修改所谓的“不可变”对象**
68 |
69 | ```java
70 | // 创建字符串"Hello World", 并赋给引用s
71 | String s = "Hello World";
72 |
73 | System.out.println("s = " + s); // Hello World
74 |
75 | // 获取String类中的value字段
76 | Field valueFieldOfString = String.class.getDeclaredField("value");
77 |
78 | // 改变value属性的访问权限
79 | valueFieldOfString.setAccessible(true);
80 |
81 | // 获取s对象上的value属性的值
82 | char[] value = (char[]) valueFieldOfString.get(s);
83 |
84 | // 改变value所引用的数组中的第5个字符
85 | value[5] = '_';
86 |
87 | System.out.println("s = " + s); // Hello_World
88 | ```
89 |
90 | 结果:
91 |
92 | ```
93 | s = Hello World
94 | s = Hello_World
95 | ```
96 |
97 | 解析:
98 |
99 | 用反射可以访问私有成员, 然后反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。但是一般我们不会这么做,这里只是简单提一下有这个东西。
100 |
101 | ### 什么是反射机制?反射机制的应用场景有哪些?
102 |
103 | #### 反射机制介绍
104 |
105 | JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
106 |
107 | #### 静态编译和动态编译
108 |
109 | - **静态编译:**在编译时确定类型,绑定对象
110 | - **动态编译:**运行时确定类型,绑定对象
111 |
112 | #### 反射机制优缺点
113 |
114 | - **优点:** 运行期类型的判断,动态加载类,提高代码灵活度。
115 | - **缺点:** 性能瓶颈:反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的java代码要慢很多。
116 |
117 | #### 反射的应用场景
118 |
119 | 反射是框架设计的灵魂。
120 |
121 | 在我们平时的项目开发过程中,基本上很少会直接使用到反射机制,但这不能说明反射机制没有用,实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/Hibernate 等框架也大量使用到了反射机制。
122 |
123 | 举例:①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中;
124 | 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性
125 |
126 | **推荐阅读:**
127 |
128 | - [Reflection:Java反射机制的应用场景](https://segmentfault.com/a/1190000010162647?utm_source=tuicool&utm_medium=referral)
129 | - [Java基础之—反射(非常重要)](https://blog.csdn.net/sinat_38259539/article/details/71799078)
130 | ### 什么是JDK?什么是JRE?什么是JVM?三者之间的联系与区别
131 |
132 | 这几个是Java中很基本很基本的东西,但是我相信一定还有很多人搞不清楚!为什么呢?因为我们大多数时候在使用现成的编译工具以及环境的时候,并没有去考虑这些东西。
133 |
134 | **JDK:** 顾名思义它是给开发者提供的开发工具箱,是给程序开发者用的。它除了包括完整的JRE(Java Runtime Environment),Java运行环境,还包含了其他供开发者使用的工具包。
135 |
136 | **JRE:** 普通用户而只需要安装JRE(Java Runtime Environment)来运行Java程序。而程序开发者必须安装JDK来编译、调试程序。
137 |
138 | **JVM:** 当我们运行一个程序时,JVM负责将字节码转换为特定机器代码,JVM提供了内存管理/垃圾回收和安全机制等。这种独立于硬件和操作系统,正是java程序可以一次编写多处执行的原因。
139 |
140 | **区别与联系:**
141 |
142 | 1. JDK用于开发,JRE用于运行java程序 ;
143 | 2. JDK和JRE中都包含JVM ;
144 | 3. JVM是java编程语言的核心并且具有平台独立性。
145 |
146 | ### 什么是字节码?采用字节码的最大好处是什么?
147 |
148 | **先看下java中的编译器和解释器:**
149 |
150 | Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做`字节码`(即扩展名为`.class`的文件),它不面向任何特定的处理器,只面向虚拟机。每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。这也就是解释了Java的编译与解释并存的特点。
151 |
152 | Java源代码---->编译器---->jvm可执行的Java字节码(即虚拟指令)---->jvm---->jvm中解释器----->机器可执行的二进制机器码---->程序运行。
153 |
154 | **采用字节码的好处:**
155 |
156 | Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。
157 |
158 | ### Java和C++的区别
159 |
160 | 我知道很多人没学过C++,但是面试官就是没事喜欢拿咱们Java和C++比呀!没办法!!!就算没学过C++,也要记下来!
161 |
162 | - 都是面向对象的语言,都支持封装、继承和多态
163 | - Java不提供指针来直接访问内存,程序内存更加安全
164 | - Java的类是单继承的,C++支持多重继承;虽然Java的类不可以多继承,但是接口可以多继承。
165 | - Java有自动内存管理机制,不需要程序员手动释放无用内存
166 |
167 |
168 | ### 接口和抽象类的区别是什么?
169 |
170 | 1. 接口的方法默认是public,所有方法在接口中不能有实现,抽象类可以有非抽象的方法
171 | 2. 接口中的实例变量默认是final类型的,而抽象类中则不一定
172 | 3. 一个类可以实现多个接口,但最多只能实现一个抽象类
173 | 4. 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
174 | 5. 接口不能用new实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
175 |
176 | 注意:Java8 后接口可以有默认实现( default )。
177 |
178 | ### 成员变量与局部变量的区别有那些?
179 |
180 | 1. 从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被public,private,static等修饰符所修饰,而局部变量不能被访问控制修饰符及static所修饰;但是,成员变量和局部变量都能被final所修饰;
181 | 2. 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存
182 | 3. 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
183 | 4. 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被final修饰但没有被static修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值。
184 |
185 | ### 重载和重写的区别
186 |
187 | **重载:** 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
188 |
189 | **重写:** 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为private则子类就不能重写该方法。
190 |
191 | ### 字符型常量和字符串常量的区别
192 | 1) 形式上:
193 | 字符常量是单引号引起的一个字符
194 | 字符串常量是双引号引起的若干个字符
195 | 2) 含义上:
196 | 字符常量相当于一个整形值(ASCII值),可以参加表达式运算
197 | 字符串常量代表一个地址值(该字符串在内存中存放位置)
198 | 3) 占内存大小
199 | 字符常量只占一个字节
200 | 字符串常量占若干个字节(至少一个字符结束标志)
201 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/MostCommonJavaInterviewQuestions/第四周(2018-8-30).md:
--------------------------------------------------------------------------------
1 |
2 | ## 1. 简述线程,程序、进程的基本概念。以及他们之间关系是什么?
3 |
4 | **线程**与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
5 |
6 | **程序**是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
7 |
8 | **进程**是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。
9 |
10 | **线程** 是 **进程** 划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。
11 |
12 | **线程上下文的切换比进程上下文切换要快很多**
13 |
14 | - 进程切换时,涉及到当前进程的CPU环境的保存和新被调度运行进程的CPU环境的设置。
15 | - 线程切换仅需要保存和设置少量的寄存器内容,不涉及存储管理方面的操作。
16 |
17 | ## 2. 线程有哪些基本状态?这些状态是如何定义的?
18 |
19 | 1. **新建(new)**:新创建了一个线程对象。
20 | 2. **可运行(runnable)**:线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取cpu的使用权。
21 | 3. **运行(running)**:可运行状态(runnable)的线程获得了cpu时间片(timeslice),执行程序代码。
22 | 4. **阻塞(block)**:阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有 机会再次获得cpu timeslice转到运行(running)状态。阻塞的情况分三种:
23 | - **(一). 等待阻塞**:运行(running)的线程执行o.wait()方法,JVM会把该线程放 入等待队列(waiting queue)中。
24 | - **(二). 同步阻塞**:运行(running)的线程在获取对象的同步锁时,若该同步 锁 被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
25 | - **(三). 其他阻塞**: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
26 | 5. **死亡(dead)**:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
27 |
28 | 
29 |
30 | 备注: 可以用早起坐地铁来比喻这个过程(下面参考自牛客网某位同学的回答):
31 |
32 | 1. 还没起床:sleeping
33 | 2. 起床收拾好了,随时可以坐地铁出发:Runnable
34 | 3. 等地铁来:Waiting
35 | 4. 地铁来了,但要排队上地铁:I/O阻塞
36 | 5. 上了地铁,发现暂时没座位:synchronized阻塞
37 | 6. 地铁上找到座位:Running
38 | 7. 到达目的地:Dead
39 |
40 |
41 | ## 3. 何为多线程?
42 |
43 | 多线程就是多个线程同时运行或交替运行。单核CPU的话是顺序执行,也就是交替运行。多核CPU的话,因为每个CPU有自己的运算器,所以在多个CPU中可以同时运行。
44 |
45 |
46 | ## 4. 为什么多线程是必要的?
47 |
48 | 1. 使用线程可以把占据长时间的程序中的任务放到后台去处理。
49 | 2. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
50 | 3. 程序的运行速度可能加快。
51 |
52 | ## 5 使用多线程常见的三种方式
53 |
54 | ### ①继承Thread类
55 |
56 | MyThread.java
57 |
58 | ```java
59 | public class MyThread extends Thread {
60 | @Override
61 | public void run() {
62 | super.run();
63 | System.out.println("MyThread");
64 | }
65 | }
66 | ```
67 | Run.java
68 |
69 | ```java
70 | public class Run {
71 |
72 | public static void main(String[] args) {
73 | MyThread mythread = new MyThread();
74 | mythread.start();
75 | System.out.println("运行结束");
76 | }
77 |
78 | }
79 |
80 | ```
81 | 运行结果:
82 | 
83 | 从上面的运行结果可以看出:线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法。
84 |
85 | ### ②实现Runnable接口
86 | 推荐实现Runnable接口方式开发多线程,因为Java单继承但是可以实现多个接口。
87 |
88 | MyRunnable.java
89 |
90 | ```java
91 | public class MyRunnable implements Runnable {
92 | @Override
93 | public void run() {
94 | System.out.println("MyRunnable");
95 | }
96 | }
97 | ```
98 |
99 | Run.java
100 |
101 | ```java
102 | public class Run {
103 |
104 | public static void main(String[] args) {
105 | Runnable runnable=new MyRunnable();
106 | Thread thread=new Thread(runnable);
107 | thread.start();
108 | System.out.println("运行结束!");
109 | }
110 |
111 | }
112 | ```
113 | 运行结果:
114 | 
115 |
116 | ### ③使用线程池
117 |
118 | **在《阿里巴巴Java开发手册》“并发处理”这一章节,明确指出线程资源必须通过线程池提供,不允许在应用中自行显示创建线程。**
119 |
120 | **为什么呢?**
121 |
122 | > **使用线程池的好处是减少在创建和销毁线程上所消耗的时间以及系统资源开销,解决资源不足的问题。如果不使用线程池,有可能会造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。**
123 |
124 | **另外《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险**
125 |
126 | > Executors 返回线程池对象的弊端如下:
127 | >
128 | > - **FixedThreadPool 和 SingleThreadExecutor** : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
129 | > - **CachedThreadPool 和 ScheduledThreadPool** : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
130 |
131 | 对于线程池感兴趣的可以查看我的这篇文章:[《Java多线程学习(八)线程池与Executor 框架》](http://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484042&idx=1&sn=541dbf2cb969a151d79f4a4f837ee1bd&chksm=fd9854ebcaefddfd1876bb96ab218be3ae7b12546695a403075d4ed22e5e17ff30ebdabc8bbf#rd) 点击阅读原文即可查看到该文章的最新版。
132 |
133 |
134 | ## 6 线程的优先级
135 |
136 | 每个线程都具有各自的优先级,**线程的优先级可以在程序中表明该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态**。但这个并不意味着低
137 | 优先级的线程得不到运行,而只是它运行的几率比较小,如垃圾回收机制线程的优先级就比较低。所以很多垃圾得不到及时的回收处理。
138 |
139 | **线程优先级具有继承特性。** 比如A线程启动B线程,则B线程的优先级和A是一样的。
140 |
141 | **线程优先级具有随机性。** 也就是说线程优先级高的不一定每一次都先执行完。
142 |
143 | Thread类中包含的成员变量代表了线程的某些优先级。如**Thread.MIN_PRIORITY(常数1)**,**Thread.NORM_PRIORITY(常数5)**,
144 | **Thread.MAX_PRIORITY(常数10)**。其中每个线程的优先级都在**Thread.MIN_PRIORITY(常数1)** 到**Thread.MAX_PRIORITY(常数10)** 之间,在默认情况下优先级都是**Thread.NORM_PRIORITY(常数5)**。
145 |
146 | 学过操作系统这门课程的话,我们可以发现多线程优先级或多或少借鉴了操作系统对进程的管理。
147 |
148 |
149 | ## 7 Java多线程分类
150 |
151 | ### 用户线程
152 |
153 | 运行在前台,执行具体的任务,如程序的主线程、连接网络的子线程等都是用户线程
154 |
155 | ### 守护线程
156 |
157 | 运行在后台,为其他前台线程服务.也可以说守护线程是JVM中非守护线程的 **“佣人”**。
158 |
159 |
160 | - **特点:** 一旦所有用户线程都结束运行,守护线程会随JVM一起结束工作
161 | - **应用:** 数据库连接池中的检测线程,JVM虚拟机启动后的检测线程
162 | - **最常见的守护线程:** 垃圾回收线程
163 |
164 |
165 | **如何设置守护线程?**
166 |
167 | 可以通过调用 Thead 类的 `setDaemon(true)` 方法设置当前的线程为守护线程。
168 |
169 | 注意事项:
170 |
171 | 1. setDaemon(true)必须在start()方法前执行,否则会抛出IllegalThreadStateException异常
172 | 2. 在守护线程中产生的新线程也是守护线程
173 | 3. 不是所有的任务都可以分配给守护线程来执行,比如读写操作或者计算逻辑
174 |
175 |
176 | ## 8 sleep()方法和wait()方法简单对比
177 |
178 | - 两者最主要的区别在于:**sleep方法没有释放锁,而wait方法释放了锁** 。
179 | - 两者都可以暂停线程的执行。
180 | - Wait通常被用于线程间交互/通信,sleep通常被用于暂停执行。
181 | - wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()方法。sleep()方法执行完成后,线程会自动苏醒。
182 |
183 |
184 | ## 9 为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?
185 |
186 | 这是另一个非常经典的java多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
187 |
188 | new一个Thread,线程进入了新建状态;调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。
189 | start()会执行线程的相应准备工作,然后自动执行run()方法的内容,这是真正的多线程工作。 而直接执行run()方法,会把run方法当成一个mian线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
190 |
191 | **总结: 调用start方法方可启动线程并使线程进入就绪状态,而run方法只是thread的一个普通方法调用,还是在主线程里执行。**
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/JavaInterviewLibrary.md:
--------------------------------------------------------------------------------
1 | 最近浏览 Github ,收藏了一些还算不错的 Java面试/学习相关的仓库,分享给大家,希望对你有帮助。我暂且按照目前的 Star 数量来排序。
2 |
3 | 本文由 SnailClimb 整理,如需转载请联系作者。
4 |
5 | ### 1. interviews
6 |
7 | - Github地址: [https://github.com/kdn251/interviews/blob/master/README-zh-cn.md](https://github.com/kdn251/interviews/blob/master/README-zh-cn.md)
8 | - star: 31k
9 | - 介绍: 软件工程技术面试个人指南。
10 | - 概览:
11 |
12 | 
13 |
14 | ### 2. JCSprout
15 |
16 | - Github地址:[https://github.com/crossoverJie/JCSprout](https://github.com/crossoverJie/JCSprout)
17 | - star: 17.7k
18 | - 介绍: Java Core Sprout:处于萌芽阶段的 Java 核心知识库。
19 | - 概览:
20 |
21 | 
22 |
23 | ### 3. JavaGuide
24 |
25 | - Github地址: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
26 | - star: 17.4k
27 | - 介绍: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
28 | - 概览:
29 |
30 | 
31 |
32 | ### 4. technology-talk
33 |
34 | - Github地址: [https://github.com/aalansehaiyang/technology-talk](https://github.com/aalansehaiyang/technology-talk)
35 | - star: 4.2k
36 | - 介绍: 汇总java生态圈常用技术框架、开源中间件,系统架构、项目管理、经典架构案例、数据库、常用三方库、线上运维等知识。
37 |
38 | ### 5. fullstack-tutorial
39 |
40 | - Github地址: [https://github.com/frank-lam/fullstack-tutorial](https://github.com/frank-lam/fullstack-tutorial)
41 | - star: 2.8k
42 | - 介绍: Full Stack Developer Tutorial,后台技术栈/全栈开发/架构师之路,秋招/春招/校招/面试。 from zero to hero。
43 | - 概览:
44 |
45 | 
46 |
47 | ### 6. java-bible
48 |
49 | - Github地址:[https://github.com/biezhi/java-bible](https://github.com/biezhi/java-bible)
50 | - star: 1.9k
51 | - 介绍: 这里记录了一些技术摘要,部分文章来自网络,本项目的目的力求分享精品技术干货,以Java为主。
52 | - 概览:
53 |
54 | 
55 |
56 | ### 7. EasyJob
57 |
58 | - Github地址:[https://github.com/it-interview/EasyJob](https://github.com/it-interview/EasyJob)
59 | - star: 1.9k
60 | - 介绍: 互联网求职面试题、知识点和面经整理。
61 |
62 | ### 8. advanced-java
63 |
64 | - Github地址:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
65 | - star: 1k
66 | - 介绍: 互联网 Java 工程师进阶知识完全扫盲
67 |
68 | ### 9. 3y
69 |
70 | - Github地址:[https://github.com/ZhongFuCheng3y/3y](https://github.com/ZhongFuCheng3y/3y)
71 | - star: 0.4 k
72 | - 介绍: Java 知识整合。
73 |
74 | 除了这九个仓库,再推荐几个不错的学习方向的仓库给大家。
75 |
76 | 1. Star 数高达 4w+的 CS 笔记-CS-Notes:[https://github.com/CyC2018/CS-Notes](https://github.com/CyC2018/CS-Notes)
77 | 2. 后端(尤其是Java)程序员的 Linux 学习仓库-Linux-Tutorial:[https://github.com/judasn/Linux-Tutorial](https://github.com/judasn/Linux-Tutorial)( Star:4.6k)
78 | 3. 两个算法相关的仓库,刷 Leetcode 的小伙伴必备:①awesome-java-leetcode:[https://github.com/Blankj/awesome-java-leetcode](https://github.com/Blankj/awesome-java-leetcode);②LintCode:[https://github.com/awangdev/LintCode](https://github.com/awangdev/LintCode)
79 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/JavaProgrammerNeedKnow.md:
--------------------------------------------------------------------------------
1 | 身边的朋友或者公众号的粉丝很多人都向我询问过:“我是双非/三本/专科学校的,我有机会进入大厂吗?”、“非计算机专业的学生能学好吗?”、“如何学习Java?”、“Java学习该学那些东西?”、“我该如何准备Java面试?”......这些方面的问题。我会根据自己的一点经验对大部分人关心的这些问题进行答疑解惑。现在又刚好赶上考研结束,这篇文章也算是给考研结束准备往Java后端方向发展的朋友们指名一条学习之路。道理懂了如果没有实际行动,那这篇文章对你或许没有任何意义。
2 |
3 | ### Question1:我是双非/三本/专科学校的,我有机会进入大厂吗?
4 |
5 | 我自己也是非985非211学校的,结合自己的经历以及一些朋友的经历,我觉得让我回答这个问题再好不过。
6 |
7 | 首先,我觉得学校歧视很正常,真的太正常了,如果要抱怨的话,你只能抱怨自己没有进入名校。但是,千万不要动不动说自己学校差,动不动拿自己学校当做自己进不了大厂的借口,学历只是筛选简历的很多标准中的一个而已,如果你够优秀,简历够丰富,你也一样可以和名校同学一起同台竞争。
8 |
9 | 企业HR肯定是更喜欢高学历的人,毕竟985,211优秀人才比例肯定比普通学校高很多,HR团队肯定会优先在这些学校里选。这就好比相亲,你是愿意在很多优秀的人中选一个优秀的,还是愿意在很多普通的人中选一个优秀的呢?
10 |
11 | 双非本科甚至是二本、三本甚至是专科的同学也有很多进入大厂的,不过比率相比于名校的低很多而已。从大厂招聘的结果上看,高学历人才的数量占据大头,那些成功进入BAT、美团,京东,网易等大厂的双非本科甚至是二本、三本甚至是专科的同学往往是因为具备丰富的项目经历或者在某个含金量比较高的竞赛比如ACM中取得了不错的成绩。**一部分学历不突出但能力出众的面试者能够进入大厂并不是说明学历不重要,而是学历的软肋能够通过其他的优势来弥补。** 所以,如果你的学校不够好而你自己又想去大厂的话,建议你可以从这几点来做:**①尽量在面试前最好有一个可以拿的出手的项目;②有实习条件的话,尽早出去实习,实习经历也会是你的简历的一个亮点(有能力在大厂实习最佳!);③参加一些含金量比较高的比赛,拿不拿得到名次没关系,重在锻炼。**
12 |
13 |
14 | ### Question2:非计算机专业的学生能学好Java后台吗?我能进大厂吗?
15 |
16 | 当然可以!现在非科班的程序员很多,很大一部分原因是互联网行业的工资比较高。我们学校外面的培训班里面90%都是非科班,我觉得他们很多人学的都还不错。另外,我的一个朋友本科是机械专业,大一开始自学安卓,技术贼溜,在我看来他比大部分本科是计算机的同学学的还要好。参考Question1的回答,即使你是非科班程序员,如果你想进入大厂的话,你也可以通过自己的其他优势来弥补。
17 |
18 | 我觉得我们不应该因为自己的专业给自己划界限或者贴标签,说实话,很多科班的同学可能并不如你,你以为科班的同学就会认真听讲吗?还不是几乎全靠自己课下自学!不过如果你是非科班的话,你想要学好,那么注定就要舍弃自己本专业的一些学习时间,这是无可厚非的。
19 |
20 | 建议非科班的同学,首先要打好计算机基础知识基础:①计算机网络、②操作系统、③数据机构与算法,我个人觉得这3个对你最重要。这些东西就像是内功,对你以后的长远发展非常有用。当然,如果你想要进大厂的话,这些知识也是一定会被问到的。另外,“一定学好数据机构与算法!一定学好数据机构与算法!一定学好数据机构与算法!”,重要的东西说3遍。
21 |
22 |
23 |
24 | ### Question3: 我没有实习经历的话找工作是不是特别艰难?
25 |
26 | 没有实习经历没关系,只要你有拿得出手的项目或者大赛经历的话,你依然有可能拿到大厂的 offer 。笔主当时找工作的时候就没有实习经历以及大赛获奖经历,单纯就是凭借自己的项目经验撑起了整个面试。
27 |
28 | 如果你既没有实习经历,又没有拿得出手的项目或者大赛经历的话,我觉得在简历关,除非你有其他特别的亮点,不然,你应该就会被刷。
29 |
30 | ### Question4: 我该如何准备面试呢?面试的注意事项有哪些呢?
31 |
32 | 下面是我总结的一些准备面试的Tips以及面试必备的注意事项:
33 |
34 | 1. **准备一份自己的自我介绍,面试的时候根据面试对象适当进行修改**(突出重点,突出自己的优势在哪里,切忌流水账);
35 | 2. **注意随身带上自己的成绩单和简历复印件;** (有的公司在面试前都会让你交一份成绩单和简历当做面试中的参考。)
36 | 3. **如果需要笔试就提前刷一些笔试题,大部分在线笔试的类型是选择题+编程题,有的还会有简答题。**(平时空闲时间多的可以刷一下笔试题目(牛客网上有很多),但是不要只刷面试题,不动手code,程序员不是为了考试而存在的。)另外,注意抓重点,因为题目太多了,但是有很多题目几乎次次遇到,像这样的题目一定要搞定。
37 | 4. **提前准备技术面试。** 搞清楚自己面试中可能涉及哪些知识点、那些知识点是重点。面试中哪些问题会被经常问到、自己改如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
38 | 5. **面试之前做好定向复习。** 也就是专门针对你要面试的公司来复习。比如你在面试之前可以在网上找找有没有你要面试的公司的面经。
39 | 6. **准备好自己的项目介绍。** 如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:①对项目整体设计的一个感受(面试官可能会让你画系统的架构图;②在这个项目中你负责了什么、做了什么、担任了什么角色;③ 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用;④项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
40 | 7. **面试之后记得复盘。** 面试遭遇失败是很正常的事情,所以善于总结自己的失败原因才是最重要的。如果失败,不要灰心;如果通过,切勿狂喜。
41 |
42 |
43 | **一些还算不错的 Java面试/学习相关的仓库,相信对大家准备面试一定有帮助:**[盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484817&idx=1&sn=12f0c254a240c40c2ccab8314653216b&chksm=fd9853f0caefdae6d191e6bf085d44ab9c73f165e3323aa0362d830e420ccbfad93aa5901021&token=766994974&lang=zh_CN#rd)
44 |
45 | ### Question5: 我该自学还是报培训班呢?
46 |
47 | 我本人更加赞同自学(你要知道去了公司可没人手把手教你了,而且几乎所有的公司都对培训班出生的有偏见。为什么有偏见,你学个东西还要去培训班,说明什么,同等水平下,你的自学能力以及自律能力一定是比不上自学的人的)。但是如果,你连每天在寝室坚持学上8个小时以上都坚持不了,或者总是容易半途而废的话,我还是推荐你去培训班。观望身边同学去培训班的,大多是非计算机专业或者是没有自律能力以及自学能力非常差的人。
48 |
49 | 另外,如果自律能力不行,你也可以通过结伴学习、参加老师的项目等方式来督促自己学习。
50 |
51 | 总结:去不去培训班主要还是看自己,如果自己能坚持自学就自学,坚持不下来就去培训班。
52 |
53 | ### Question6: 没有项目经历/博客/Github开源项目怎么办?
54 |
55 | 从现在开始做!
56 |
57 | 网上有很多非常不错的项目视频,你就跟着一步一步做,不光要做,还要改进,改善。另外,如果你的老师有相关 Java 后台项目的话,你也可以主动申请参与进来。
58 |
59 | 如果有自己的博客,也算是简历上的一个亮点。建议可以在掘金、Segmentfault、CSDN等技术交流社区写博客,当然,你也可以自己搭建一个博客(采用 Hexo+Githu Pages 搭建非常简单)。写一些什么?学习笔记、实战内容、读书笔记等等都可以。
60 |
61 | 多用 Github,用好 Github,上传自己不错的项目,写好 readme 文档,在其他技术社区做好宣传。相信你也会收获一个不错的开源项目!
62 |
63 |
64 | ### Question7: 大厂到底青睐什么样的应届生?
65 |
66 | 从阿里、腾讯等大厂招聘官网对于Java后端方向/后端方向的应届实习生的要求,我们大概可以总结归纳出下面这 4 点能给简历增加很多分数:
67 |
68 | - 参加过竞赛(含金量超高的是ACM);
69 | - 对数据结构与算法非常熟练;
70 | - 参与过实际项目(比如学校网站);
71 | - 参与过某个知名的开源项目或者自己的某个开源项目很不错;
72 |
73 | 除了我上面说的这三点,在面试Java工程师的时候,下面几点也提升你的个人竞争力:
74 |
75 | - 熟悉Python、Shell、Perl等脚本语言;
76 | - 熟悉 Java 优化,JVM调优;
77 | - 熟悉 SOA 模式;
78 | - 熟悉自己所用框架的底层知识比如Spring;
79 | - 了解分布式一些常见的理论;
80 | - 具备高并发开发经验;大数据开发经验等等。
81 |
82 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/books.md:
--------------------------------------------------------------------------------
1 |
2 | ### 核心基础知识
3 |
4 | - [《图解HTTP》](https://book.douban.com/subject/25863515/)(推荐,豆瓣评分 8.1 , 1.6K+人评价): 讲漫画一样的讲HTTP,很有意思,不会觉得枯燥,大概也涵盖也HTTP常见的知识点。因为篇幅问题,内容可能不太全面。不过,如果不是专门做网络方向研究的小伙伴想研究HTTP相关知识的话,读这本书的话应该来说就差不多了。
5 | - [《大话数据结构》](https://book.douban.com/subject/6424904/)(推荐,豆瓣评分 7.9 , 1K+人评价):入门类型的书籍,读起来比较浅显易懂,适合没有数据结构基础或者说数据结构没学好的小伙伴用来入门数据结构。
6 | - [《数据结构与算法分析:C语言描述》](https://book.douban.com/subject/1139426/)(推荐,豆瓣评分 8.9,1.6K+人评价):本书是《Data Structures and Algorithm Analysis in C》一书第2版的简体中译本。原书曾被评为20世纪顶尖的30部计算机著作之一,作者Mark Allen Weiss在数据结构和算法分析方面卓有建树,他的数据结构和算法分析的著作尤其畅销,并受到广泛好评.已被世界500余所大学用作教材。
7 | - [《算法图解》](https://book.douban.com/subject/26979890/)(推荐,豆瓣评分 8.4,0.6K+人评价):入门类型的书籍,读起来比较浅显易懂,适合没有算法基础或者说算法没学好的小伙伴用来入门。示例丰富,图文并茂,以让人容易理解的方式阐释了算法.读起来比较快,内容不枯燥!
8 | - [《算法 第四版》](https://book.douban.com/subject/10432347/)(推荐,豆瓣评分 9.3,0.4K+人评价):Java语言描述,算法领域经典的参考书,全面介绍了关于算法和数据结构的必备知识,并特别针对排序、搜索、图处理和字符串处理进行了论述。书的内容非常多,可以说是Java程序员的必备书籍之一了。
9 |
10 |
11 |
12 |
13 | ### Java相关
14 |
15 | - [《Effective java 》](https://book.douban.com/subject/3360807/)(推荐,豆瓣评分 9.0,1.4K+人评价):本书介绍了在Java编程中78条极具实用价值的经验规则,这些经验规则涵盖了大多数开发人员每天所面临的问题的解决方案。通过对Java平台设计专家所使用的技术的全面描述,揭示了应该做什么,不应该做什么才能产生清晰、健壮和高效的代码。本书中的每条规则都以简短、独立的小文章形式出现,并通过例子代码加以进一步说明。本书内容全面,结构清晰,讲解详细。可作为技术人员的参考用书。
16 | - [《Head First Java.第二版》](https://book.douban.com/subject/2000732/)(推荐,豆瓣评分 8.7,1.0K+人评价): 可以说是我的Java启蒙书籍了,特别适合新手读当然也适合我们用来温故Java知识点。
17 | - [《Java多线程编程核心技术》](https://book.douban.com/subject/26555197/): Java多线程入门级书籍还不错,但是说实话,质量不是很高,很快就可以阅读完。
18 | - [《JAVA网络编程 第4版》](https://book.douban.com/subject/26259017/): 可以系统的学习一下网络的一些概念以及网络编程在Java中的使用。
19 | - [《Java核心技术卷1+卷2》](https://book.douban.com/subject/25762168/)(推荐): 很棒的两本书,建议有点Java基础之后再读,介绍的还是比较深入的,非常推荐。这两本书我一般也会用来巩固知识点,是两本适合放在自己身边的好书。
20 | - [《Java编程思想(第4版)》](https://book.douban.com/subject/2130190/)(推荐,豆瓣评分 9.1,3.2K+人评价):这本书要常读,初学者可以快速概览,中等程序员可以深入看看java,老鸟还可以用之回顾java的体系。这本书之所以厉害,因为它在无形中整合了设计模式,这本书之所以难读,也恰恰在于他对设计模式的整合是无形的。
21 | - [《Java并发编程的艺术》](https://book.douban.com/subject/26591326/)(推荐,豆瓣评分 7.2,0.2K+人评价): 这本书不是很适合作为Java并发入门书籍,需要具备一定的JVM基础。我感觉有些东西讲的还是挺深入的,推荐阅读。
22 | - [《实战Java高并发程序设计》](https://book.douban.com/subject/26663605/)(推荐):豆瓣评分 8.3 ,书的质量没的说,推荐大家好好看一下。
23 | - [《Java程序员修炼之道》](https://book.douban.com/subject/24841235/): 很杂,我只看了前面几章,不太推荐阅读。
24 | - [《深入理解Java虚拟机(第2版)周志明》](https://book.douban.com/subject/24722612/)(推荐,豆瓣评分 8.9,1.0K+人评价):建议多刷几遍,书中的所有知识点可以通过JAVA运行时区域和JAVA的内存模型与线程两个大模块罗列完全。
25 | - [《Netty实战》](https://book.douban.com/subject/27038538/)(推荐,豆瓣评分 7.8,92人评价):内容很细,如果想学Netty的话,推荐阅读这本书!
26 | - [《从Paxos到Zookeeper》](https://book.douban.com/subject/26292004/)(推荐,豆瓣评分 7.8,0.3K人评价):简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了Paxos和ZAB协议。同时,本书深入介绍了分布式一致性问题的工业解决方案——ZooKeeper,并着重向读者展示这一分布式协调框架的使用方法、内部实现及运维技巧,旨在帮助读者全面了解ZooKeeper,并更好地使用和运维ZooKeeper。
27 |
28 | ### JavaWeb相关
29 |
30 | - [《深入分析Java Web技术内幕》](https://book.douban.com/subject/25953851/): 感觉还行,涉及的东西也蛮多。
31 | - [《Spring实战(第4版)》](https://book.douban.com/subject/26767354/)(推荐,豆瓣评分 8.3
32 | ,0.3K+人评价):不建议当做入门书籍读,入门的话可以找点国人的书或者视频看。这本定位就相当于是关于Spring的新华字典,只有一些基本概念的介绍和示例,涵盖了Spring的各个方面,但都不够深入。就像作者在最后一页写的那样:“学习Spring,这才刚刚开始”。
33 | - [《Java Web整合开发王者归来》](https://book.douban.com/subject/4189495/)(已过时):当时刚开始学的时候就是开的这本书,基本上是完完整整的看完了。不过,我不是很推荐大家看。这本书比较老了,里面很多东西都已经算是过时了。不过,这本书的一个很大优点是:基础知识点概括全面。
34 | - [《Redis实战》](https://book.douban.com/subject/26612779/):如果你想了解Redis的一些概念性知识的话,这本书真的非常不错。
35 | - [《Redis设计与实现》](https://book.douban.com/subject/25900156/)(推荐,豆瓣评分 8.5,0.5K+人评价)
36 | - [《深入剖析Tomcat》](https://book.douban.com/subject/10426640/)(推荐,豆瓣评分 8.4,0.2K+人评价):本书深入剖析Tomcat 4和Tomcat 5中的每个组件,并揭示其内部工作原理。通过学习本书,你将可以自行开发Tomcat组件,或者扩展已有的组件。 读完这本书,基本可以摆脱背诵面试题的尴尬。
37 | - [《高性能MySQL》](https://book.douban.com/subject/23008813/)(推荐,豆瓣评分 9.3,0.4K+人评价):mysql 领域的经典之作,拥有广泛的影响力。不但适合数据库管理员(dba)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,相信都能从本书有所收获。
38 | - [深入理解Nginx(第2版)](https://book.douban.com/subject/26745255/):作者讲的非常细致,注释都写的都很工整,对于 Nginx 的开发人员非常有帮助。优点是细致,缺点是过于细致,到处都是代码片段,缺少一些抽象。
39 | - [《RabbitMQ实战指南》](https://book.douban.com/subject/27591386/):《RabbitMQ实战指南》从消息中间件的概念和RabbitMQ的历史切入,主要阐述RabbitMQ的安装、使用、配置、管理、运维、原理、扩展等方面的细节。如果你想浅尝RabbitMQ的使用,这本书是你最好的选择;如果你想深入RabbitMQ的原理,这本书也是你最好的选择;总之,如果你想玩转RabbitMQ,这本书一定是最值得看的书之一
40 | - [《Spring Cloud微服务实战》](https://book.douban.com/subject/27025912/):从时下流行的微服务架构概念出发,详细介绍了Spring Cloud针对微服务架构中几大核心要素的解决方案和基础组件。对于各个组件的介绍,《Spring Cloud微服务实战》主要以示例与源码结合的方式来帮助读者更好地理解这些组件的使用方法以及运行原理。同时,在介绍的过程中,还包含了作者在实践中所遇到的一些问题和解决思路,可供读者在实践中作为参考。
41 | - [《第一本Docker书》](https://book.douban.com/subject/26780404/):Docker入门书籍!
42 |
43 | ### 操作系统
44 |
45 | - [《鸟哥的Linux私房菜》](https://book.douban.com/subject/4889838/)(推荐,,豆瓣评分 9.1,0.3K+人评价):本书是最具知名度的Linux入门书《鸟哥的Linux私房菜基础学习篇》的最新版,全面而详细地介绍了Linux操作系统。全书分为5个部分:第一部分着重说明Linux的起源及功能,如何规划和安装Linux主机;第二部分介绍Linux的文件系统、文件、目录与磁盘的管理;第三部分介绍文字模式接口 shell和管理系统的好帮手shell脚本,另外还介绍了文字编辑器vi和vim的使用方法;第四部分介绍了对于系统安全非常重要的Linux账号的管理,以及主机系统与程序的管理,如查看进程、任务分配和作业管理;第五部分介绍了系统管理员(root)的管理事项,如了解系统运行状况、系统服务,针对登录文件进行解析,对系统进行备份以及核心的管理等。
46 |
47 | ### 架构相关
48 |
49 | - [《大型网站技术架构:核心原理与案例分析+李智慧》](https://book.douban.com/subject/25723064/)(推荐):这本书我读过,基本不需要你有什么基础啊~读起来特别轻松,但是却可以学到很多东西,非常推荐了。另外我写过这本书的思维导图,关注我的微信公众号:“Java面试通关手册”回复“大型网站技术架构”即可领取思维导图。
50 | - [《亿级流量网站架构核心技术》](https://book.douban.com/subject/26999243/)(推荐):一书总结并梳理了亿级流量网站高可用和高并发原则,通过实例详细介绍了如何落地这些原则。本书分为四部分:概述、高可用原则、高并发原则、案例实战。从负载均衡、限流、降级、隔离、超时与重试、回滚机制、压测与预案、缓存、池化、异步化、扩容、队列等多方面详细介绍了亿级流量网站的架构核心技术,让读者看后能快速运用到实践项目中。
51 | - [《架构解密从分布式到微服务(Leaderus著)》](https://book.douban.com/subject/27081188/):很一般的书籍,我就是当做课后图书来阅读的。
52 |
53 | ### 代码优化
54 |
55 | - [《重构_改善既有代码的设计》](https://book.douban.com/subject/4262627/)(推荐):豆瓣 9.1 分,重构书籍的开山鼻祖。
56 |
57 | ### 课外书籍
58 |
59 | - 《追风筝的人》(推荐)
60 | - 《穆斯林的葬礼》 (推荐)
61 | - 《三体》 (推荐)
62 | - 《活着——余华》 (推荐)
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/interviewPrepare.md:
--------------------------------------------------------------------------------
1 | 这是【备战春招/秋招系列】的第二篇文章,主要是简单地介绍如何去准备面试。
2 |
3 | 不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个“有章可循”说的意思只是说应对技术面试是可以提前准备。 我其实特别不喜欢那种临近考试就提前背啊记啊各种题的行为,非常反对!我觉得这种方法特别极端,而且在稍有一点经验的面试官面前是根本没有用的。建议大家还是一步一个脚印踏踏实实地走。
4 |
5 | ### 1 如何获取大厂面试机会?
6 |
7 | **在讲如何获取大厂面试机会之前,先来给大家科普/对比一下两个校招非常常见的概念——春招和秋招。**
8 |
9 | 1. **招聘人数** :秋招多于春招 ;
10 | 2. **招聘时间** : 秋招一般7月左右开始,大概一直持续到10月底。但是大厂(如BAT)都会早开始早结束,所以一定要把握好时间。春招最佳时间为3月,次佳时间为4月,进入5月基本就不会再有春招了(金三银四)。
11 | 3. **应聘难度** :秋招略大于春招;
12 | 4. **招聘公司:** 秋招数量多,而春招数量较少,一般为秋招的补充。
13 |
14 | **综上,一般来说,秋招的含金量明显是高于春招的。**
15 |
16 | **下面我就说一下我自己知道的一些方法,不过应该也涵盖了大部分获取面试机会的方法。**
17 |
18 | 1. **关注大厂官网,随时投递简历(走流程的网申);**
19 | 2. **线下参加宣讲会,直接投递简历;**
20 | 3. **找到师兄师姐/认识的人,帮忙内推(能够让你避开网申简历筛选,笔试筛选,还是挺不错的,不过也还是需要你的简历够棒);**
21 | 4. **博客发文被看中/Github优秀开源项目作者,大厂内部人员邀请你面试;**
22 | 5. **求职类网站投递简历(不是太推荐,适合海投);**
23 |
24 |
25 | 除了这些方法,我也遇到过这样的经历:有些大公司的一些部门可能暂时没招够人,然后如果你的亲戚或者朋友刚好在这个公司,而你正好又在寻求offer,那么面试机会基本上是有了,而且这种面试的难度好像一般还普遍比其他正规面试低很多。
26 |
27 | ### 2 面试前的准备
28 |
29 | ### 2.1 准备自己的自我介绍
30 |
31 | 从HR面、技术面到高管面/部门主管面,面试官一般会让你先自我介绍一下,所以好好准备自己的自我介绍真的非常重要。网上一般建议的是准备好两份自我介绍:一份对hr说的,主要讲能突出自己的经历,会的编程技术一语带过;另一份对技术面试官说的,主要讲自己会的技术细节,项目经验,经历那些就一语带过。
32 |
33 | 我这里简单分享一下我自己的自我介绍的一个简单的模板吧:
34 |
35 | > 面试官,您好!我叫某某。大学时间我主要利用课外时间学习某某。在校期间参与过一个某某系统的开发,另外,自己学习过程中也写过很多系统比如某某系统。在学习之余,我比较喜欢通过博客整理分享自己所学知识。我现在是某某社区的认证作者,写过某某很不错的文章。另外,我获得过某某奖,我的Github上开源的某个项目已经有多少Star了。
36 |
37 | ### 2.2 关于着装
38 |
39 | 穿西装、打领带、小皮鞋?NO!NO!NO!这是互联网公司面试又不是去走红毯,所以你只需要穿的简单大方就好,不需要太正式。
40 |
41 | ### 2.3 随身带上自己的成绩单和简历
42 |
43 | 有的公司在面试前都会让你交一份成绩单和简历当做面试中的参考。
44 |
45 | ### 2.4 如果需要笔试就提前刷一些笔试题
46 |
47 | 平时空闲时间多的可以刷一下笔试题目(牛客网上有很多)。但是不要只刷面试题,不动手code,程序员不是为了考试而存在的。
48 |
49 | ### 2.5 花时间一些逻辑题
50 |
51 | 面试中发现有些公司都有逻辑题测试环节,并且都把逻辑笔试成绩作为很重要的一个参考。
52 |
53 | ### 2.6 准备好自己的项目介绍
54 |
55 | 如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:
56 |
57 | 1. 对项目整体设计的一个感受(面试官可能会让你画系统的架构图)
58 | 2. 在这个项目中你负责了什么、做了什么、担任了什么角色
59 | 3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
60 | 4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
61 |
62 | ### 2.7 提前准备技术面试
63 |
64 | 搞清楚自己面试中可能涉及哪些知识点、那些知识点是重点。面试中哪些问题会被经常问到、自己改如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
65 |
66 | ### 2.7 面试之前做好定向复习
67 |
68 | 所谓定向复习就是专门针对你要面试的公司来复习。比如你在面试之前可以在网上找找有没有你要面试的公司的面经。
69 |
70 | 举个栗子:在我面试 ThoughtWorks 的前几天我就在网上找了一些关于 ThoughtWorks 的技术面的一些文章。然后知道了 ThoughtWorks 的技术面会让我们在之前做的作业的基础上增加一个或两个功能,所以我提前一天就把我之前做的程序重新重构了一下。然后在技术面的时候,简单的改了几行代码之后写个测试就完事了。如果没有提前准备,我觉得 20 分钟我很大几率会完不成这项任务。
71 |
72 | # 3 面试之后复盘
73 |
74 | 如果失败,不要灰心;如果通过,切勿狂喜。面试和工作实际上是两回事,可能很多面试未通过的人,工作能力比你强的多,反之亦然。我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md:
--------------------------------------------------------------------------------
1 | 我还记得当时我去参加面试的时候,几乎每一场面试,特别是HR面和高管面的时候,面试官总是会在结尾问我:“问了你这么多问题了,你有什么问题问我吗?”。这个时候很多人内心就会陷入短暂的纠结中:我该问吗?不问的话面试官会不会对我影响不好?问什么问题?问这个问题会不会让面试官对我的影响不好啊?
2 |
3 | 
4 |
5 | ### 这个问题对最终面试结果的影响到底大不大?
6 |
7 | 就技术面试而言,回答这个问题的时候,只要你不是触碰到你所面试的公司的雷区,那么我觉得这对你能不能拿到最终offer来说影响确实是不大的。我说这些并不代表你就可以直接对面试官说:“我没问题了。”,笔主当时面试的时候确实也说过挺多次“没问题要问了。”,最终也没有导致笔主被pass掉(可能是前面表现比较好,哈哈,自恋一下)。我现在回想起来,觉得自己当时做法其实挺不对的。面试本身就是一个双向选择的过程,你对这个问题的回答也会侧面反映出你对这次面试的上心程度,你的问题是否有价值,也影响了你最终的选择与公司是否选择你。
8 |
9 | 面试官在技术面试中主要考察的还是你这样个人到底有没有胜任这个工作的能力以及你是否适合公司未来的发展需要,很多公司还需要你认同它的文化,我觉得你只要不是太笨,应该不会栽在这里。除非你和另外一个人在能力上相同,但是只能在你们两个人中选一个,那么这个问题才对你能不能拿到offer至关重要。有准备总比没准备好,给面试官留一个好的影响总归是没错的。
10 |
11 | 但是,就非技术面试来说,我觉得好好回答这个问题对你最终的结果还是比较重要的。
12 |
13 | 总的来说不管是技术面试还是非技术面试,如果你想赢得公司的青睐和尊重,我觉得我们都应该重视这个问题。
14 |
15 | ### 真诚一点,不要问太 Low 的问题
16 |
17 | 回答这个问题很重要的一点就是你没有必要放低自己的姿态问一些很虚或者故意讨好面试官的问题,也不要把自己从面经上学到的东西照搬下来使用。面试官也不是傻子,特别是那种特别有经验的面试官,你是真心诚意的问问题,还是从别处照搬问题来讨好面试官,人家可能一听就听出来了。总的来说,还是要真诚。除此之外,不要问太Low的问题,会显得你整个人格局比较小或者说你根本没有准备(侧面反映你对这家公司不伤心,既然你不上心,为什么要要你呢)。举例几个比较 Low 的问题,大家看看自己有没有问过其中的问题:
18 |
19 | - 贵公司的主要业务是什么?(面试之前自己不知道提前网上查一下吗?)
20 | - 贵公司的男女比例如何?(考虑脱单?记住你是来工作的!)
21 | - 贵公司一年搞几次外出旅游?(你是来工作的,这些娱乐活动先别放在心上!)
22 | - ......
23 |
24 | ### 有哪些有价值的问题值得问?
25 |
26 | 针对这个问题。笔主专门找了几个专门做HR工作的小哥哥小姐姐们询问并且查阅了挺多前辈们的回答,然后结合自己的实际经历,我概括了下面几个比较适合问的问题。
27 |
28 | #### 面对HR或者其他Level比较低的面试官时
29 |
30 | 1. **能不能谈谈你作为一个公司老员工对公司的感受?** (这个问题比较容易回答,不会让面试官陷入无话可说的尴尬境地。另外,从面试官的回答中你可以加深对这个公司的了解,让你更加清楚这个公司到底是不是你想的那样或者说你是否能适应这个公司的文化。除此之外,这样的问题在某种程度上还可以拉进你与面试官的距离。)
31 | 2. **能不能问一下,你当时因为什么原因选择加入这家公司的呢或者说这家公司有哪些地方吸引你?有什么地方你觉得还不太好或者可以继续完善吗?** (类似第一个问题,都是问面试官个人对于公司的看法,)
32 | 3. **我觉得我这次表现的不是太好,你有什么建议或者评价给我吗?**(这个是我常问的。我觉得说自己表现不好只是这个语境需要这样来说,这样可以显的你比较谦虚好学上进。)
33 | 4. **接下来我会有一段空档期,有什么值得注意或者建议学习的吗?** (体现出你对工作比较上心,自助学习意识比较强。)
34 | 5. **这个岗位为什么还在招人?** (岗位真实性和价值咨询)
35 | 6. **大概什么时候能给我回复呢?** (终面的时候,如果面试官没有说的话,可以问一下)
36 | 7. ......
37 |
38 |
39 |
40 | #### 面对部门领导
41 |
42 | 1. **部门的主要人员分配以及对应的主要工作能简单介绍一下吗?**
43 | 2. **未来如果我要加入这个团队,你对我的期望是什么?** (部门领导一般情况下是你的直属上级了,你以后和他打交道的机会应该是最多的。你问这个问题,会让他感觉你是一个对他的部门比较上心,比较有团体意识,并且愿意倾听的候选人。)
44 | 3. **公司对新入职的员工的培养机制是什么样的呢?** (正规的公司一般都有培养机制,提前问一下是对你自己的负责也会显的你比较上心)
45 | 4. **以您来看,这个岗位未来在公司内部的发展如何?** (在我看来,问这个问题也是对你自己的负责吧,谁不想发展前景更好的岗位呢?)
46 | 5. **团队现在面临的最大挑战是什么?** (这样的问题不会暴露你对公司的不了解,并且也能让你对未来工作的挑战或困难有一个提前的预期。)
47 |
48 |
49 |
50 | #### 面对Level比较高的(比如总裁,老板)
51 |
52 | 1. **贵公司的发展目标和方向是什么?** (看下公司的发展是否满足自己的期望)
53 | 2. **与同行业的竞争者相比,贵公司的核心竞争优势在什么地方?** (充分了解自己的优势和劣势)
54 | 3. **公司现在面临的最大挑战是什么?**
55 |
56 | ### 来个补充,顺便送个祝福给大家
57 |
58 | 薪酬待遇和相关福利问题一般在终面的时候(最好不要在前面几面的时候就问到这个问题),面试官会提出来或者在面试完之后以邮件的形式告知你。一般来说,如果面试官很愿意为你回答问题,对你的问题也比较上心的话,那他肯定是觉得你就是他们要招的人。
59 |
60 | 大家在面试的时候,可以根据自己对于公司或者岗位的了解程度,对上面提到的问题进行适当修饰或者修改。上面提到的一些问题只是给没有经验的朋友一个参考,如果你还有其他比较好的问题的话,那当然也更好啦!
61 |
62 | 金三银四。过了二月就到了面试高峰期或者说是黄金期。几份惊喜几份愁,愿各位能始终不忘初心!每个人都有每个人的难处。引用一句《阿甘正传》里面的台词:“生活就像一盒巧克力,你永远不知道下一块是什么味道“。
63 |
64 | 
--------------------------------------------------------------------------------
/EssentialContentForInterview/PreparingForInterview/程序员的简历之道.md:
--------------------------------------------------------------------------------
1 | # 程序员的简历就该这样写
2 |
3 | ### 1 前言
4 | 一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情况下,写出一份好的简历也是一项很棒的能力。
5 |
6 | ### 2 为什么说简历很重要?
7 |
8 | #### 2.1 先从面试前来说
9 |
10 | 假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR就会决定你这一关是Fail还是Pass。
11 |
12 | 假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。
13 |
14 | 另外,就算你通过了筛选,后面的面试中,面试官也会根据你的简历来判断你究竟是否值得他花费很多时间去面试。
15 |
16 | 所以,简历就像是我们的一个门面一样,它在很大程度上决定了你能否进入到下一轮的面试中。
17 |
18 | #### 2.2 再从面试中来说
19 |
20 | 我发现大家比较喜欢看面经 ,这点无可厚非,但是大部分面经都没告诉你很多问题都是在特定条件下才问的。举个简单的例子:一般情况下你的简历上注明你会的东西才会被问到(Java、数据结构、网络、算法这些基础是每个人必问的),比如写了你会 redis,那面试官就很大概率会问你 redis 的一些问题。比如:redis的常见数据类型及应用场景、redis是单线程为什么还这么快、 redis 和 memcached 的区别、redis 内存淘汰机制等等。
21 |
22 | 所以,首先,你要明确的一点是:**你不会的东西就不要写在简历上**。另外,**你要考虑你该如何才能让你的亮点在简历中凸显出来**,比如:你在某某项目做了什么事情解决了什么问题(只要有项目就一定有要解决的问题)、你的某一个项目里使用了什么技术后整体性能和并发量提升了很多等等。
23 |
24 | 面试和工作是两回事,聪明的人会把面试官往自己擅长的领域领,其他人则被面试官牵着鼻子走。虽说面试和工作是两回事,但是你要想要获得自己满意的 offer ,你自身的实力必须要强。
25 |
26 | ### 3 下面这几点你必须知道
27 |
28 | 1. 大部分公司的HR都说我们不看重学历(骗你的!),但是如果你的学校不出众的话,很难在一堆简历中脱颖而出,除非你的简历上有特别的亮点,比如:某某大厂的实习经历、获得了某某大赛的奖等等。
29 | 2. **大部分应届生找工作的硬伤是没有工作经验或实习经历,所以如果你是应届生就不要错过秋招和春招。一旦错过,你后面就极大可能会面临社招,这个时候没有工作经验的你可能就会面临各种碰壁,导致找不到一个好的工作**
30 | 3. **写在简历上的东西一定要慎重,这是面试官大量提问的地方;**
31 | 4. **将自己的项目经历完美的展示出来非常重要。**
32 |
33 | ### 4 必须了解的两大法则
34 |
35 |
36 | **①STAR法则(Situation Task Action Result):**
37 |
38 | - **Situation:** 事情是在什么情况下发生;
39 | - **Task::** 你是如何明确你的任务的;
40 | - **Action:** 针对这样的情况分析,你采用了什么行动方式;
41 | - **Result:** 结果怎样,在这样的情况下你学习到了什么。
42 |
43 | 简而言之,STAR法则,就是一种讲述自己故事的方式,或者说,是一个清晰、条理的作文模板。不管是什么,合理熟练运用此法则,可以轻松的对面试官描述事物的逻辑方式,表现出自己分析阐述问题的清晰性、条理性和逻辑性。
44 |
45 | 下面这段内容摘自百度百科,我觉得写的非常不错:
46 |
47 | > STAR法则,500强面试题回答时的技巧法则,备受面试者成功者和500强HR的推崇。
48 | 由于这个法则被广泛应用于面试问题的回答,尽管我们还在写简历阶段,但是,写简历时能把面试的问题就想好,会使自己更加主动和自信,做到简历,面试关联性,逻辑性强,不至于在一个月后去面试,却把简历里的东西都忘掉了(更何况有些朋友会稍微夸大简历内容)
49 | 在我们写简历时,每个人都要写上自己的工作经历,活动经历,想必每一个同学,都会起码花上半天甚至更长的时间去搜寻脑海里所有有关的经历,争取找出最好的东西写在简历上。
50 | 但是此时,我们要注意了,简历上的任何一个信息点都有可能成为日后面试时的重点提问对象,所以说,不能只管写上让自己感觉最牛的经历就完事了,要想到今后,在面试中,你所写的经历万一被面试官问到,你真的能回答得流利,顺畅,且能通过这段经历,证明自己正是适合这个职位的人吗?
51 |
52 | **②FAB 法则(Feature Advantage Benefit):**
53 |
54 | - **Feature:** 是什么;
55 | - **Advantage:** 比别人好在哪些地方;
56 | - **Benefit:** 如果雇佣你,招聘方会得到什么好处。
57 |
58 | 简单来说,这个法则主要是让你的面试官知道你的优势、招了你之后对公司有什么帮助。
59 |
60 | ### 5 项目经历怎么写?
61 |
62 | 简历上有一两个项目经历很正常,但是真正能把项目经历很好的展示给面试官的非常少。对于项目经历大家可以考虑从如下几点来写:
63 |
64 | 1. 对项目整体设计的一个感受
65 | 2. 在这个项目中你负责了什么、做了什么、担任了什么角色
66 | 3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
67 | 4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
68 |
69 | ### 6 专业技能该怎么写?
70 | 先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几天时间学习一下,然后在简历上可以写上自己了解这个技能。比如你可以这样写(下面这部分内容摘自我的简历,大家可以根据自己的情况做一些修改和完善):
71 |
72 | - 计算机网络、数据结构、算法、操作系统等课内基础知识:掌握
73 | - Java 基础知识:掌握
74 | - JVM 虚拟机(Java内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM内存管理):掌握
75 | - 高并发、高可用、高性能系统开发:掌握
76 | - Struts2、Spring、Hibernate、Ajax、Mybatis、JQuery :掌握
77 | - SSH 整合、SSM 整合、 SOA 架构:掌握
78 | - Dubbo: 掌握
79 | - Zookeeper: 掌握
80 | - 常见消息队列: 掌握
81 | - Linux:掌握
82 | - MySQL常见优化手段:掌握
83 | - Spring Boot +Spring Cloud +Docker:了解
84 | - Hadoop 生态相关技术中的 HDFS、Storm、MapReduce、Hive、Hbase :了解
85 | - Python 基础、一些常见第三方库比如OpenCV、wxpy、wordcloud、matplotlib:熟悉
86 |
87 | ### 7 开源程序员Markdown格式简历模板分享
88 |
89 | 分享一个Github上开源的程序员简历模板。包括PHP程序员简历模板、iOS程序员简历模板、Android程序员简历模板、Web前端程序员简历模板、Java程序员简历模板、C/C++程序员简历模板、NodeJS程序员简历模板、架构师简历模板以及通用程序员简历模板 。
90 | Github地址:[https://github.com/geekcompany/ResumeSample](https://github.com/geekcompany/ResumeSample)
91 |
92 |
93 | 我的下面这篇文章讲了如何写一份Markdown格式的简历,另外,文中还提到了一种实现 Markdown 格式到PDF、HTML、JPEG这几种格式的转换方法。
94 |
95 | [手把手教你用Markdown写一份高质量的简历](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484347&idx=1&sn=a986ea7e199871999a5257bd3ed78be1&chksm=fd9855dacaefdccc2c5d5f8f79c4aa1b608ad5b42936bccaefb99a850a2e6e8e2e910e1b3153&token=719595858&lang=zh_CN#rd)
96 |
97 | ### 8 其他的一些小tips
98 |
99 | 1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。
100 | 2. 注意排版(不需要花花绿绿的),尽量使用Markdown语法。
101 | 3. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。
102 | 4. 如果自己的Github比较活跃的话,写上去也会为你加分很多。
103 | 5. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容
104 | 6. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。
105 | 7. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。
106 | 8. 简历最后最好能加上:“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的你会很有礼貌。
107 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/手把手教你用Markdown写一份高质量的简历.md:
--------------------------------------------------------------------------------
1 | ## Markdown 简历模板样式一览
2 | 
3 | **可以看到我把联系方式放在第一位,因为公司一般会与你联系,所以把联系方式放在第一位也是为了方便联系考虑。**
4 |
5 | ## 为什么要用 Markdown 写简历?
6 |
7 | Markdown 语法简单,易于上手。使用正确的 Markdown 语言写出来的简历不论是在排版还是格式上都比较干净,易于阅读。另外,使用 Markdown 写简历也会给面试官一种你比较专业的感觉。
8 |
9 | 除了这些,我觉得使用 Markdown 写简历可以很方便将其与PDF、HTML、PNG格式之间转换。后面我会介绍到转换方法,只需要一条命令你就可以实现 Markdown 到 PDF、HTML 与 PNG之间的无缝切换。
10 |
11 | > 下面的一些内容我在之前的一篇文章中已经提到过,这里再说一遍,最后会分享如何实现Markdown 到 PDF、HTML、PNG格式之间转换。
12 |
13 | ## 为什么说简历很重要?
14 |
15 | 假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR就会决定你这一关是Fail还是Pass。
16 |
17 | 假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。
18 |
19 | 另外,就算你通过了筛选,后面的面试中,面试官也会根据你的简历来判断你究竟是否值得他花费很多时间去面试。
20 |
21 | ## 写简历的两大法则
22 |
23 | 目前写简历的方式有两种普遍被认可,一种是 STAR, 一种是 FAB。
24 |
25 | **STAR法则(Situation Task Action Result):**
26 |
27 | - **Situation:** 事情是在什么情况下发生;
28 | - **Task::** 你是如何明确你的任务的;
29 | - **Action:** 针对这样的情况分析,你采用了什么行动方式;
30 | - **Result:** 结果怎样,在这样的情况下你学习到了什么。
31 |
32 | **FAB 法则(Feature Advantage Benefit):**
33 |
34 | - **Feature:** 是什么;
35 | - **Advantage:** 比别人好在哪些地方;
36 | - **Benefit:** 如果雇佣你,招聘方会得到什么好处。
37 |
38 | ## 项目经历怎么写?
39 | 简历上有一两个项目经历很正常,但是真正能把项目经历很好的展示给面试官的非常少。对于项目经历大家可以考虑从如下几点来写:
40 |
41 | 1. 对项目整体设计的一个感受
42 | 2. 在这个项目中你负责了什么、做了什么、担任了什么角色
43 | 3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
44 | 4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的。
45 |
46 | ## 专业技能该怎么写?
47 | 先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几天时间学习一下,然后在简历上可以写上自己了解这个技能。比如你可以这样写:
48 |
49 | - Dubbo:精通
50 | - Spring:精通
51 | - Docker:掌握
52 | - SOA分布式开发 :掌握
53 | - Spring Cloud:了解
54 |
55 | ## 简历模板分享
56 |
57 | **开源程序员简历模板**: [https://github.com/geekcompany/ResumeSample](https://github.com/geekcompany/ResumeSample)(包括PHP程序员简历模板、iOS程序员简历模板、Android程序员简历模板、Web前端程序员简历模板、Java程序员简历模板、C/C++程序员简历模板、NodeJS程序员简历模板、架构师简历模板以及通用程序员简历模板)
58 |
59 | **上述简历模板的改进版本:** [https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/简历模板.md](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/简历模板.md)
60 |
61 | ## 其他的一些小tips
62 |
63 | 1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。
64 | 2. 注意排版(不需要花花绿绿的),尽量使用Markdown语法。
65 | 3. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。
66 | 4. 如果自己的Github比较活跃的话,写上去也会为你加分很多。
67 | 5. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容
68 | 6. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。
69 | 7. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。
70 | 8. 简历最后最好能加上:“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的你会很有礼貌。
71 |
72 |
73 | > 我们刚刚讲了很多关于如何写简历的内容并且分享了一份 Markdown 格式的简历文档。下面我们来看看如何实现 Markdown 到 HTML格式、PNG格式之间转换。
74 | ## Markdown 到 HTML格式、PNG格式之间转换
75 |
76 | 网上很难找到一个比较方便并且效果好的转换方法,最后我是通过 Visual Studio Code 的 Markdown PDF 插件完美解决了这个问题!
77 |
78 | ### 安装 Markdown PDF 插件
79 |
80 | **① 打开Visual Studio Code ,按快捷键 F1,选择安装扩展选项**
81 |
82 | 
83 |
84 | **② 搜索 “Markdown PDF” 插件并安装 ,然后重启**
85 |
86 | 
87 |
88 | ### 使用方法
89 |
90 | 随便打开一份 Markdown 文件 点击F1,然后输入export即可!
91 |
92 | 
93 |
94 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/简历模板.md:
--------------------------------------------------------------------------------
1 | # 联系方式
2 |
3 | - 手机:
4 | - Email:
5 | - 微信:
6 |
7 | # 个人信息
8 |
9 | - 姓名/性别/出生日期
10 | - 本科/xxx计算机系xxx专业/英语六级
11 | - 技术博客:[http://snailclimb.top/](http://snailclimb.top/)
12 | - 荣誉奖励:获得了什么奖(获奖时间)
13 | - Github:[https://github.com/Snailclimb ](https://github.com/Snailclimb)
14 | - Github Resume: [http://resume.github.io/?Snailclimb](http://resume.github.io/?Snailclimb)
15 | - 期望职位:Java 研发程序员/大数据工程师(Java后台开发为首选)
16 | - 期望城市:xxx城市
17 |
18 |
19 | # 项目经历
20 |
21 | ## xxx项目
22 |
23 | ### 项目描述
24 |
25 | 介绍该项目是做什么的、使用到了什么技术以及你对项目整体设计的一个感受
26 |
27 | ### 责任描述
28 |
29 | 主要可以从下面三点来写:
30 |
31 | 1. 在这个项目中你负责了什么、做了什么、担任了什么角色
32 | 2. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
33 | 3. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的。
34 |
35 | # 开源项目和技术文章
36 |
37 | ## 开源项目
38 |
39 | - [Java-Guide](https://github.com/Snailclimb/Java-Guide) :一份涵盖大部分Java程序员所需要掌握的核心知识。Star:3.9K; Fork:0.9k。
40 |
41 |
42 | ## 技术文章推荐
43 |
44 | - [可能是把Java内存区域讲的最清楚的一篇文章](https://juejin.im/post/5b7d69e4e51d4538ca5730cb)
45 | - [搞定JVM垃圾回收就是这么简单](https://juejin.im/post/5b85ea54e51d4538dd08f601)
46 | - [前端&后端程序员必备的Linux基础知识](https://juejin.im/post/5b3b19856fb9a04fa42f8c71)
47 | - [可能是把Docker的概念讲的最清楚的一篇文章](https://juejin.im/post/5b260ec26fb9a00e8e4b031a)
48 |
49 |
50 | # 校园经历(可选)
51 |
52 | ## 2016-2017
53 |
54 | 担任学校社团-致深社副会长,主要负责团队每周活动的组建以及每周例会的主持。
55 |
56 | ## 2017-2018
57 | 担任学校传媒组织:“长江大学在线信息传媒”的副站长以及安卓组成员。主要负责每周例会主持、活动策划以及学校校园通APP的研发工作。
58 |
59 |
60 | # 技能清单
61 |
62 | 以下均为我熟练使用的技能
63 |
64 | - Web开发:PHP/Hack/Node
65 | - Web框架:ThinkPHP/Yaf/Yii/Lavarel/LazyPHP
66 | - 前端框架:Bootstrap/AngularJS/EmberJS/HTML5/Cocos2dJS/ionic
67 | - 前端工具:Bower/Gulp/SaSS/LeSS/PhoneGap
68 | - 数据库相关:MySQL/PgSQL/PDO/SQLite
69 | - 版本管理、文档和自动化部署工具:Svn/Git/PHPDoc/Phing/Composer
70 | - 单元测试:PHPUnit/SimpleTest/Qunit
71 | - 云和开放平台:SAE/BAE/AWS/微博开放平台/微信应用开发
72 |
73 | # 自我评价(可选)
74 |
75 | 自我发挥。切记不要过度自夸!!!
76 |
77 |
78 | ### 感谢您花时间阅读我的简历,期待能有机会和您共事。
79 |
80 |
--------------------------------------------------------------------------------
/EssentialContentForInterview/面试必备之乐观锁与悲观锁.md:
--------------------------------------------------------------------------------
1 | ### 何谓悲观锁与乐观锁
2 |
3 | > 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。
4 |
5 | #### 悲观锁
6 |
7 | 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(**共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程**)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中`synchronized`和`ReentrantLock`等独占锁就是悲观锁思想的实现。
8 |
9 |
10 | #### 乐观锁
11 |
12 | 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。**乐观锁适用于多读的应用类型,这样可以提高吞吐量**,像数据库提供的类似于**write_condition机制**,其实都是提供的乐观锁。在Java中`java.util.concurrent.atomic`包下面的原子变量类就是使用了乐观锁的一种实现方式**CAS**实现的。
13 |
14 | #### 两种锁的使用场景
15 |
16 | 从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像**乐观锁适用于写比较少的情况下(多读场景)**,即冲突真的很少发生的时候,这样可以省去了锁的开销,加大了系统的整个吞吐量。但如果是多写的情况,一般会经常产生冲突,这就会导致上层应用会不断的进行retry,这样反倒是降低了性能,所以**一般多写的场景下用悲观锁就比较合适。**
17 |
18 |
19 | ### 乐观锁常见的两种实现方式
20 |
21 | > **乐观锁一般会使用版本号机制或CAS算法实现。**
22 |
23 | #### 1. 版本号机制
24 |
25 | 一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。
26 |
27 | **举一个简单的例子:**
28 | 假设数据库中帐户信息表中有一个 version 字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100 。
29 |
30 | 1. 操作员 A 此时将其读出( version=1 ),并从其帐户余额中扣除 $50( $100-$50 )。
31 | 2. 在操作员 A 操作的过程中,操作员B 也读入此用户信息( version=1 ),并从其帐户余额中扣除 $20 ( $100-$20 )。
32 | 3. 操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2 。
33 | 4. 操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足 “ 提交版本必须大于记录当前版本才能执行更新 “ 的乐观锁策略,因此,操作员 B 的提交被驳回。
34 |
35 | 这样,就避免了操作员 B 用基于 version=1 的旧数据修改的结果覆盖操作员A 的操作结果的可能。
36 |
37 | #### 2. CAS算法
38 |
39 | 即**compare and swap(比较与交换)**,是一种有名的**无锁算法**。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。**CAS算法**涉及到三个操作数
40 |
41 | - 需要读写的内存值 V
42 | - 进行比较的值 A
43 | - 拟写入的新值 B
44 |
45 | 当且仅当 V 的值等于 A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是一个原子操作)。一般情况下是一个**自旋操作**,即**不断的重试**。
46 |
47 | 关于自旋锁,大家可以看一下这篇文章,非常不错:[《
48 | 面试必备之深入理解自旋锁》](https://blog.csdn.net/qq_34337272/article/details/81252853)
49 |
50 | ### 乐观锁的缺点
51 |
52 | > ABA 问题是乐观锁一个常见的问题
53 |
54 | #### 1 ABA 问题
55 |
56 | 如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的 **"ABA"问题。**
57 |
58 | JDK 1.5 以后的 `AtomicStampedReference 类`就提供了此种能力,其中的 `compareAndSet 方法`就是首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
59 |
60 | #### 2 循环时间长开销大
61 | **自旋CAS(也就是不成功就一直循环执行直到成功)如果长时间不成功,会给CPU带来非常大的执行开销。** 如果JVM能支持处理器提供的pause指令那么效率会有一定的提升,pause指令有两个作用,第一它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零。第二它可以避免在退出循环的时候因内存顺序冲突(memory order violation)而引起CPU流水线被清空(CPU pipeline flush),从而提高CPU的执行效率。
62 |
63 | #### 3 只能保证一个共享变量的原子操作
64 |
65 | CAS 只对单个共享变量有效,当操作涉及跨多个共享变量时 CAS 无效。但是从 JDK 1.5开始,提供了`AtomicReference类`来保证引用对象之间的原子性,你可以把多个变量放在一个对象里来进行 CAS 操作.所以我们可以使用锁或者利用`AtomicReference类`把多个共享变量合并成一个共享变量来操作。
66 |
67 |
68 |
69 | ### CAS与synchronized的使用情景
70 |
71 | > **简单的来说CAS适用于写比较少的情况下(多读场景,冲突一般较少),synchronized适用于写比较多的情况下(多写场景,冲突一般较多)**
72 |
73 | 1. 对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。
74 | 2. 对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。
75 |
76 |
77 | 补充: Java并发编程这个领域中synchronized关键字一直都是元老级的角色,很久之前很多人都会称它为 **“重量级锁”** 。但是,在JavaSE 1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的 **偏向锁** 和 **轻量级锁** 以及其它**各种优化**之后变得在某些情况下并不是那么重了。synchronized的底层实现主要依靠 **Lock-Free** 的队列,基本思路是 **自旋后阻塞**,**竞争切换后继续竞争锁**,**稍微牺牲了公平性,但获得了高吞吐量**。在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS。
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/Java/Java IO与NIO.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | - [IO流学习总结](#io流学习总结)
4 | - [一 Java IO,硬骨头也能变软](#一-java-io,硬骨头也能变软)
5 | - [二 java IO体系的学习总结](#二-java-io体系的学习总结)
6 | - [三 Java IO面试题](#三-java-io面试题)
7 | - [NIO与AIO学习总结](#nio与aio学习总结)
8 | - [一 Java NIO 概览](#一-java-nio-概览)
9 | - [二 Java NIO 之 Buffer\(缓冲区\)](#二-java-nio-之-buffer缓冲区)
10 | - [三 Java NIO 之 Channel(通道)](#三-java-nio-之-channel(通道))
11 | - [四 Java NIO之Selector(选择器)](#四-java-nio之selector(选择器))
12 | - [五 Java NIO之拥抱Path和Files](#五-java-nio之拥抱path和files)
13 | - [六 NIO学习总结以及NIO新特性介绍](#六-nio学习总结以及nio新特性介绍)
14 | - [七 Java NIO AsynchronousFileChannel异步文件通](#七-java-nio-asynchronousfilechannel异步文件通)
15 | - [八 高并发Java(8):NIO和AIO](#八-高并发java(8):nio和aio)
16 | - [推荐阅读](#推荐阅读)
17 | - [在 Java 7 中体会 NIO.2 异步执行的快乐](#在-java-7-中体会-nio2-异步执行的快乐)
18 | - [Java AIO总结与示例](#java-aio总结与示例)
19 |
20 |
21 |
22 |
23 |
24 | ## IO流学习总结
25 |
26 | ### [一 Java IO,硬骨头也能变软](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483981&idx=1&sn=6e5c682d76972c8d2cf271a85dcf09e2&chksm=fd98542ccaefdd3a70428e9549bc33e8165836855edaa748928d16c1ebde9648579d3acaac10#rd)
27 |
28 | **(1) 按操作方式分类结构图:**
29 |
30 | 
31 |
32 |
33 | **(2)按操作对象分类结构图**
34 |
35 | 
36 |
37 | ### [二 java IO体系的学习总结](https://blog.csdn.net/nightcurtis/article/details/51324105)
38 | 1. **IO流的分类:**
39 | - 按照流的流向分,可以分为输入流和输出流;
40 | - 按照操作单元划分,可以划分为字节流和字符流;
41 | - 按照流的角色划分为节点流和处理流。
42 | 2. **流的原理浅析:**
43 |
44 | java Io流共涉及40多个类,这些类看上去很杂乱,但实际上很有规则,而且彼此之间存在非常紧密的联系, Java Io流的40多个类都是从如下4个抽象类基类中派生出来的。
45 |
46 | - **InputStream/Reader**: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
47 | - **OutputStream/Writer**: 所有输出流的基类,前者是字节输出流,后者是字符输出流。
48 | 3. **常用的io流的用法**
49 |
50 | ### [三 Java IO面试题](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483985&idx=1&sn=38531c2cee7b87f125df7aef41637014&chksm=fd985430caefdd26b0506aa84fc26251877eccba24fac73169a4d6bd1eb5e3fbdf3c3b940261#rd)
51 |
52 | ## NIO与AIO学习总结
53 |
54 |
55 | ### [一 Java NIO 概览](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483956&idx=1&sn=57692bc5b7c2c6dfb812489baadc29c9&chksm=fd985455caefdd4331d828d8e89b22f19b304aa87d6da73c5d8c66fcef16e4c0b448b1a6f791#rd)
56 |
57 | 1. **NIO简介**:
58 |
59 | Java NIO 是 java 1.4, 之后新出的一套IO接口NIO中的N可以理解为Non-blocking,不单纯是New。
60 |
61 | 2. **NIO的特性/NIO与IO区别:**
62 | - 1)IO是面向流的,NIO是面向缓冲区的;
63 | - 2)IO流是阻塞的,NIO流是不阻塞的;
64 | - 3)NIO有选择器,而IO没有。
65 | 3. **读数据和写数据方式:**
66 | - 从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
67 |
68 | - 从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。
69 |
70 | 4. **NIO核心组件简单介绍**
71 | - **Channels**
72 | - **Buffers**
73 | - **Selectors**
74 |
75 |
76 | ### [二 Java NIO 之 Buffer(缓冲区)](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483961&idx=1&sn=f67bef4c279e78043ff649b6b03fdcbc&chksm=fd985458caefdd4e3317ccbdb2d0a5a70a5024d3255eebf38183919ed9c25ade536017c0a6ba#rd)
77 |
78 | 1. **Buffer(缓冲区)介绍:**
79 | - Java NIO Buffers用于和NIO Channel交互。 我们从Channel中读取数据到buffers里,从Buffer把数据写入到Channels;
80 | - Buffer本质上就是一块内存区;
81 | - 一个Buffer有三个属性是必须掌握的,分别是:capacity容量、position位置、limit限制。
82 | 2. **Buffer的常见方法**
83 | - Buffer clear()
84 | - Buffer flip()
85 | - Buffer rewind()
86 | - Buffer position(int newPosition)
87 | 3. **Buffer的使用方式/方法介绍:**
88 | - 分配缓冲区(Allocating a Buffer):
89 | ```java
90 | ByteBuffer buf = ByteBuffer.allocate(28);//以ByteBuffer为例子
91 | ```
92 | - 写入数据到缓冲区(Writing Data to a Buffer)
93 |
94 | **写数据到Buffer有两种方法:**
95 |
96 | 1.从Channel中写数据到Buffer
97 | ```java
98 | int bytesRead = inChannel.read(buf); //read into buffer.
99 | ```
100 | 2.通过put写数据:
101 | ```java
102 | buf.put(127);
103 | ```
104 |
105 | 4. **Buffer常用方法测试**
106 |
107 | 说实话,NIO编程真的难,通过后面这个测试例子,你可能才能勉强理解前面说的Buffer方法的作用。
108 |
109 |
110 | ### [三 Java NIO 之 Channel(通道)](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483966&idx=1&sn=d5cf18c69f5f9ec2aff149270422731f&chksm=fd98545fcaefdd49296e2c78000ce5da277435b90ba3c03b92b7cf54c6ccc71d61d13efbce63#rd)
111 |
112 |
113 | 1. **Channel(通道)介绍**
114 | - 通常来说NIO中的所有IO都是从 Channel(通道) 开始的。
115 | - NIO Channel通道和流的区别:
116 | 2. **FileChannel的使用**
117 | 3. **SocketChannel和ServerSocketChannel的使用**
118 | 4. **️DatagramChannel的使用**
119 | 5. **Scatter / Gather**
120 | - Scatter: 从一个Channel读取的信息分散到N个缓冲区中(Buufer).
121 | - Gather: 将N个Buffer里面内容按照顺序发送到一个Channel.
122 | 6. **通道之间的数据传输**
123 | - 在Java NIO中如果一个channel是FileChannel类型的,那么他可以直接把数据传输到另一个channel。
124 | - transferFrom() :transferFrom方法把数据从通道源传输到FileChannel
125 | - transferTo() :transferTo方法把FileChannel数据传输到另一个channel
126 |
127 |
128 | ### [四 Java NIO之Selector(选择器)](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483970&idx=1&sn=d5e2b133313b1d0f32872d54fbdf0aa7&chksm=fd985423caefdd354b587e57ce6cf5f5a7bec48b9ab7554f39a8d13af47660cae793956e0f46#rd)
129 |
130 |
131 | 1. **Selector(选择器)介绍**
132 | - Selector 一般称 为选择器 ,当然你也可以翻译为 多路复用器 。它是Java NIO核心组件中的一个,用于检查一个或多个NIO Channel(通道)的状态是否处于可读、可写。如此可以实现单线程管理多个channels,也就是可以管理多个网络链接。
133 | - 使用Selector的好处在于: 使用更少的线程来就可以来处理通道了, 相比使用多个线程,避免了线程上下文切换带来的开销。
134 | 2. **Selector(选择器)的使用方法介绍**
135 | - Selector的创建
136 | ```java
137 | Selector selector = Selector.open();
138 | ```
139 | - 注册Channel到Selector(Channel必须是非阻塞的)
140 | ```java
141 | channel.configureBlocking(false);
142 | SelectionKey key = channel.register(selector, Selectionkey.OP_READ);
143 | ```
144 | - SelectionKey介绍
145 |
146 | 一个SelectionKey键表示了一个特定的通道对象和一个特定的选择器对象之间的注册关系。
147 | - 从Selector中选择channel(Selecting Channels via a Selector)
148 |
149 | 选择器维护注册过的通道的集合,并且这种注册关系都被封装在SelectionKey当中.
150 | - 停止选择的方法
151 |
152 | wakeup()方法 和close()方法。
153 | 3. **模板代码**
154 |
155 | 有了模板代码我们在编写程序时,大多数时间都是在模板代码中添加相应的业务代码。
156 | 4. **客户端与服务端简单交互实例**
157 |
158 |
159 |
160 | ### [五 Java NIO之拥抱Path和Files](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483976&idx=1&sn=2296c05fc1b840a64679e2ad7794c96d&chksm=fd985429caefdd3f48e2ee6fdd7b0f6fc419df90b3de46832b484d6d1ca4e74e7837689c8146&token=537240785&lang=zh_CN#rd)
161 |
162 | **一 文件I/O基石:Path:**
163 | - 创建一个Path
164 | - File和Path之间的转换,File和URI之间的转换
165 | - 获取Path的相关信息
166 | - 移除Path中的冗余项
167 |
168 | **二 拥抱Files类:**
169 | - Files.exists() 检测文件路径是否存在
170 | - Files.createFile() 创建文件
171 | - Files.createDirectories()和Files.createDirectory()创建文件夹
172 | - Files.delete()方法 可以删除一个文件或目录
173 | - Files.copy()方法可以吧一个文件从一个地址复制到另一个位置
174 | - 获取文件属性
175 | - 遍历一个文件夹
176 | - Files.walkFileTree()遍历整个目录
177 |
178 | ### [六 NIO学习总结以及NIO新特性介绍](https://blog.csdn.net/a953713428/article/details/64907250)
179 |
180 | - **内存映射:**
181 |
182 | 这个功能主要是为了提高大文件的读写速度而设计的。内存映射文件(memory-mappedfile)能让你创建和修改那些大到无法读入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问了。将文件的一段区域映射到内存中,比传统的文件处理速度要快很多。内存映射文件它虽然最终也是要从磁盘读取数据,但是它并不需要将数据读取到OS内核缓冲区,而是直接将进程的用户私有地址空间中的一部分区域与文件对象建立起映射关系,就好像直接从内存中读、写文件一样,速度当然快了。
183 |
184 | ### [七 Java NIO AsynchronousFileChannel异步文件通](http://wiki.jikexueyuan.com/project/java-nio-zh/java-nio-asynchronousfilechannel.html)
185 |
186 | Java7中新增了AsynchronousFileChannel作为nio的一部分。AsynchronousFileChannel使得数据可以进行异步读写。
187 |
188 | ### [八 高并发Java(8):NIO和AIO](http://www.importnew.com/21341.html)
189 |
190 |
191 |
192 | ## 推荐阅读
193 |
194 | ### [在 Java 7 中体会 NIO.2 异步执行的快乐](https://www.ibm.com/developerworks/cn/java/j-lo-nio2/index.html)
195 |
196 | ### [Java AIO总结与示例](https://blog.csdn.net/x_i_y_u_e/article/details/52223406)
197 | AIO是异步IO的缩写,虽然NIO在网络操作中,提供了非阻塞的方法,但是NIO的IO行为还是同步的。对于NIO来说,我们的业务线程是在IO操作准备好时,得到通知,接着就由这个线程自行进行IO操作,IO操作本身是同步的。
198 |
199 |
200 | **欢迎关注我的微信公众号:"Java面试通关手册"(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美文,分享各种Java学习资源):**
201 |
--------------------------------------------------------------------------------
/Java/Java虚拟机(jvm).md:
--------------------------------------------------------------------------------
1 | Java面试通关手册(Java学习指南)github地址(欢迎star和pull):[https://github.com/Snailclimb/Java_Guide](https://github.com/Snailclimb/Java_Guide)
2 |
3 |
4 |
5 | 下面是按jvm虚拟机知识点分章节总结的一些jvm学习与面试相关的一些东西。一般作为Java程序员在面试的时候一般会问的大多就是**Java内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM内存管理**这些问题了。这些内容参考周的《深入理解Java虚拟机》中第二章和第三章就足够了对应下面的[深入理解虚拟机之Java内存区域:](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483910%26idx%3D1%26sn%3D246f39051a85fc312577499691fba89f%26chksm%3Dfd985467caefdd71f9a7c275952be34484b14f9e092723c19bd4ef557c324169ed084f868bdb%23rd)和[深入理解虚拟机之垃圾回收](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483914%26idx%3D1%26sn%3D9aa157d4a1570962c39783cdeec7e539%26chksm%3Dfd98546bcaefdd7d9f61cd356e5584e56b64e234c3a403ed93cb6d4dde07a505e3000fd0c427%23rd)这两篇文章。
6 |
7 |
8 | > ### 常见面试题
9 |
10 | [深入理解虚拟机之Java内存区域:](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483910%26idx%3D1%26sn%3D246f39051a85fc312577499691fba89f%26chksm%3Dfd985467caefdd71f9a7c275952be34484b14f9e092723c19bd4ef557c324169ed084f868bdb%23rd)
11 |
12 | 1. 介绍下Java内存区域(运行时数据区)。
13 |
14 | 2. 对象的访问定位的两种方式。
15 |
16 |
17 | [深入理解虚拟机之垃圾回收](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483914%26idx%3D1%26sn%3D9aa157d4a1570962c39783cdeec7e539%26chksm%3Dfd98546bcaefdd7d9f61cd356e5584e56b64e234c3a403ed93cb6d4dde07a505e3000fd0c427%23rd)
18 |
19 | 1. 如何判断对象是否死亡(两种方法)。
20 |
21 | 2. 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。
22 |
23 | 3. 垃圾收集有哪些算法,各自的特点?
24 |
25 | 4. HotSpot为什么要分为新生代和老年代?
26 |
27 | 5. 常见的垃圾回收器有那些?
28 |
29 | 6. 介绍一下CMS,G1收集器。
30 |
31 | 7. Minor Gc和Full GC 有什么不同呢?
32 |
33 |
34 |
35 | [虚拟机性能监控和故障处理工具](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483922%26idx%3D1%26sn%3D0695ff4c2700ccebb8fbc39011866bd8%26chksm%3Dfd985473caefdd6583eb42dbbc7f01918dc6827c808292bb74a5b6333e3d526c097c9351e694%23rd)
36 |
37 | 1. JVM调优的常见命令行工具有哪些?
38 |
39 | [深入理解虚拟机之类文件结构](https://link.zhihu.com/?target=https%3A//mp.weixin.qq.com/s%3F__biz%3DMzU4NDQ4MzU5OA%3D%3D%26mid%3D2247483926%26idx%3D1%26sn%3D224413da998f7e024f7b8d87397934d9%26chksm%3Dfd985477caefdd61a2fe1a3f0be29e057082252e579332f5b6d9072a150b838cefe2c47b6e5a%23rd)
40 |
41 | 1. 简单介绍一下Class类文件结构(常量池主要存放的是那两大常量?Class文件的继承关系是如何确定的?字段表、方法表、属性表主要包含那些信息?)
42 |
43 | [深入理解虚拟机之虚拟机类加载机制](http://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483934&idx=1&sn=f247f9bee4e240f5e7fac25659da3bff&chksm=fd98547fcaefdd6996e1a7046e03f29df9308bdf82ceeffd111112766ffd3187892700f64b40#rd)
44 |
45 | 1. 简单说说类加载过程,里面执行了哪些操作?
46 |
47 | 2. 对类加载器有了解吗?
48 |
49 | 3. 什么是双亲委派模型?
50 |
51 | 4. 双亲委派模型的工作过程以及使用它的好处。
52 |
53 |
54 |
55 |
56 |
57 | > ### 推荐阅读
58 |
59 | [深入理解虚拟机之虚拟机字节码执行引擎](https://juejin.im/post/5aebcb076fb9a07a9a10b5f3)
60 |
61 | [《深入理解 Java 内存模型》读书笔记](http://www.54tianzhisheng.cn/2018/02/28/Java-Memory-Model/) (非常不错的文章)
62 |
63 | [全面理解Java内存模型(JMM)及volatile关键字 ](https://blog.csdn.net/javazejian/article/details/72772461)
64 |
65 | **欢迎关注我的微信公众号:"Java面试通关手册"(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美文,分享各种Java学习资源):**
66 |
67 | 
68 |
--------------------------------------------------------------------------------
/Java/What's New in JDK8/JDK8接口规范-静态、默认方法.md:
--------------------------------------------------------------------------------
1 | JDK8接口规范
2 | ===
3 | 在JDK8中引入了lambda表达式,出现了函数式接口的概念,为了在扩展接口时保持向前兼容性(比如泛型也是为了保持兼容性而失去了在一些别的语言泛型拥有的功能),Java接口规范发生了一些改变。。
4 | ---
5 | ## 1.JDK8以前的接口规范
6 | - JDK8以前接口可以定义的变量和方法
7 | - 所有变量(Field)不论是否显式 的声明为```public static final```,它实际上都是```public static final```的。
8 | - 所有方法(Method)不论是否显示 的声明为```public abstract```,它实际上都是```public abstract```的。
9 | ```java
10 | public interface AInterfaceBeforeJDK8 {
11 | int FIELD = 0;
12 | void simpleMethod();
13 | }
14 | ```
15 | 以上接口信息反编译以后可以看到字节码信息里Filed是public static final的,而方法是public abstract的,即是你没有显示的去声明它。
16 | ```java
17 | {
18 | public static final int FIELD;
19 | descriptor: I
20 | flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
21 | ConstantValue: int 0
22 |
23 | public abstract void simpleMethod();
24 | descriptor: ()V
25 | flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
26 | }
27 | ```
28 | ## 2.JDK8之后的接口规范
29 | - JDK8之后接口可以定义的变量和方法
30 | - 变量(Field)仍然必须是 ```java public static final```的
31 | - 方法(Method)除了可以是public abstract之外,还可以是public static或者是default(相当于仅public修饰的实例方法)的。
32 | 从以上改变不难看出,修改接口的规范主要是为了能在扩展接口时保持向前兼容。
33 |
下面是一个JDK8之后的接口例子
34 | ```java
35 | public interface AInterfaceInJDK8 {
36 | int simpleFiled = 0;
37 | static int staticField = 1;
38 |
39 | public static void main(String[] args) {
40 | }
41 | static void staticMethod(){}
42 |
43 | default void defaultMethod(){}
44 |
45 | void simpleMethod() throws IOException;
46 |
47 | }
48 | ```
49 | 进行反编译(去除了一些没用信息)
50 | ```java
51 | {
52 | public static final int simpleFiled;
53 | flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
54 |
55 | public static final int staticField;
56 | flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
57 |
58 | public static void main(java.lang.String[]);
59 | flags: (0x0009) ACC_PUBLIC, ACC_STATIC
60 |
61 | public static void staticMethod();
62 | flags: (0x0009) ACC_PUBLIC, ACC_STATIC
63 |
64 | public void defaultMethod();
65 | flags: (0x0001) ACC_PUBLIC
66 |
67 | public abstract void simpleMethod() throws java.io.IOException;
68 | flags: (0x0401) ACC_PUBLIC, ACC_ABSTRACT
69 | Exceptions:
70 | throws java.io.IOException
71 | }
72 | ```
73 | 可以看到 default关键字修饰的方法是像实例方法一样定义的,所以我们来定义一个只有default的方法并且实现一下试一试。
74 | ```java
75 | interface Default {
76 | default int defaultMethod() {
77 | return 4396;
78 | }
79 | }
80 |
81 | public class DefaultMethod implements Default {
82 | public static void main(String[] args) {
83 | DefaultMethod defaultMethod = new DefaultMethod();
84 | System.out.println(defaultMethod.defaultMethod());
85 | //compile error : Non-static method 'defaultMethod()' cannot be referenced from a static context
86 | //! DefaultMethod.defaultMethod();
87 | }
88 | }
89 | ```
90 | 可以看到default方法确实像实例方法一样,必须有实例对象才能调用,并且子类在实现接口时,可以不用实现default方法,也可以覆盖该方法。
91 | 这有点像子类继承父类实例方法。
92 |
93 | 接口静态方法就像是类静态方法,唯一的区别是**接口静态方法只能通过接口名调用,而类静态方法既可以通过类名调用也可以通过实例调用**
94 | ```java
95 | interface Static {
96 | static int staticMethod() {
97 | return 4396;
98 | }
99 | }
100 | ... main(String...args)
101 | //!compile error: Static method may be invoked on containing interface class only
102 | //!aInstanceOfStatic.staticMethod();
103 | ...
104 | ```
105 | 另一个问题是多继承问题,大家知道Java中类是不支持多继承的,但是接口是多继承和多实现(implements后跟多个接口)的,
106 | 那么如果一个接口继承另一个接口,两个接口都有同名的default方法会怎么样呢?答案是会像类继承一样覆写(@Override),以下代码在IDE中可以顺利编译
107 | ```java
108 | interface Default {
109 | default int defaultMethod() {
110 | return 4396;
111 | }
112 | }
113 | interface Default2 extends Default {
114 | @Override
115 | default int defaultMethod() {
116 | return 9527;
117 | }
118 | }
119 | public class DefaultMethod implements Default,Default2 {
120 | public static void main(String[] args) {
121 | DefaultMethod defaultMethod = new DefaultMethod();
122 | System.out.println(defaultMethod.defaultMethod());
123 | }
124 | }
125 |
126 | 输出 : 9527
127 | ```
128 | 出现上面的情况时,会优先找继承树上近的方法,类似于“短路优先”。
129 |
130 | 那么如果一个类实现了两个没有继承关系的接口,且这两个接口有同名方法的话会怎么样呢?IDE会要求你重写这个冲突的方法,让你自己选择去执行哪个方法,因为IDE它
131 | 还没智能到你不告诉它,它就知道你想执行哪个方法。可以通过```java 接口名.super```指针来访问接口中定义的实例(default)方法。
132 | ```java
133 | interface Default {
134 | default int defaultMethod() {
135 | return 4396;
136 | }
137 | }
138 |
139 | interface Default2 {
140 | default int defaultMethod() {
141 | return 9527;
142 | }
143 | }
144 | //如果不重写
145 | //compile error : defaults.DefaultMethod inherits unrelated defaults for defaultMethod() from types defaults.Default and defaults.Default2
146 | public class DefaultMethod implements Default,Default2 {
147 | @Override
148 | public int defaultMethod() {
149 | System.out.println(Default.super.defaultMethod());
150 | System.out.println(Default2.super.defaultMethod());
151 | return 996;
152 | }
153 | public static void main(String[] args) {
154 | DefaultMethod defaultMethod = new DefaultMethod();
155 | System.out.println(defaultMethod.defaultMethod());
156 | }
157 | }
158 |
159 | 运行输出 :
160 | 4396
161 | 9527
162 | 996
163 | ```
164 |
--------------------------------------------------------------------------------
/Java/What's New in JDK8/Lambda表达式.md:
--------------------------------------------------------------------------------
1 | JDK8--Lambda表达式
2 | ===
3 | ## 1.什么是Lambda表达式
4 | **Lambda表达式实质上是一个可传递的代码块,Lambda又称为闭包或者匿名函数,是函数式编程语法,让方法可以像普通参数一样传递**
5 |
6 | ## 2.Lambda表达式语法
7 | ```(参数列表) -> {执行代码块}```
8 |
参数列表可以为空```()->{}```
9 |
可以加类型声明比如```(String para1, int para2) -> {return para1 + para2;}```我们可以看到,lambda同样可以有返回值.
10 |
在编译器可以推断出类型的时候,可以将类型声明省略,比如```(para1, para2) -> {return para1 + para2;}```
11 |
(lambda有点像动态类型语言语法。lambda在字节码层面是用invokedynamic实现的,而这条指令就是为了让JVM更好的支持运行在其上的动态类型语言)
12 |
13 | ## 3.函数式接口
14 | 在了解Lambda表达式之前,有必要先了解什么是函数式接口```(@FunctionalInterface)```
15 | **函数式接口指的是有且只有一个抽象(abstract)方法的接口**
16 | 当需要一个函数式接口的对象时,就可以用Lambda表达式来实现,举个常用的例子:
17 |
18 | ```java
19 | Thread thread = new Thread(() -> {
20 | System.out.println("This is JDK8's Lambda!");
21 | });
22 | ```
23 | 这段代码和函数式接口有啥关系?我们回忆一下,Thread类的构造函数里是不是有一个以Runnable接口为参数的?
24 | ```java
25 | public Thread(Runnable target) {...}
26 |
27 | /**
28 | * Runnable Interface
29 | */
30 | @FunctionalInterface
31 | public interface Runnable {
32 | public abstract void run();
33 | }
34 | ```
35 | 到这里大家可能已经明白了,**Lambda表达式相当于一个匿名类或者说是一个匿名方法**。上面Thread的例子相当于
36 | ```java
37 | Thread thread = new Thread(new Runnable() {
38 | @Override
39 | public void run() {
40 | System.out.println("Anonymous class");
41 | }
42 | });
43 | ```
44 | 也就是说,上面的lambda表达式相当于实现了这个run()方法,然后当做参数传入(个人感觉可以这么理解,lambda表达式就是一个函数,只不过它的返回值、参数列表都
45 | 由编译器帮我们推断,因此可以减少很多代码量)。
46 |
Lambda也可以这样用 :
47 | ```java
48 | Runnable runnable = () -> {...};
49 | ```
50 | 其实这和上面的用法没有什么本质上的区别。
51 |
至此大家应该明白什么是函数式接口以及函数式接口和lambda表达式之间的关系了。在JDK8中修改了接口的规范,
52 | 目的是为了在给接口添加新的功能时保持向前兼容(个人理解),比如一个已经定义了的函数式接口,某天我们想给它添加新功能,那么就不能保持向前兼容了,
53 | 因为在旧的接口规范下,添加新功能必定会破坏这个函数式接口[(JDK8中接口规范)]()
54 |
55 | 除了上面说的Runnable接口之外,JDK中已经存在了很多函数式接口
56 | 比如(当然不止这些):
57 | - ```java.util.concurrent.Callable```
58 | - ```java.util.Comparator```
59 | - ```java.io.FileFilter```
60 |
**关于JDK中的预定义的函数式接口**
61 |
62 | - JDK在```java.util.function```下预定义了很多函数式接口
63 | - ```Function {R apply(T t);}``` 接受一个T对象,然后返回一个R对象,就像普通的函数。
64 | - ```Consumer {void accept(T t);}``` 消费者 接受一个T对象,没有返回值。
65 | - ```Predicate {boolean test(T t);}``` 判断,接受一个T对象,返回一个布尔值。
66 | - ```Supplier {T get();} 提供者(工厂)``` 返回一个T对象。
67 | - 其他的跟上面的相似,大家可以看一下function包下的具体接口。
68 | ## 4.变量作用域
69 | ```java
70 | public class VaraibleHide {
71 | @FunctionalInterface
72 | interface IInner {
73 | void printInt(int x);
74 | }
75 | public static void main(String[] args) {
76 | int x = 20;
77 | IInner inner = new IInner() {
78 | int x = 10;
79 | @Override
80 | public void printInt(int x) {
81 | System.out.println(x);
82 | }
83 | };
84 | inner.printInt(30);
85 |
86 | inner = (s) -> {
87 | //Variable used in lambda expression should be final or effectively final
88 | //!int x = 10;
89 | //!x= 50; error
90 | System.out.print(x);
91 | };
92 | inner.printInt(30);
93 | }
94 | }
95 | 输出 :
96 | 30
97 | 20
98 | ```
99 | 对于lambda表达式```java inner = (s) -> {System.out.print(x);};```,变量x并不是在lambda表达式中定义的,像这样并不是在lambda中定义或者通过lambda的参数列表()获取的变量成为自由变量,它是被lambda表达式捕获的。
100 |
lambda表达式和内部类一样,对外部自由变量捕获时,外部自由变量必须为final或者是最终变量(effectively final)的,也就是说这个变量初始化后就不能为它赋新值,
101 | 同时lambda不像内部类/匿名类,lambda表达式与外围嵌套块有着相同的作用域,因此对变量命名的有关规则对lambda同样适用。大家阅读上面的代码对这些概念应该
102 | 不难理解。
103 | ## 5.方法引用
104 | **只需要提供方法的名字,具体的调用过程由Lambda和函数式接口来确定,这样的方法调用成为方法引用。**
105 |
下面的例子会打印list中的每个元素:
106 | ```java
107 | List list = new ArrayList<>();
108 | for (int i = 0; i < 10; ++i) {
109 | list.add(i);
110 | }
111 | list.forEach(System.out::println);
112 | ```
113 | 其中```System.out::println```这个就是一个方法引用,等价于Lambda表达式 ```(para)->{System.out.println(para);}```
114 |
我们看一下List#forEach方法 ```default void forEach(Consumer super T> action)```可以看到它的参数是一个Consumer接口,该接口是一个函数式接口
115 | ```java
116 | @FunctionalInterface
117 | public interface Consumer {
118 | void accept(T t);
119 | ```
120 | 大家能发现这个函数接口的方法和```System.out::println```有什么相似的么?没错,它们有着相似的参数列表和返回值。
121 |
我们自己定义一个方法,看看能不能像标准输出的打印函数一样被调用
122 | ```java
123 | public class MethodReference {
124 | public static void main(String[] args) {
125 | List list = new ArrayList<>();
126 | for (int i = 0; i < 10; ++i) {
127 | list.add(i);
128 | }
129 | list.forEach(MethodReference::myPrint);
130 | }
131 |
132 | static void myPrint(int i) {
133 | System.out.print(i + ", ");
134 | }
135 | }
136 |
137 | 输出: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
138 | ```
139 | 可以看到,我们自己定义的方法也可以当做方法引用。
140 |
到这里大家多少对方法引用有了一定的了解,我们再来说一下方法引用的形式。
141 | - 方法引用
142 | - 类名::静态方法名
143 | - 类名::实例方法名
144 | - 类名::new (构造方法引用)
145 | - 实例名::实例方法名
146 | 可以看出,方法引用是通过(方法归属名)::(方法名)来调用的。通过上面的例子已经讲解了一个`类名::静态方法名`的使用方法了,下面再依次介绍其余的几种
147 | 方法引用的使用方法。
148 | **类名::实例方法名**
149 | 先来看一段代码
150 | ```java
151 | String[] strings = new String[10];
152 | Arrays.sort(strings, String::compareToIgnoreCase);
153 | ```
154 | **上面的String::compareToIgnoreCase等价于(x, y) -> {return x.compareToIgnoreCase(y);}**
155 | 我们看一下`Arrays#sort`方法`public static void sort(T[] a, Comparator super T> c)`,
156 | 可以看到第二个参数是一个Comparator接口,该接口也是一个函数式接口,其中的抽象方法是`int compare(T o1, T o2);`,再看一下
157 | `String#compareToIgnoreCase`方法,`public int compareToIgnoreCase(String str)`,这个方法好像和上面讲方法引用中`类名::静态方法名`不大一样啊,它
158 | 的参数列表和函数式接口的参数列表不一样啊,虽然它的返回值一样?
159 |
是的,确实不一样但是别忘了,String类的这个方法是个实例方法,而不是静态方法,也就是说,这个方法是需要有一个接收者的。所谓接收者就是
160 | instance.method(x)中的instance,
161 | 它是某个类的实例,有的朋友可能已经明白了。上面函数式接口的`compare(T o1, T o2)`中的第一个参数作为了实例方法的接收者,而第二个参数作为了实例方法的
162 | 参数。我们再举一个自己实现的例子:
163 | ```java
164 | public class MethodReference {
165 | static Random random = new Random(47);
166 | public static void main(String[] args) {
167 | MethodReference[] methodReferences = new MethodReference[10];
168 | Arrays.sort(methodReferences, MethodReference::myCompare);
169 | }
170 | int myCompare(MethodReference o) {
171 | return random.nextInt(2) - 1;
172 | }
173 | }
174 | ```
175 | 上面的例子可以在IDE里通过编译,大家有兴趣的可以模仿上面的例子自己写一个程序,打印出排序后的结果。
176 |
**构造器引用**
177 | 构造器引用仍然需要与特定的函数式接口配合使用,并不能像下面这样直接使用。IDE会提示String不是一个函数式接口
178 | ```java
179 | //compile error : String is not a functional interface
180 | String str = String::new;
181 | ```
182 | 下面是一个使用构造器引用的例子,可以看出构造器引用可以和这种工厂型的函数式接口一起使用的。
183 | ```java
184 | interface IFunctional {
185 | T func();
186 | }
187 |
188 | public class ConstructorReference {
189 |
190 | public ConstructorReference() {
191 | }
192 |
193 | public static void main(String[] args) {
194 | Supplier supplier0 = () -> new ConstructorReference();
195 | Supplier supplier1 = ConstructorReference::new;
196 | IFunctional functional = () -> new ConstructorReference();
197 | IFunctional functional1 = ConstructorReference::new;
198 | }
199 | }
200 | ```
201 | 下面是一个JDK官方的例子
202 | ```java
203 | public static , DEST extends Collection>
204 | DEST transferElements(
205 | SOURCE sourceCollection,
206 | Supplier collectionFactory) {
207 |
208 | DEST result = collectionFactory.get();
209 | for (T t : sourceCollection) {
210 | result.add(t);
211 | }
212 | return result;
213 | }
214 |
215 | ...
216 |
217 | Set rosterSet = transferElements(
218 | roster, HashSet::new);
219 | ```
220 |
221 | **实例::实例方法**
222 |
223 | 其实开始那个例子就是一个实例::实例方法的引用
224 | ```java
225 | List list = new ArrayList<>();
226 | for (int i = 0; i < 10; ++i) {
227 | list.add(i);
228 | }
229 | list.forEach(System.out::println);
230 | ```
231 | 其中System.out就是一个实例,println是一个实例方法。相信不用再给大家做解释了。
232 | ## 总结
233 | Lambda表达式是JDK8引入Java的函数式编程语法,使用Lambda需要直接或者间接的与函数式接口配合,在开发中使用Lambda可以减少代码量,
234 | 但是并不是说必须要使用Lambda(虽然它是一个很酷的东西)。有些情况下使用Lambda会使代码的可读性急剧下降,并且也节省不了多少代码,
235 | 所以在实际开发中还是需要仔细斟酌是否要使用Lambda。和Lambda相似的还有JDK10中加入的var类型推断,同样对于这个特性需要斟酌使用。
236 |
--------------------------------------------------------------------------------
/Java/What's New in JDK8/改进的类型推断.md:
--------------------------------------------------------------------------------
1 | ## 改进的类型推断
2 | ### 1.什么是类型推断
3 | 类型推断就像它的字面意思一样,编译器根据你显示声明的已知的信息 推断出你没有显示声明的类型,这就是类型推断。
4 | 看过《Java编程思想 第四版》的朋友可能还记得里面讲解泛型一章的时候,里面很多例子是下面这样的:
5 | ```java
6 | Map map = new Map();
7 | ```
8 | 而我们平常写的都是这样的:
9 | ```java
10 | Map map = new Map<>();
11 | ```
12 | 这就是类型推断,《Java编程思想 第四版》这本书出书的时候最新的JDK只有1.6(JDK7推出的类型推断),在Java编程思想里Bruce Eckel大叔还提到过这个问题
13 | (可能JDK的官方人员看了Bruce Eckel大叔的Thinking in Java才加的类型推断,☺),在JDK7中推出了上面这样的类型推断,可以减少一些无用的代码。
14 | (Java编程思想到现在还只有第四版,是不是因为Bruce Eckel大叔觉得Java新推出的语言特性“然并卵”呢?/滑稽)
15 |
16 | 在JDK7中,类型推断只有上面例子的那样的能力,即只有在使用**赋值语句**时才能自动推断出泛型参数信息(即<>里的信息),下面的官方文档里的例子在JDK7里会编译
17 | 错误
18 | ```java
19 | List stringList = new ArrayList<>();
20 | stringList.add("A");
21 | //error : addAll(java.util.Collection extends java.lang.String>)in List cannot be applied to (java.util.List)
22 | stringList.addAll(Arrays.asList());
23 | ```
24 | 但是上面的代码在JDK8里可以通过,也就说,JDK8里,类型推断不仅可以用于赋值语句,而且可以根据代码中上下文里的信息推断出更多的信息,因此我们需要些的代码
25 | 会更少。加强的类型推断还有一个就是用于Lambda表达式了。
26 |
27 | 大家其实不必细究类型推断,在日常使用中IDE会自动判断,当IDE自己无法推断出足够的信息时,就需要我们额外做一下工作,比如在<>里添加更多的类型信息,
28 | 相信随着Java的进化,这些便利的功能会越来越强大。
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Java/What's New in JDK8/通过反射获得方法的参数信息.md:
--------------------------------------------------------------------------------
1 | ## 通过反射获得方法的参数信息
2 | JDK8之前 .class文件是不会存储方法参数信息的,因此也就无法通过反射获取该信息(想想反射获取类信息的入口是什么?当然就是Class类了)。即是是在JDK11里
3 | 也不会默认生成这些信息,可以通过在javac加上-parameters参数来让javac生成这些信息(javac就是java编译器,可以把java文件编译成.class文件)。生成额外
4 | 的信息(运行时非必须信息)会消耗内存并且有可能公布敏感信息(某些方法参数比如password,JDK文档里这么说的),并且确实很多信息javac并不会为我们生成,比如
5 | LocalVariableTable,javac就不会默认生成,需要你加上 -g:vars来强制让编译器生成,同样的,方法参数信息也需要加上
6 | -parameters来让javac为你在.class文件中生成这些信息,否则运行时反射是无法获取到这些信息的。在讲解Java语言层面的方法之前,先看一下javac加上该
7 | 参数和不加生成的信息有什么区别(不感兴趣想直接看运行代码的可以跳过这段)。下面是随便写的一个类。
8 | ```java
9 | public class ByteCodeParameters {
10 | public String simpleMethod(String canUGetMyName, Object yesICan) {
11 | return "9527";
12 | }
13 | }
14 | ```
15 | 先来不加参数编译和反编译一下这个类javac ByteCodeParameters.java , javap -v ByteCodeParameters:
16 | ```java
17 | //只截取了部分信息
18 | public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
19 | descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
20 | flags: (0x0001) ACC_PUBLIC
21 | Code:
22 | stack=1, locals=3, args_size=3
23 | 0: ldc #2 // String 9527
24 | 2: areturn
25 | LineNumberTable:
26 | line 5: 0
27 | //这个方法的描述到这里就结束了
28 | ```
29 | 接下来我们加上参数javac -parameters ByteCodeParameters.java 再来看反编译的信息:
30 | ```java
31 | public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
32 | descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
33 | flags: (0x0001) ACC_PUBLIC
34 | Code:
35 | stack=1, locals=3, args_size=3
36 | 0: ldc #2 // String 9527
37 | 2: areturn
38 | LineNumberTable:
39 | line 8: 0
40 | MethodParameters:
41 | Name Flags
42 | canUGetMyName
43 | yesICan
44 | ```
45 | 可以看到.class文件里多了一个MethodParameters信息,这就是参数的名字,可以看到默认是不保存的。
46 |
下面看一下在Intelj Idea里运行的这个例子,我们试一下通过反射获取方法名 :
47 | ```java
48 | public class ByteCodeParameters {
49 | public String simpleMethod(String canUGetMyName, Object yesICan) {
50 | return "9527";
51 | }
52 |
53 | public static void main(String[] args) throws NoSuchMethodException {
54 | Class> clazz = ByteCodeParameters.class;
55 | Method simple = clazz.getDeclaredMethod("simpleMethod", String.class, Object.class);
56 | Parameter[] parameters = simple.getParameters();
57 | for (Parameter p : parameters) {
58 | System.out.println(p.getName());
59 | }
60 | }
61 | }
62 | 输出 :
63 | arg0
64 | arg1
65 | ```
66 | ???说好的方法名呢????别急,哈哈。前面说了,默认是不生成参数名信息的,因此我们需要做一些配置,我们找到IDEA的settings里的Java Compiler选项,在
67 | Additional command line parameters:一行加上-parameters(Eclipse 也是找到Java Compiler选中Stoer information about method parameters),或者自
68 | 己编译一个.class文件放在IDEA的out下,然后再来运行 :
69 | ```java
70 | 输出 :
71 | canUGetMyName
72 | yesICan
73 | ```
74 | 这样我们就通过反射获取到参数信息了。想要了解更多的同学可以自己研究一下 [官方文档]
75 | (https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html)
76 |
77 | ## 总结与补充
78 | 在JDK8之后,可以通过-parameters参数来让编译器生成参数信息然后在运行时通过反射获取方法参数信息,其实在SpringFramework
79 | 里面也有一个LocalVariableTableParameterNameDiscoverer对象可以获取方法参数名信息,有兴趣的同学可以自行百度(这个类在打印日志时可能会比较有用吧,个人感觉)。
80 |
--------------------------------------------------------------------------------
/Java/多线程系列.md:
--------------------------------------------------------------------------------
1 | > ## 多线程系列文章
2 | 下列文章,我都更新在了我的博客专栏:[Java并发编程指南](https://blog.csdn.net/column/details/20860.html)。
3 |
4 | 1. [Java多线程学习(一)Java多线程入门](http://blog.csdn.net/qq_34337272/article/details/79640870)
5 | 2. [Java多线程学习(二)synchronized关键字(1)](http://blog.csdn.net/qq_34337272/article/details/79655194)
6 | 3. [Java多线程学习(二)synchronized关键字(2)](http://blog.csdn.net/qq_34337272/article/details/79670775)
7 | 4. [Java多线程学习(三)volatile关键字](http://blog.csdn.net/qq_34337272/article/details/79680771)
8 | 5. [Java多线程学习(四)等待/通知(wait/notify)机制](http://blog.csdn.net/qq_34337272/article/details/79690279)
9 |
10 | 6. [Java多线程学习(五)线程间通信知识点补充](http://blog.csdn.net/qq_34337272/article/details/79694226)
11 | 7. [Java多线程学习(六)Lock锁的使用](http://blog.csdn.net/qq_34337272/article/details/79714196)
12 | 8. [Java多线程学习(七)并发编程中一些问题](https://blog.csdn.net/qq_34337272/article/details/79844051)
13 | 9. [Java多线程学习(八)线程池与Executor 框架](https://blog.csdn.net/qq_34337272/article/details/79959271)
14 |
15 |
16 | > ## 多线程系列文章重要知识点与思维导图
17 |
18 | ### Java多线程学习(一)Java多线程入门
19 |
20 | 
21 |
22 | ### Java多线程学习(二)synchronized关键字(1)
23 | 
24 |
25 | 注意:**可重入锁的概念**。
26 |
27 | 另外要注意:**synchronized取得的锁都是对象锁,而不是把一段代码或方法当做锁。** 如果多个线程访问的是同一个对象,哪个线程先执行带synchronized关键字的方法,则哪个线程就持有该方法,那么其他线程只能呈等待状态。如果多个线程访问的是多个对象则不一定,因为多个对象会产生多个锁。
28 |
29 | ### Java多线程学习(二)synchronized关键字(2)
30 |
31 | 
32 |
33 | **注意:**
34 |
35 | - 其他线程执行对象中**synchronized同步方法**(上一节我们介绍过,需要回顾的可以看上一节的文章)和**synchronized(this)代码块**时呈现同步效果;
36 | - **如果两个线程使用了同一个“对象监视器”(synchronized(object)),运行结果同步,否则不同步**.
37 |
38 | **synchronized关键字加到static静态方法**和**synchronized(class)代码块**上都是是给**Class类**上锁,而**synchronized关键字加到非static静态方法**上是给**对象**上锁。
39 |
40 | 数据类型String的常量池属性:**在Jvm中具有String常量池缓存的功能**
41 |
42 | ### Java多线程学习(三)volatile关键字
43 |
44 | 
45 | **注意:**
46 |
47 | **synchronized关键字**和**volatile关键字**比较
48 |
49 | ### Java多线程学习(四)等待/通知(wait/notify)机制
50 |
51 | 
52 |
53 | ### Java多线程学习(五)线程间通信知识点补充
54 |
55 | 
56 | **注意:** ThreadLocal类主要解决的就是让每个线程绑定自己的值,可以将ThreadLocal类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
57 |
58 | ### Java多线程学习(六)Lock锁的使用
59 |
60 | 
61 |
62 | ### Java多线程学习(七)并发编程中一些问题
63 |
64 | 
65 |
66 | ### Java多线程学习(八)线程池与Executor 框架
67 |
68 | 
69 |
70 |
--------------------------------------------------------------------------------
/Java/设计模式.md:
--------------------------------------------------------------------------------
1 | # Java 设计模式
2 |
3 | 下面是自己学习设计模式的时候做的总结,有些是自己的原创文章,有些是网上写的比较好的文章,保存下来细细消化吧!
4 |
5 | **系列文章推荐:**
6 |
7 | ## 创建型模式
8 |
9 | ### 创建型模式概述
10 |
11 | - 创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
12 | - 创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。
13 |
14 | 
15 |
16 | ### 常见创建型模式详解
17 |
18 | - **单例模式:** [深入理解单例模式——只有一个实例](https://blog.csdn.net/qq_34337272/article/details/80455972)
19 | - **工厂模式:** [深入理解工厂模式——由对象工厂生成对象](https://blog.csdn.net/qq_34337272/article/details/80472071)
20 | - **建造者模式:** [深入理解建造者模式 ——组装复杂的实例](http://blog.csdn.net/qq_34337272/article/details/80540059)
21 | - **原型模式:** [深入理解原型模式 ——通过复制生成实例](https://blog.csdn.net/qq_34337272/article/details/80706444)
22 |
23 | ## 结构型模式
24 |
25 | ### 结构型模式概述
26 |
27 | - **结构型模式(Structural Pattern):** 描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构
28 | 
29 | - **结构型模式可以分为类结构型模式和对象结构型模式:**
30 | - 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
31 | - 对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
32 |
33 | 
34 |
35 | ### 常见结构型模式详解
36 |
37 | - **适配器模式:**
38 | - [深入理解适配器模式——加个“适配器”以便于复用](https://segmentfault.com/a/1190000011856448)
39 | - [适配器模式原理及实例介绍-IBM](https://www.ibm.com/developerworks/cn/java/j-lo-adapter-pattern/index.html)
40 | - **桥接模式:** [设计模式笔记16:桥接模式(Bridge Pattern)](https://blog.csdn.net/yangzl2008/article/details/7670996)
41 | - **组合模式:** [大话设计模式—组合模式](https://blog.csdn.net/lmb55/article/details/51039781)
42 | - **装饰模式:** [java模式—装饰者模式](https://www.cnblogs.com/chenxing818/p/4705919.html)、[Java设计模式-装饰者模式](https://blog.csdn.net/cauchyweierstrass/article/details/48240147)
43 | - **外观模式:** [java设计模式之外观模式(门面模式)](https://www.cnblogs.com/lthIU/p/5860607.html)
44 | - **享元模式:** [享元模式](http://www.jasongj.com/design_pattern/flyweight/)
45 | - **代理模式:**
46 | - [代理模式原理及实例讲解 (IBM出品,很不错)](https://www.ibm.com/developerworks/cn/java/j-lo-proxy-pattern/index.html)
47 | - [轻松学,Java 中的代理模式及动态代理](https://blog.csdn.net/briblue/article/details/73928350)
48 | - [Java代理模式及其应用](https://blog.csdn.net/justloveyou_/article/details/74203025)
49 |
50 |
51 | ## 行为型模式
52 |
53 | ### 行为型模式概述
54 |
55 | - 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
56 | - 行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
57 | - 通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
58 |
59 | **行为型模式分为类行为型模式和对象行为型模式两种:**
60 |
61 | - **类行为型模式:** 类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
62 | - **对象行为型模式:** 对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。
63 |
64 | 
65 |
66 | - **职责链模式:**
67 | - [Java设计模式之责任链模式、职责链模式](https://blog.csdn.net/jason0539/article/details/45091639)
68 | - [责任链模式实现的三种方式](https://www.cnblogs.com/lizo/p/7503862.html)
69 | - **命令模式:** 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。
70 | - **解释器模式:**
71 | - **迭代器模式:**
72 | - **中介者模式:**
73 | - **备忘录模式:**
74 | - **观察者模式:**
75 | - **状态模式:**
76 | - **策略模式:**
77 |
78 | 策略模式作为设计原则中开闭原则最典型的体现,也是经常使用的。下面这篇博客介绍了策略模式一般的组成部分和概念,并用了一个小demo去说明了策略模式的应用。
79 |
80 | [java设计模式之策略模式](https://blog.csdn.net/zlj1217/article/details/81230077)
81 |
82 | - **模板方法模式:**
83 | - **访问者模式:**
84 |
85 |
--------------------------------------------------------------------------------
/主流框架/Spring学习与面试.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Spring相关教程/资料:
4 |
5 | > ## 官网相关
6 |
7 | [Spring官网](https://spring.io/)
8 |
9 | [Spring系列主要项目](https://spring.io/projects)
10 |
11 | 从配置到安全性,Web应用到大数据 - 无论您的应用程序的基础架构需求如何,都有一个Spring Project来帮助您构建它。 从小处着手,根据需要使用 - Spring是通过设计模块化的。
12 |
13 | [Spring官网指南](https://spring.io/guides)
14 |
15 | 无论您在构建什么,这些指南都旨在尽可能快地提高您的工作效率 - 使用Spring团队推荐的最新Spring项目发布和技术。
16 |
17 | [Spring官方文档翻译(1~6章)](https://blog.csdn.net/tangtong1/article/details/51326887)
18 |
19 | > ## 系统学习教程:
20 |
21 | ### 文档:
22 |
23 | [极客学院Spring Wiki](http://wiki.jikexueyuan.com/project/spring/transaction-management.html)
24 |
25 | [Spring W3Cschool教程 ](https://www.w3cschool.cn/wkspring/f6pk1ic8.html)
26 |
27 | ### 视频:
28 |
29 | [网易云课堂——58集精通java教程Spring框架开发](http://study.163.com/course/courseMain.htm?courseId=1004475015#/courseDetail?tab=1&35)
30 |
31 | [慕课网相关视频](https://www.imooc.com/)
32 |
33 | **黑马视频(非常推荐):**
34 | 微信公众号:“**Java面试通关手册**”后台回复“**资源分享第一波**”免费领取。
35 |
36 | > ## 一些常用的东西
37 |
38 | [Spring Framework 4.3.17.RELEASE API](https://docs.spring.io/spring/docs/4.3.17.RELEASE/javadoc-api/)
39 |
40 | 默认浏览器打开,当需要查某个类的作用的时候,可以在浏览器通过ctrl+f搜索。
41 |
42 |
43 | # 面试必备知识点
44 |
45 |
46 | > ## SpringAOP,IOC实现原理
47 |
48 | AOP实现原理、动态代理和静态代理、Spring IOC的初始化过程、IOC原理、自己实现怎么实现一个IOC容器?这些东西都是经常会被问到的。
49 |
50 | [自己动手实现的 Spring IOC 和 AOP - 上篇](http://www.coolblog.xyz/2018/01/18/自己动手实现的-Spring-IOC-和-AOP-上篇/)
51 |
52 | [自己动手实现的 Spring IOC 和 AOP - 下篇](http://www.coolblog.xyz/2018/01/18/自己动手实现的-Spring-IOC-和-AOP-下篇/)
53 |
54 | ### AOP:
55 |
56 | AOP思想的实现一般都是基于 **代理模式** ,在JAVA中一般采用JDK动态代理模式,但是我们都知道,**JDK动态代理模式只能代理接口而不能代理类**。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。
57 |
58 | - 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
59 | - 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。
60 |
61 |
62 |
63 | [※静态代理、JDK动态代理、CGLIB动态代理讲解](http://www.cnblogs.com/puyangsky/p/6218925.html)
64 |
65 | 我们知道AOP思想的实现一般都是基于 **代理模式** ,所以在看下面的文章之前建议先了解一下静态代理以及JDK动态代理、CGLIB动态代理的实现方式。
66 |
67 | [Spring AOP 入门](https://juejin.im/post/5aa7818af265da23844040c6)
68 |
69 | 带你入门的一篇文章。这篇文章主要介绍了AOP中的基本概念:5种类型的通知(Before,After,After-returning,After-throwing,Around);Spring中对AOP的支持:AOP思想的实现一般都是基于代理模式,在JAVA中一般采用JDK动态代理模式,Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理,
70 |
71 | [※Spring AOP 基于AspectJ注解如何实现AOP](https://juejin.im/post/5a55af9e518825734d14813f)
72 |
73 |
74 | **AspectJ是一个AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能(当然需要特殊的编译器)**,可以这样说AspectJ是目前实现AOP框架中最成熟,功能最丰富的语言,更幸运的是,AspectJ与java程序完全兼容,几乎是无缝关联,因此对于有java编程基础的工程师,上手和使用都非常容易
75 |
76 | Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别。
77 |
78 |
79 | [※探秘Spring AOP(慕课网视频,很不错)](https://www.imooc.com/learn/869)
80 |
81 | 慕课网视频,讲解的很不错,详细且深入
82 |
83 |
84 | [spring源码剖析(六)AOP实现原理剖析](https://blog.csdn.net/fighterandknight/article/details/51209822)
85 |
86 | 通过源码分析Spring AOP的原理
87 |
88 | ### IOC:
89 |
90 | Spring IOC的初始化过程:
91 | 
92 |
93 | [[Spring框架]Spring IOC的原理及详解。](https://www.cnblogs.com/wang-meng/p/5597490.html)
94 |
95 | [Spring IOC核心源码学习](https://yikun.github.io/2015/05/29/Spring-IOC核心源码学习/)
96 |
97 | 比较简短,推荐阅读。
98 |
99 | [Spring IOC 容器源码分析](https://javadoop.com/post/spring-ioc)
100 |
101 | 强烈推荐,内容详尽,而且便于阅读。
102 |
103 | > ## Spring事务管理
104 |
105 | [可能是最漂亮的Spring事务管理详解](https://juejin.im/post/5b00c52ef265da0b95276091)
106 |
107 | [Spring编程式和声明式事务实例讲解](https://juejin.im/post/5b010f27518825426539ba38)
108 |
109 | > ## 其他
110 |
111 | **Spring单例与线程安全:**
112 |
113 | [Spring框架中的单例模式(源码解读)](http://www.cnblogs.com/chengxuyuanzhilu/p/6404991.html)
114 |
115 | 单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中一个类只有一个实例。spring依赖注入时,使用了 多重判断加锁 的单例模式。
116 |
117 | > ## Spring源码阅读
118 |
119 | 阅读源码不仅可以加深我们对Spring设计思想的理解,提高自己的编码水品,还可以让自己在面试中如鱼得水。下面的是Github上的一个开源的Spring源码阅读,大家有时间可以看一下,当然你如果有时间也可以自己慢慢研究源码。
120 |
121 | ### [Spring源码阅读](https://github.com/seaswalker/Spring)
122 | - [spring-core](https://github.com/seaswalker/Spring/blob/master/note/Spring.md)
123 | - [spring-aop](https://github.com/seaswalker/Spring/blob/master/note/spring-aop.md)
124 | - [spring-context](https://github.com/seaswalker/Spring/blob/master/note/spring-context.md)
125 | - [spring-task](https://github.com/seaswalker/Spring/blob/master/note/spring-task.md)
126 | - [spring-transaction](https://github.com/seaswalker/Spring/blob/master/note/spring-transaction.md)
127 | - [spring-mvc](https://github.com/seaswalker/Spring/blob/master/note/spring-mvc.md)
128 | - [guava-cache](https://github.com/seaswalker/Spring/blob/master/note/guava-cache.md)
129 |
--------------------------------------------------------------------------------
/主流框架/ZooKeeper数据模型和常见命令.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | - [ZooKeeper 数据模型](#zookeeper-数据模型)
4 | - [ZNode\(数据节点\)的结构](#znode数据节点的结构)
5 | - [测试 ZooKeeper 中的常见操作](#测试-zookeeper-中的常见操作)
6 | - [连接 ZooKeeper 服务](#连接-zookeeper-服务)
7 | - [查看常用命令\(help 命令\)](#查看常用命令help-命令)
8 | - [创建节点\(create 命令\)](#创建节点create-命令)
9 | - [更新节点数据内容\(set 命令\)](#更新节点数据内容set-命令)
10 | - [获取节点的数据\(get 命令\)](#获取节点的数据get-命令)
11 | - [查看某个目录下的子节点\(ls 命令\)](#查看某个目录下的子节点ls-命令)
12 | - [查看节点状态\(stat 命令\)](#查看节点状态stat-命令)
13 | - [查看节点信息和状态\(ls2 命令\)](#查看节点信息和状态ls2-命令)
14 | - [删除节点\(delete 命令\)](#删除节点delete-命令)
15 | - [参考](#参考)
16 |
17 |
18 |
19 | > 看本文之前如果你没有安装 ZooKeeper 的话,可以参考这篇文章:[《使用 SpringBoot+Dubbo 搭建一个简单分布式服务》](https://github.com/Snailclimb/springboot-integration-examples/blob/master/md/springboot-dubbo.md) 的 “开始实战 1 :zookeeper 环境安装搭建” 这部分进行安装(Centos7.4 环境下)。如果你想对 ZooKeeper 有一个整体了解的话,可以参考这篇文章:[《可能是把 ZooKeeper 概念讲的最清楚的一篇文章》](https://github.com/Snailclimb/JavaGuide/blob/master/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6/ZooKeeper.md)
20 |
21 | ### ZooKeeper 数据模型
22 |
23 | ZNode(数据节点)是 ZooKeeper 中数据的最小单元,每个ZNode上都可以保存数据,同时还是可以有子节点(这就像树结构一样,如下图所示)。可以看出,节点路径标识方式和Unix文件
24 | 系统路径非常相似,都是由一系列使用斜杠"/"进行分割的路径表示,开发人员可以向这个节点中写人数据,也可以在节点下面创建子节点。这些操作我们后面都会介绍到。
25 | 
26 |
27 | 提到 ZooKeeper 数据模型,还有一个不得不得提的东西就是 **事务 ID** 。事务的ACID(Atomic:原子性;Consistency:一致性;Isolation:隔离性;Durability:持久性)四大特性我在这里就不多说了,相信大家也已经挺腻了。
28 |
29 | 在Zookeeper中,事务是指能够改变 ZooKeeper 服务器状态的操作,我们也称之为事务操作或更新操作,一般包括数据节点创建与删除、数据节点内容更新和客户端会话创建与失效等操作。对于每一个事务请求,**ZooKeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 来表示**,通常是一个64位的数字。每一个ZXID对应一次更新操作,**从这些 ZXID 中可以间接地识别出Zookeeper处理这些更新操作请求的全局顺序**。
30 |
31 |
32 |
33 | ### ZNode(数据节点)的结构
34 |
35 | 每个 ZNode 由2部分组成:
36 |
37 | - stat:状态信息
38 | - data:数据内容
39 |
40 | 如下所示,我通过 get 命令来获取 根目录下的 dubbo 节点的内容。(get 命令在下面会介绍到)
41 |
42 | ```shell
43 | [zk: 127.0.0.1:2181(CONNECTED) 6] get /dubbo
44 | # 该数据节点关联的数据内容为空
45 | null
46 | # 下面是该数据节点的一些状态信息,其实就是 Stat 对象的格式化输出
47 | cZxid = 0x2
48 | ctime = Tue Nov 27 11:05:34 CST 2018
49 | mZxid = 0x2
50 | mtime = Tue Nov 27 11:05:34 CST 2018
51 | pZxid = 0x3
52 | cversion = 1
53 | dataVersion = 0
54 | aclVersion = 0
55 | ephemeralOwner = 0x0
56 | dataLength = 0
57 | numChildren = 1
58 |
59 | ```
60 | 这些状态信息其实就是 Stat 对象的格式化输出。Stat 类中包含了一个数据节点的所有状态信息的字段,包括事务ID、版本信息和子节点个数等,如下图所示(图源:《从Paxos到Zookeeper 分布式一致性原理与实践》,下面会介绍通过 stat 命令查看数据节点的状态)。
61 |
62 | **Stat 类:**
63 |
64 | 
65 |
66 | 关于数据节点的状态信息说明(也就是对Stat 类中的各字段进行说明),可以参考下图(图源:《从Paxos到Zookeeper 分布式一致性原理与实践》)。
67 |
68 | 
69 |
70 | ### 测试 ZooKeeper 中的常见操作
71 |
72 |
73 | #### 连接 ZooKeeper 服务
74 |
75 | 进入安装 ZooKeeper文件夹的 bin 目录下执行下面的命令连接 ZooKeeper 服务(Linux环境下)(连接之前首选要确定你的 ZooKeeper 服务已经启动成功)。
76 |
77 | ```shell
78 | ./zkCli.sh -server 127.0.0.1:2181
79 | ```
80 | 
81 |
82 | 从上图可以看出控制台打印出了很多信息,包括我们的主机名称、JDK 版本、操作系统等等。如果你成功看到这些信息,说明你成功连接到 ZooKeeper 服务。
83 |
84 | #### 查看常用命令(help 命令)
85 |
86 | help 命令查看 zookeeper 常用命令
87 |
88 | 
89 |
90 | #### 创建节点(create 命令)
91 |
92 | 通过 create 命令在根目录创建了node1节点,与它关联的字符串是"node1"
93 |
94 | ```shell
95 | [zk: 127.0.0.1:2181(CONNECTED) 34] create /node1 “node1”
96 | ```
97 | 通过 create 命令在根目录创建了node1节点,与它关联的内容是数字 123
98 |
99 | ```shell
100 | [zk: 127.0.0.1:2181(CONNECTED) 1] create /node1/node1.1 123
101 | Created /node1/node1.1
102 | ```
103 |
104 | #### 更新节点数据内容(set 命令)
105 |
106 | ```shell
107 | [zk: 127.0.0.1:2181(CONNECTED) 11] set /node1 "set node1"
108 | ```
109 |
110 | #### 获取节点的数据(get 命令)
111 |
112 | get 命令可以获取指定节点的数据内容和节点的状态,可以看出我们通过set 命令已经将节点数据内容改为 "set node1"。
113 |
114 | ```shell
115 | set node1
116 | cZxid = 0x47
117 | ctime = Sun Jan 20 10:22:59 CST 2019
118 | mZxid = 0x4b
119 | mtime = Sun Jan 20 10:41:10 CST 2019
120 | pZxid = 0x4a
121 | cversion = 1
122 | dataVersion = 1
123 | aclVersion = 0
124 | ephemeralOwner = 0x0
125 | dataLength = 9
126 | numChildren = 1
127 |
128 | ```
129 |
130 | #### 查看某个目录下的子节点(ls 命令)
131 |
132 | 通过 ls 命令查看根目录下的节点
133 |
134 | ```shell
135 | [zk: 127.0.0.1:2181(CONNECTED) 37] ls /
136 | [dubbo, zookeeper, node1]
137 | ```
138 | 通过 ls 命令查看 node1 目录下的节点
139 |
140 | ```shell
141 | [zk: 127.0.0.1:2181(CONNECTED) 5] ls /node1
142 | [node1.1]
143 | ```
144 | zookeeper 中的 ls 命令和 linux 命令中的 ls 类似, 这个命令将列出绝对路径path下的所有子节点信息(列出1级,并不递归)
145 |
146 | #### 查看节点状态(stat 命令)
147 |
148 | 通过 stat 命令查看节点状态
149 |
150 | ```shell
151 | [zk: 127.0.0.1:2181(CONNECTED) 10] stat /node1
152 | cZxid = 0x47
153 | ctime = Sun Jan 20 10:22:59 CST 2019
154 | mZxid = 0x47
155 | mtime = Sun Jan 20 10:22:59 CST 2019
156 | pZxid = 0x4a
157 | cversion = 1
158 | dataVersion = 0
159 | aclVersion = 0
160 | ephemeralOwner = 0x0
161 | dataLength = 11
162 | numChildren = 1
163 | ```
164 | 上面显示的一些信息比如cversion、aclVersion、numChildren等等,我在上面 “ZNode(数据节点)的结构” 这部分已经介绍到。
165 |
166 | #### 查看节点信息和状态(ls2 命令)
167 |
168 |
169 | ls2 命令更像是 ls 命令和 stat 命令的结合。ls2 命令返回的信息包括2部分:子节点列表 + 当前节点的stat信息。
170 |
171 | ```shell
172 | [zk: 127.0.0.1:2181(CONNECTED) 7] ls2 /node1
173 | [node1.1]
174 | cZxid = 0x47
175 | ctime = Sun Jan 20 10:22:59 CST 2019
176 | mZxid = 0x47
177 | mtime = Sun Jan 20 10:22:59 CST 2019
178 | pZxid = 0x4a
179 | cversion = 1
180 | dataVersion = 0
181 | aclVersion = 0
182 | ephemeralOwner = 0x0
183 | dataLength = 11
184 | numChildren = 1
185 |
186 | ```
187 |
188 | #### 删除节点(delete 命令)
189 |
190 | 这个命令很简单,但是需要注意的一点是如果你要删除某一个节点,那么这个节点必须无子节点才行。
191 |
192 | ```shell
193 | [zk: 127.0.0.1:2181(CONNECTED) 3] delete /node1/node1.1
194 | ```
195 |
196 | 在后面我会介绍到 Java 客户端 API的使用以及开源 Zookeeper 客户端 ZkClient 和 Curator 的使用。
197 |
198 |
199 | ### 参考
200 |
201 | - 《从Paxos到Zookeeper 分布式一致性原理与实践》
202 |
203 |
--------------------------------------------------------------------------------
/数据存储/MySQL Index.md:
--------------------------------------------------------------------------------
1 |
2 | # 思维导图-索引篇
3 |
4 | > 系列思维导图源文件(数据库+架构)以及思维导图制作软件—XMind8 破解安装,公众号后台回复:**“思维导图”** 免费领取!(下面的图片不是很清楚,原图非常清晰,另外提供给大家源文件也是为了大家根据自己需要进行修改)
5 |
6 | 
7 |
8 | > **下面是我补充的一些内容**
9 |
10 | # 为什么索引能提高查询速度
11 |
12 | > 以下内容整理自:
13 | > 地址: https://juejin.im/post/5b55b842f265da0f9e589e79
14 | > 作者 :Java3y
15 |
16 | ### 先从 MySQL 的基本存储结构说起
17 |
18 | MySQL的基本存储结构是页(记录都存在页里边):
19 |
20 | 
21 |
22 | 
23 |
24 | - **各个数据页可以组成一个双向链表**
25 | - **每个数据页中的记录又可以组成一个单向链表**
26 | - 每个数据页都会为存储在它里边儿的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录
27 | - 以其他列(非主键)作为搜索条件:只能从最小记录开始依次遍历单链表中的每条记录。
28 |
29 | 所以说,如果我们写select * from user where indexname = 'xxx'这样没有进行任何优化的sql语句,默认会这样做:
30 |
31 | 1. **定位到记录所在的页:需要遍历双向链表,找到所在的页**
32 | 2. **从所在的页内中查找相应的记录:由于不是根据主键查询,只能遍历所在页的单链表了**
33 |
34 | 很明显,在数据量很大的情况下这样查找会很慢!这样的时间复杂度为O(n)。
35 |
36 |
37 | ### 使用索引之后
38 |
39 | 索引做了些什么可以让我们查询加快速度呢?其实就是将无序的数据变成有序(相对):
40 |
41 | 
42 |
43 | 要找到id为8的记录简要步骤:
44 |
45 | 
46 |
47 | 很明显的是:没有用索引我们是需要遍历双向链表来定位对应的页,现在通过 **“目录”** 就可以很快地定位到对应的页上了!(二分查找,时间复杂度近似为O(logn))
48 |
49 | 其实底层结构就是B+树,B+树作为树的一种实现,能够让我们很快地查找出对应的记录。
50 |
51 | # 关于索引其他重要的内容补充
52 |
53 | > 以下内容整理自:《Java工程师修炼之道》
54 |
55 |
56 | ### 最左前缀原则
57 |
58 | MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。如User表的name和city加联合索引就是(name,city)o而最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如下:
59 |
60 | ```
61 | select * from user where name=xx and city=xx ; //可以命中索引
62 | select * from user where name=xx ; // 可以命中索引
63 | select * from user where city=xx; // 无法命中索引
64 | ```
65 | 这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 `city= xx and name =xx`,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的.
66 |
67 | 由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDERBY子句也遵循此规则。
68 |
69 | ### 注意避免冗余索引
70 |
71 | 冗余索引指的是索引的功能相同,能够命中 就肯定能命中 ,那么 就是冗余索引如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的 在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。
72 |
73 | MySQLS.7 版本后,可以通过查询 sys 库的 `schemal_r dundant_indexes` 表来查看冗余索引
74 |
75 | ### Mysql如何为表字段添加索引???
76 |
77 | 1.添加PRIMARY KEY(主键索引)
78 |
79 | ```
80 | ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )
81 | ```
82 | 2.添加UNIQUE(唯一索引)
83 |
84 | ```
85 | ALTER TABLE `table_name` ADD UNIQUE ( `column` )
86 | ```
87 |
88 | 3.添加INDEX(普通索引)
89 |
90 | ```
91 | ALTER TABLE `table_name` ADD INDEX index_name ( `column` )
92 | ```
93 |
94 | 4.添加FULLTEXT(全文索引)
95 |
96 | ```
97 | ALTER TABLE `table_name` ADD FULLTEXT ( `column`)
98 | ```
99 |
100 | 5.添加多列索引
101 |
102 | ```
103 | ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )
104 | ```
105 |
106 |
107 | # 参考
108 |
109 | - 《Java工程师修炼之道》
110 | - 《MySQL高性能书籍_第3版》
111 | - https://juejin.im/post/5b55b842f265da0f9e589e79
112 |
113 |
--------------------------------------------------------------------------------
/数据存储/MySQL.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):[https://github.com/Snailclimb/Java_Guide](https://github.com/Snailclimb/Java_Guide)
4 |
5 | > ## 书籍推荐
6 |
7 | **《高性能MySQL : 第3版》**
8 |
9 | > ## 文字教程推荐
10 |
11 | [MySQL 教程(菜鸟教程)](http://www.runoob.com/mysql/mysql-tutorial.html)
12 |
13 | [MySQL教程(易百教程)](https://www.yiibai.com/mysql/)
14 |
15 | > ## 视频教程推荐
16 |
17 |
18 | **基础入门:** [与MySQL的零距离接触-慕课网](https://www.imooc.com/learn/122)
19 |
20 | **Mysql开发技巧:** [MySQL开发技巧(一)](https://www.imooc.com/learn/398) [MySQL开发技巧(二)](https://www.imooc.com/learn/427) [MySQL开发技巧(三)](https://www.imooc.com/learn/449)
21 |
22 | **Mysql5.7新特性及相关优化技巧:** [MySQL5.7版本新特性](https://www.imooc.com/learn/533) [性能优化之MySQL优化](https://www.imooc.com/learn/194)
23 |
24 | [MySQL集群(PXC)入门](https://www.imooc.com/learn/993) [MyCAT入门及应用](https://www.imooc.com/learn/951)
25 |
26 |
27 |
28 | > ## 常见问题总结
29 |
30 | - ### ①存储引擎
31 |
32 | [MySQL常见的两种存储引擎:MyISAM与InnoDB的爱恨情仇](https://juejin.im/post/5b1685bef265da6e5c3c1c34)
33 |
34 | - ### ②字符集及校对规则
35 |
36 | 字符集指的是一种从二进制编码到某类字符符号的映射。校对规则则是指某种字符集下的排序规则。Mysql中每一种字符集都会对应一系列的校对规则。
37 |
38 | Mysql采用的是类似继承的方式指定字符集的默认值,每个数据库以及每张数据表都有自己的默认值,他们逐层继承。比如:某个库中所有表的默认字符集将是该数据库所指定的字符集(这些表在没有指定字符集的情况下,才会采用默认字符集) PS:整理自《Java工程师修炼之道》
39 |
40 | 详细内容可以参考: [MySQL字符集及校对规则的理解](https://www.cnblogs.com/geaozhang/p/6724393.html#mysqlyuzifuji)
41 |
42 | - ### ③索引相关的内容(数据库使用中非常关键的技术,合理正确的使用索引可以大大提高数据库的查询性能)
43 |
44 | Mysql索引使用的数据结构主要有**BTree索引** 和 **哈希索引** 。对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
45 |
46 | Mysql的BTree索引使用的是B数中的B+Tree,但对于主要的两种存储引擎的实现方式是不同的。
47 |
48 | **MyISAM:** B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
49 |
50 | **InnoDB:** 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。**在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。** **因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。** PS:整理自《Java工程师修炼之道》
51 |
52 | 详细内容可以参考:
53 |
54 | [干货:mysql索引的数据结构](https://www.jianshu.com/p/1775b4ff123a)
55 |
56 | [MySQL优化系列(三)--索引的使用、原理和设计优化](https://blog.csdn.net/Jack__Frost/article/details/72571540)
57 |
58 | [数据库两大神器【索引和锁】](https://juejin.im/post/5b55b842f265da0f9e589e79#comment)
59 |
60 | - ### ④查询缓存的使用
61 |
62 | my.cnf加入以下配置,重启Mysql开启查询缓存
63 | ```
64 | query_cache_type=1
65 | query_cache_size=600000
66 | ```
67 |
68 | Mysql执行以下命令也可以开启查询缓存
69 |
70 | ```
71 | set global query_cache_type=1;
72 | set global query_cache_size=600000;
73 | ```
74 | 如上,**开启查询缓存后在同样的查询条件以及数据情况下,会直接在缓存中返回结果**。这里的查询条件包括查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的信息。因此任何两个查询在任何字符上的不同都会导致缓存不命中。此外,如果查询中包含任何用户自定义函数、存储函数、用户变量、临时表、Mysql库中的系统表,其查询结果也不会被缓存。
75 |
76 | 缓存建立之后,Mysql的查询缓存系统会跟踪查询中涉及的每张表,如果这些表(数据或结构)发生变化,那么和这张表相关的所有缓存数据都将失效。
77 |
78 | **缓存虽然能够提升数据库的查询性能,但是缓存同时也带来了额外的开销,每次查询后都要做一次缓存操作,失效后还要销毁。** 因此,开启缓存查询要谨慎,尤其对于写密集的应用来说更是如此。如果开启,要注意合理控制缓存空间大小,一般来说其大小设置为几十MB比较合适。此外,**还可以通过sql_cache和sql_no_cache来控制某个查询语句是否需要缓存:**
79 | ```
80 | select sql_no_cache count(*) from usr;
81 | ```
82 |
83 | - ### ⑤事务机制
84 |
85 | **关系性数据库需要遵循ACID规则,具体内容如下:**
86 |
87 | 
88 |
89 | 1. **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
90 | 2. **一致性:** 执行事务前后,数据库从一个一致性状态转换到另一个一致性状态。
91 | 3. **隔离性:** 并发访问数据库时,一个用户的事物不被其他事务所干扰,各并发事务之间数据库是独立的;
92 | 4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库 发生故障也不应该对其有任何影响。
93 |
94 | **为了达到上述事务特性,数据库定义了几种不同的事务隔离级别:**
95 |
96 | - **READ_UNCOMMITTED(未提交读):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**
97 | - **READ_COMMITTED(提交读):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**
98 | - **REPEATABLE_READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生。**
99 | - **SERIALIZABLE(串行):** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
100 |
101 | 这里需要注意的是:**Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.**
102 |
103 | 事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVCC(多版本并发控制),通过行的创建时间和行的过期时间来支持并发一致性读和回滚等特性。
104 |
105 | 详细内容可以参考: [可能是最漂亮的Spring事务管理详解](https://blog.csdn.net/qq_34337272/article/details/80394121)
106 |
107 | - ### ⑥锁机制与InnoDB锁算法
108 | **MyISAM和InnoDB存储引擎使用的锁:**
109 |
110 | - MyISAM采用表级锁(table-level locking)。
111 | - InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
112 |
113 | **表级锁和行级锁对比:**
114 |
115 | - **表级锁:** Mysql中锁定 **粒度最大** 的一种锁,对当前操作的整张表加锁,实现简单,资源消耗也比较少,加锁快,不会出现死锁。其锁定粒度最大,触发锁冲突的概率最高,并发度最低,MyISAM和 InnoDB引擎都支持表级锁。
116 | - **行级锁:** Mysql中锁定 **粒度最小** 的一种锁,只针对当前操作的行进行加锁。 行级锁能大大减少数据库操作的冲突。其加锁粒度最小,并发度高,但加锁的开销也最大,加锁慢,会出现死锁。
117 |
118 | 详细内容可以参考:
119 | [Mysql锁机制简单了解一下](https://blog.csdn.net/qq_34337272/article/details/80611486)
120 |
121 | **InnoDB存储引擎的锁的算法有三种:**
122 | - Record lock:单个行记录上的锁
123 | - Gap lock:间隙锁,锁定一个范围,不包括记录本身
124 | - Next-key lock:record+gap 锁定一个范围,包含记录本身
125 |
126 | **相关知识点:**
127 | 1. innodb对于行的查询使用next-key lock
128 | 2. Next-locking keying为了解决Phantom Problem幻读问题
129 | 3. 当查询的索引含有唯一属性时,将next-key lock降级为record key
130 | 4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生
131 | 5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1
132 |
133 | - ### ⑦大表优化
134 |
135 | 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
136 |
137 | 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
138 | 2. **读/写分离:** 经典的数据库拆分方案,主库负责写,从库负责读;
139 | 3 . **垂直分区:**
140 |
141 | **根据数据库里面数据表的相关性进行拆分。** 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
142 |
143 | **简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。
144 | 
145 |
146 | **垂直拆分的优点:** 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
147 |
148 | **垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
149 |
150 | 4. **水平分区:**
151 |
152 |
153 | **保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。**
154 |
155 | 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。
156 |
157 | 
158 |
159 | 水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水平拆分最好分库** 。
160 |
161 | 水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨界点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
162 |
163 | **下面补充一下数据库分片的两种常见方案:**
164 | - **客户端代理:** **分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。** 当当网的 **Sharding-JDBC** 、阿里的TDDL是两种比较常用的实现。
165 | - **中间件代理:** **在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。** 我们现在谈的 **Mycat** 、360的Atlas、网易的DDB等等都是这种架构的实现。
166 |
167 |
168 | 详细内容可以参考:
169 | [MySQL大表优化方案](https://segmentfault.com/a/1190000006158186)
170 |
171 |
172 |
--------------------------------------------------------------------------------
/数据存储/Redis/Redis持久化.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | 非常感谢《redis实战》真本书,本文大多内容也参考了书中的内容。非常推荐大家看一下《redis实战》这本书,感觉书中的很多理论性东西还是很不错的。
4 |
5 | 为什么本文的名字要加上春夏秋冬又一春,哈哈 ,这是一部韩国的电影,我感觉电影不错,所以就用在文章名字上了,没有什么特别的含义,然后下面的有些配图也是电影相关镜头。
6 |
7 | 
8 |
9 | **很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后回复数据),或者是为了防止系统故障而将数据备份到一个远程位置。**
10 |
11 | Redis不同于Memcached的很重一点就是,**Redis支持持久化**,而且支持两种不同的持久化操作。Redis的一种持久化方式叫**快照(snapshotting,RDB)**,另一种方式是**只追加文件(append-only file,AOF)**.这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法。
12 |
13 |
14 | ## 快照(snapshotting)持久化
15 |
16 | Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。
17 |
18 |
19 | 
20 |
21 | **快照持久化是Redis默认采用的持久化方式**,在redis.conf配置文件中默认有此下配置:
22 | ```
23 |
24 | save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
25 |
26 | save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
27 |
28 | save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
29 | ```
30 |
31 | 根据配置,快照将被写入dbfilename选项指定的文件里面,并存储在dir选项指定的路径上面。如果在新的快照文件创建完毕之前,Redis、系统或者硬件这三者中的任意一个崩溃了,那么Redis将丢失最近一次创建快照写入的所有数据。
32 |
33 | 举个例子:假设Redis的上一个快照是2:35开始创建的,并且已经创建成功。下午3:06时,Redis又开始创建新的快照,并且在下午3:08快照创建完毕之前,有35个键进行了更新。如果在下午3:06到3:08期间,系统发生了崩溃,导致Redis无法完成新快照的创建工作,那么Redis将丢失下午2:35之后写入的所有数据。另一方面,如果系统恰好在新的快照文件创建完毕之后崩溃,那么Redis将丢失35个键的更新数据。
34 |
35 | **创建快照的办法有如下几种:**
36 |
37 | - **BGSAVE命令:** 客户端向Redis发送 **BGSAVE命令** 来创建一个快照。对于支持BGSAVE命令的平台来说(基本上所有平台支持,除了Windows平台),Redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求。
38 | - **SAVE命令:** 客户端还可以向Redis发送 **SAVE命令** 来创建一个快照,接到SAVE命令的Redis服务器在快照创建完毕之前不会再响应任何其他命令。SAVE命令不常用,我们通常只会在没有足够内存去执行BGSAVE命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
39 | - **save选项:** 如果用户设置了save选项(一般会默认设置),比如 **save 60 10000**,那么从Redis最近一次创建快照之后开始算起,当“60秒之内有10000次写入”这个条件被满足时,Redis就会自动触发BGSAVE命令。
40 | - **SHUTDOWN命令:** 当Redis通过SHUTDOWN命令接收到关闭服务器的请求时,或者接收到标准TERM信号时,会执行一个SAVE命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在SAVE命令执行完毕之后关闭服务器。
41 | - **一个Redis服务器连接到另一个Redis服务器:** 当一个Redis服务器连接到另一个Redis服务器,并向对方发送SYNC命令来开始一次复制操作的时候,如果主服务器目前没有执行BGSAVE操作,或者主服务器并非刚刚执行完BGSAVE操作,那么主服务器就会执行BGSAVE命令
42 |
43 | 如果系统真的发生崩溃,用户将丢失最近一次生成快照之后更改的所有数据。因此,快照持久化只适用于即使丢失一部分数据也不会造成一些大问题的应用程序。不能接受这个缺点的话,可以考虑AOF持久化。
44 |
45 |
46 |
47 | ## **AOF(append-only file)持久化**
48 | 与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
49 | ```
50 | appendonly yes
51 | ```
52 |
53 | 开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。
54 |
55 | 
56 |
57 | **在Redis的配置文件中存在三种同步方式,它们分别是:**
58 |
59 | ```
60 |
61 | appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
62 | appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
63 | appendfsync no #让操作系统决定何时进行同步
64 | ```
65 |
66 | **appendfsync always** 可以实现将数据丢失减到最少,不过这种方式需要对硬盘进行大量的写入而且每次只写入一个命令,十分影响Redis的速度。另外使用固态硬盘的用户谨慎使用appendfsync always选项,因为这会明显降低固态硬盘的使用寿命。
67 |
68 | 为了兼顾数据和写入性能,用户可以考虑 **appendfsync everysec选项** ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。
69 |
70 |
71 | **appendfsync no** 选项一般不推荐,这种方案会使Redis丢失不定量的数据而且如果用户的硬盘处理写入操作的速度不够的话,那么当缓冲区被等待写入的数据填满时,Redis的写入操作将被阻塞,这会导致Redis的请求速度变慢。
72 |
73 | **虽然AOF持久化非常灵活地提供了多种不同的选项来满足不同应用程序对数据安全的不同要求,但AOF持久化也有缺陷——AOF文件的体积太大。**
74 |
75 | ## 重写/压缩AOF
76 |
77 | AOF虽然在某个角度可以将数据丢失降低到最小而且对性能影响也很小,但是极端的情况下,体积不断增大的AOF文件很可能会用完硬盘空间。另外,如果AOF体积过大,那么还原操作执行时间就可能会非常长。
78 |
79 | 为了解决AOF体积过大的问题,用户可以向Redis发送 **BGREWRITEAOF命令** ,这个命令会通过移除AOF文件中的冗余命令来重写(rewrite)AOF文件来减小AOF文件的体积。BGREWRITEAOF命令和BGSAVE创建快照原理十分相似,所以AOF文件重写也需要用到子进程,这样会导致性能问题和内存占用问题,和快照持久化一样。更糟糕的是,如果不加以控制的话,AOF文件的体积可能会比快照文件大好几倍。
80 |
81 | **文件重写流程:**
82 |
83 | 
84 | 和快照持久化可以通过设置save选项来自动执行BGSAVE一样,AOF持久化也可以通过设置
85 |
86 | ```
87 | auto-aof-rewrite-percentage
88 | ```
89 |
90 | 选项和
91 |
92 | ```
93 | auto-aof-rewrite-min-size
94 | ```
95 |
96 | 选项自动执行BGREWRITEAOF命令。举例:假设用户对Redis设置了如下配置选项并且启用了AOF持久化。那么当AOF文件体积大于64mb,并且AOF的体积比上一次重写之后的体积大了至少一倍(100%)的时候,Redis将执行BGREWRITEAOF命令。
97 |
98 | ```
99 | auto-aof-rewrite-percentage 100
100 | auto-aof-rewrite-min-size 64mb
101 | ```
102 |
103 | 无论是AOF持久化还是快照持久化,将数据持久化到硬盘上都是非常有必要的,但除了进行持久化外,用户还必须对持久化得到的文件进行备份(最好是备份到不同的地方),这样才能尽量避免数据丢失事故发生。如果条件允许的话,最好能将快照文件和重新重写的AOF文件备份到不同的服务器上面。
104 |
105 | 随着负载量的上升,或者数据的完整性变得 越来越重要时,用户可能需要使用到复制特性。
106 |
107 | ## Redis 4.0 对于持久化机制的优化
108 | Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 `aof-use-rdb-preamble` 开启)。
109 |
110 | 如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分就是压缩格式不再是 AOF 格式,可读性较差。
111 |
112 | 参考:
113 |
114 | 《Redis实战》
115 |
116 | [深入学习Redis(2):持久化](https://www.cnblogs.com/kismetv/p/9137897.html)
117 |
118 |
119 |
--------------------------------------------------------------------------------
/数据存储/Redis/Redlock分布式锁.md:
--------------------------------------------------------------------------------
1 | 这篇文章主要是对 Redis 官方网站刊登的 [Distributed locks with Redis](https://redis.io/topics/distlock) 部分内容的总结和翻译。
2 |
3 | ## 什么是 RedLock
4 |
5 | Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 *Redlock*,此种方式比原先的单节点的方法更安全。它可以保证以下特性:
6 |
7 | 1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁
8 | 2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
9 | 3. 容错性:只要大部分 Redis 节点存活就可以正常提供服务
10 |
11 | ## 怎么在单节点上实现分布式锁
12 |
13 | > SET resource_name my_random_value NX PX 30000
14 |
15 | 主要依靠上述命令,该命令仅当 Key 不存在时(NX保证)set 值,并且设置过期时间 3000ms (PX保证),值 my_random_value 必须是所有 client 和所有锁请求发生期间唯一的,释放锁的逻辑是:
16 |
17 | ```lua
18 | if redis.call("get",KEYS[1]) == ARGV[1] then
19 | return redis.call("del",KEYS[1])
20 | else
21 | return 0
22 | end
23 | ```
24 |
25 | 上述实现可以避免释放另一个client创建的锁,如果只有 del 命令的话,那么如果 client1 拿到 lock1 之后因为某些操作阻塞了很长时间,此时 Redis 端 lock1 已经过期了并且已经被重新分配给了 client2,那么 client1 此时再去释放这把锁就会造成 client2 原本获取到的锁被 client1 无故释放了,但现在为每个 client 分配一个 unique 的 string 值可以避免这个问题。至于如何去生成这个 unique string,方法很多随意选择一种就行了。
26 |
27 | ## Redlock 算法
28 |
29 | 算法很易懂,起 5 个 master 节点,分布在不同的机房尽量保证可用性。为了获得锁,client 会进行如下操作:
30 |
31 | 1. 得到当前的时间,微妙单位
32 | 2. 尝试顺序地在 5 个实例上申请锁,当然需要使用相同的 key 和 random value,这里一个 client 需要合理设置与 master 节点沟通的 timeout 大小,避免长时间和一个 fail 了的节点浪费时间
33 | 3. 当 client 在大于等于 3 个 master 上成功申请到锁的时候,且它会计算申请锁消耗了多少时间,这部分消耗的时间采用获得锁的当下时间减去第一步获得的时间戳得到,如果锁的持续时长(lock validity time)比流逝的时间多的话,那么锁就真正获取到了。
34 | 4. 如果锁申请到了,那么锁真正的 lock validity time 应该是 origin(lock validity time) - 申请锁期间流逝的时间
35 | 5. 如果 client 申请锁失败了,那么它就会在少部分申请成功锁的 master 节点上执行释放锁的操作,重置状态
36 |
37 | ## 失败重试
38 |
39 | 如果一个 client 申请锁失败了,那么它需要稍等一会在重试避免多个 client 同时申请锁的情况,最好的情况是一个 client 需要几乎同时向 5 个 master 发起锁申请。另外就是如果 client 申请锁失败了它需要尽快在它曾经申请到锁的 master 上执行 unlock 操作,便于其他 client 获得这把锁,避免这些锁过期造成的时间浪费,当然如果这时候网络分区使得 client 无法联系上这些 master,那么这种浪费就是不得不付出的代价了。
40 |
41 | ## 放锁
42 |
43 | 放锁操作很简单,就是依次释放所有节点上的锁就行了
44 |
45 | ## 性能、崩溃恢复和 fsync
46 |
47 | 如果我们的节点没有持久化机制,client 从 5 个 master 中的 3 个处获得了锁,然后其中一个重启了,这是注意 **整个环境中又出现了 3 个 master 可供另一个 client 申请同一把锁!** 违反了互斥性。如果我们开启了 AOF 持久化那么情况会稍微好转一些,因为 Redis 的过期机制是语义层面实现的,所以在 server 挂了的时候时间依旧在流逝,重启之后锁状态不会受到污染。但是考虑断电之后呢,AOF部分命令没来得及刷回磁盘直接丢失了,除非我们配置刷回策略为 fsnyc = always,但这会损伤性能。解决这个问题的方法是,当一个节点重启之后,我们规定在 max TTL 期间它是不可用的,这样它就不会干扰原本已经申请到的锁,等到它 crash 前的那部分锁都过期了,环境不存在历史锁了,那么再把这个节点加进来正常工作。
48 |
--------------------------------------------------------------------------------
/数据存储/Redis/如何做可靠的分布式锁,Redlock真的可行么.md:
--------------------------------------------------------------------------------
1 | 本文是对 [Martin Kleppmann](https://martin.kleppmann.com/) 的文章 [How to do distributed locking](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html) 部分内容的翻译和总结,上次写 Redlock 的原因就是看到了 Martin 的这篇文章,写得很好,特此翻译和总结。感兴趣的同学可以翻看原文,相信会收获良多。
2 |
3 | 开篇作者认为现在 Redis 逐渐被使用到数据管理领域,这个领域需要更强的数据一致性和耐久性,这使得他感到担心,因为这不是 Redis 最初设计的初衷(事实上这也是很多业界程序员的误区,越来越把 Redis 当成数据库在使用),其中基于 Redis 的分布式锁就是令人担心的其一。
4 |
5 | Martin 指出首先你要明确你为什么使用分布式锁,为了性能还是正确性?为了帮你区分这二者,在这把锁 fail 了的时候你可以询问自己以下问题:
6 | 1. **要性能的:** 拥有这把锁使得你不会重复劳动(例如一个 job 做了两次),如果这把锁 fail 了,两个节点同时做了这个 Job,那么这个 Job 增加了你的成本。
7 | 2. **要正确性的:** 拥有锁可以防止并发操作污染你的系统或者数据,如果这把锁 fail 了两个节点同时操作了一份数据,结果可能是数据不一致、数据丢失、file 冲突等,会导致严重的后果。
8 |
9 | 上述二者都是需求锁的正确场景,但是你必须清楚自己是因为什么原因需要分布式锁。
10 |
11 | 如果你只是为了性能,那没必要用 Redlock,它成本高且复杂,你只用一个 Redis 实例也够了,最多加个从防止主挂了。当然,你使用单节点的 Redis 那么断电或者一些情况下,你会丢失锁,但是你的目的只是加速性能且断电这种事情不会经常发生,这并不是什么大问题。并且如果你使用了单节点 Redis,那么很显然你这个应用需要的锁粒度是很模糊粗糙的,也不会是什么重要的服务。
12 |
13 | 那么是否 Redlock 对于要求正确性的场景就合适呢?Martin 列举了若干场景证明 Redlock 这种算法是不可靠的。
14 |
15 | ## 用锁保护资源
16 | 这节里 Martin 先将 Redlock 放在了一边而是仅讨论总体上一个分布式锁是怎么工作的。在分布式环境下,锁比 mutex 这类复杂,因为涉及到不同节点、网络通信并且他们随时可能无征兆的 fail 。
17 | Martin 假设了一个场景,一个 client 要修改一个文件,它先申请得到锁,然后修改文件写回,放锁。另一个 client 再申请锁 ... 代码流程如下:
18 |
19 | ```java
20 | // THIS CODE IS BROKEN
21 | function writeData(filename, data) {
22 | var lock = lockService.acquireLock(filename);
23 | if (!lock) {
24 | throw 'Failed to acquire lock';
25 | }
26 |
27 | try {
28 | var file = storage.readFile(filename);
29 | var updated = updateContents(file, data);
30 | storage.writeFile(filename, updated);
31 | } finally {
32 | lock.release();
33 | }
34 | }
35 | ```
36 |
37 | 可惜即使你的锁服务非常完美,上述代码还是可能跪,下面的流程图会告诉你为什么:
38 |
39 | 
40 |
41 | 上述图中,得到锁的 client1 在持有锁的期间 pause 了一段时间,例如 GC 停顿。锁有过期时间(一般叫租约,为了防止某个 client 崩溃之后一直占有锁),但是如果 GC 停顿太长超过了锁租约时间,此时锁已经被另一个 client2 所得到,原先的 client1 还没有感知到锁过期,那么奇怪的结果就会发生,曾经 HBase 就发生过这种 Bug。即使你在 client1 写回之前检查一下锁是否过期也无助于解决这个问题,因为 GC 可能在任何时候发生,即使是你非常不便的时候(在最后的检查与写操作期间)。
42 | 如果你认为自己的程序不会有长时间的 GC 停顿,还有其他原因会导致你的进程 pause。例如进程可能读取尚未进入内存的数据,所以它得到一个 page fault 并且等待 page 被加载进缓存;还有可能你依赖于网络服务;或者其他进程占用 CPU;或者其他人意外发生 SIGSTOP 等。
43 |
44 | ... .... 这里 Martin 又增加了一节列举各种进程 pause 的例子,为了证明上面的代码是不安全的,无论你的锁服务多完美。
45 |
46 | ## 使用 Fencing (栅栏)使得锁变安全
47 | 修复问题的方法也很简单:你需要在每次写操作时加入一个 fencing token。这个场景下,fencing token 可以是一个递增的数字(lock service 可以做到),每次有 client 申请锁就递增一次:
48 |
49 | 
50 |
51 | client1 申请锁同时拿到 token33,然后它进入长时间的停顿锁也过期了。client2 得到锁和 token34 写入数据,紧接着 client1 活过来之后尝试写入数据,自身 token33 比 34 小因此写入操作被拒绝。注意这需要存储层来检查 token,但这并不难实现。如果你使用 Zookeeper 作为 lock service 的话那么你可以使用 zxid 作为递增数字。
52 | 但是对于 Redlock 你要知道,没什么生成 fencing token 的方式,并且怎么修改 Redlock 算法使其能产生 fencing token 呢?好像并不那么显而易见。因为产生 token 需要单调递增,除非在单节点 Redis 上完成但是这又没有高可靠性,你好像需要引进一致性协议来让 Redlock 产生可靠的 fencing token。
53 |
54 | ## 使用时间来解决一致性
55 | Redlock 无法产生 fencing token 早该成为在需求正确性的场景下弃用它的理由,但还有一些值得讨论的地方。
56 |
57 | 学术界有个说法,算法对时间不做假设:因为进程可能pause一段时间、数据包可能因为网络延迟延后到达、时钟可能根本就是错的。而可靠的算法依旧要在上述假设下做正确的事情。
58 |
59 | 对于 failure detector 来说,timeout 只能作为猜测某个节点 fail 的依据,因为网络延迟、本地时钟不正确等其他原因的限制。考虑到 Redis 使用 gettimeofday,而不是单调的时钟,会受到系统时间的影响,可能会突然前进或者后退一段时间,这会导致一个 key 更快或更慢地过期。
60 |
61 | 可见,Redlock 依赖于许多时间假设,它假设所有 Redis 节点都能对同一个 Key 在其过期前持有差不多的时间、跟过期时间相比网络延迟很小、跟过期时间相比进程 pause 很短。
62 |
63 | ## 用不可靠的时间打破 Redlock
64 | 这节 Martin 举了个因为时间问题,Redlock 不可靠的例子。
65 |
66 | 1. client1 从 ABC 三个节点处申请到锁,DE由于网络原因请求没有到达
67 | 2. C节点的时钟往前推了,导致 lock 过期
68 | 3. client2 在CDE处获得了锁,AB由于网络原因请求未到达
69 | 4. 此时 client1 和 client2 都获得了锁
70 |
71 | **在 Redlock 官方文档中也提到了这个情况,不过是C崩溃的时候,Redlock 官方本身也是知道 Redlock 算法不是完全可靠的,官方为了解决这种问题建议使用延时启动,相关内容可以看之前的[这篇文章](https://zhuanlan.zhihu.com/p/40915772)。但是 Martin 这里分析得更加全面,指出延时启动不也是依赖于时钟的正确性的么?**
72 |
73 | 接下来 Martin 又列举了进程 Pause 时而不是时钟不可靠时会发生的问题:
74 |
75 | 1. client1 从 ABCDE 处获得了锁
76 | 2. 当获得锁的 response 还没到达 client1 时 client1 进入 GC 停顿
77 | 3. 停顿期间锁已经过期了
78 | 4. client2 在 ABCDE 处获得了锁
79 | 5. client1 GC 完成收到了获得锁的 response,此时两个 client 又拿到了同一把锁
80 |
81 | **同时长时间的网络延迟也有可能导致同样的问题。**
82 |
83 | ## Redlock 的同步性假设
84 | 这些例子说明了,仅有在你假设了一个同步性系统模型的基础上,Redlock 才能正常工作,也就是系统能满足以下属性:
85 |
86 | 1. 网络延时边界,即假设数据包一定能在某个最大延时之内到达
87 | 2. 进程停顿边界,即进程停顿一定在某个最大时间之内
88 | 3. 时钟错误边界,即不会从一个坏的 NTP 服务器处取得时间
89 |
90 | ## 结论
91 | Martin 认为 Redlock 实在不是一个好的选择,对于需求性能的分布式锁应用它太重了且成本高;对于需求正确性的应用来说它不够安全。因为它对高危的时钟或者说其他上述列举的情况进行了不可靠的假设,如果你的应用只需要高性能的分布式锁不要求多高的正确性,那么单节点 Redis 够了;如果你的应用想要保住正确性,那么不建议 Redlock,建议使用一个合适的一致性协调系统,例如 Zookeeper,且保证存在 fencing token。
92 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.classpath:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
2 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | securityAlgorithm
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.m2e.core.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.jdt.core.javanature
21 | org.eclipse.m2e.core.maven2Nature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/test/java=UTF-8
4 | encoding/=UTF-8
5 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
3 | org.eclipse.jdt.core.compiler.compliance=1.5
4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
5 | org.eclipse.jdt.core.compiler.source=1.5
6 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | com.snailclimb.ks
6 | securityAlgorithm
7 | 0.0.1-SNAPSHOT
8 | jar
9 |
10 | securityAlgorithm
11 | http://maven.apache.org
12 |
13 |
14 | UTF-8
15 |
16 |
17 |
18 |
19 | junit
20 | junit
21 | 4.12
22 | test
23 |
24 |
25 |
26 | commons-codec
27 | commons-codec
28 | 1.8
29 |
30 |
31 | org.bouncycastle
32 | bcprov-jdk15on
33 | 1.56
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/Base64Demo.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.util.Base64;
5 |
6 | public class Base64Demo {
7 |
8 | public static void main(String[] args) throws UnsupportedEncodingException {
9 | // TODO Auto-generated method stub
10 | CommonsCodecDemo();
11 | bouncyCastleDemo();
12 | jdkDemo();
13 | }
14 |
15 | static String str = "你若安好,便是晴天";
16 |
17 | /**
18 | * commons codec实现Base64加密解密
19 | */
20 | public static void CommonsCodecDemo() {
21 | // 加密:
22 | byte[] encodeBytes = org.apache.commons.codec.binary.Base64.encodeBase64(str.getBytes());
23 | System.out.println("commons codec实现base64加密: " + new String(encodeBytes));
24 | // 解密:
25 | byte[] decodeBytes = org.apache.commons.codec.binary.Base64.decodeBase64(encodeBytes);
26 | System.out.println("commons codec实现base64解密: " + new String(decodeBytes));
27 | }
28 |
29 | /**
30 | * bouncy castle实现Base64加密解密
31 | */
32 | public static void bouncyCastleDemo() {
33 | // 加密
34 | byte[] encodeBytes = org.bouncycastle.util.encoders.Base64.encode(str.getBytes());
35 | System.out.println("bouncy castle实现base64加密: " + new String(encodeBytes));
36 | // 解密
37 | byte[] decodeBytes = org.bouncycastle.util.encoders.Base64.decode(encodeBytes);
38 | System.out.println("bouncy castle实现base64解密:" + new String(decodeBytes));
39 | }
40 |
41 | public static void jdkDemo() throws UnsupportedEncodingException {
42 | // 加密
43 | String encodeBytes = Base64.getEncoder().encodeToString(str.getBytes("UTF-8"));
44 | System.out.println("JDK实现的base64加密: " + encodeBytes);
45 | //解密
46 | byte[] decodeBytes = Base64.getDecoder().decode(encodeBytes.getBytes("UTF-8"));
47 | System.out.println("JDK实现的base64解密: "+new String(decodeBytes));
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/DesDemo.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.security.SecureRandom;
5 | import javax.crypto.spec.DESKeySpec;
6 | import javax.crypto.SecretKeyFactory;
7 | import javax.crypto.SecretKey;
8 | import javax.crypto.Cipher;
9 |
10 | /**
11 | * DES加密介绍 DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究,
12 | * 后来被美国政府正式采用,之后开始广泛流传,但是近些年使用越来越少,因为DES使用56位密钥,以现代计算能力,
13 | * 24小时内即可被破解。虽然如此,在某些简单应用中,我们还是可以使用DES加密算法,本文简单讲解DES的JAVA实现 。
14 | * 注意:DES加密和解密过程中,密钥长度都必须是8的倍数
15 | */
16 | public class DesDemo {
17 | public DesDemo() {
18 | }
19 |
20 | // 测试
21 | public static void main(String args[]) {
22 | // 待加密内容
23 | String str = "cryptology";
24 | // 密码,长度要是8的倍数
25 | String password = "95880288";
26 |
27 | byte[] result;
28 | try {
29 | result = DesDemo.encrypt(str.getBytes(), password);
30 | System.out.println("加密后:" + result);
31 | byte[] decryResult = DesDemo.decrypt(result, password);
32 | System.out.println("解密后:" + decryResult);
33 | } catch (UnsupportedEncodingException e2) {
34 | // TODO Auto-generated catch block
35 | e2.printStackTrace();
36 | } catch (Exception e1) {
37 | e1.printStackTrace();
38 | }
39 | }
40 |
41 | // 直接将如上内容解密
42 |
43 | /**
44 | * 加密
45 | *
46 | * @param datasource
47 | * byte[]
48 | * @param password
49 | * String
50 | * @return byte[]
51 | */
52 | public static byte[] encrypt(byte[] datasource, String password) {
53 | try {
54 | SecureRandom random = new SecureRandom();
55 | DESKeySpec desKey = new DESKeySpec(password.getBytes());
56 | // 创建一个密匙工厂,然后用它把DESKeySpec转换成
57 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
58 | SecretKey securekey = keyFactory.generateSecret(desKey);
59 | // Cipher对象实际完成加密操作
60 | Cipher cipher = Cipher.getInstance("DES");
61 | // 用密匙初始化Cipher对象,ENCRYPT_MODE用于将 Cipher 初始化为加密模式的常量
62 | cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
63 | // 现在,获取数据并加密
64 | // 正式执行加密操作
65 | return cipher.doFinal(datasource); // 按单部分操作加密或解密数据,或者结束一个多部分操作
66 | } catch (Throwable e) {
67 | e.printStackTrace();
68 | }
69 | return null;
70 | }
71 |
72 | /**
73 | * 解密
74 | *
75 | * @param src
76 | * byte[]
77 | * @param password
78 | * String
79 | * @return byte[]
80 | * @throws Exception
81 | */
82 | public static byte[] decrypt(byte[] src, String password) throws Exception {
83 | // DES算法要求有一个可信任的随机数源
84 | SecureRandom random = new SecureRandom();
85 | // 创建一个DESKeySpec对象
86 | DESKeySpec desKey = new DESKeySpec(password.getBytes());
87 | // 创建一个密匙工厂
88 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// 返回实现指定转换的
89 | // Cipher
90 | // 对象
91 | // 将DESKeySpec对象转换成SecretKey对象
92 | SecretKey securekey = keyFactory.generateSecret(desKey);
93 | // Cipher对象实际完成解密操作
94 | Cipher cipher = Cipher.getInstance("DES");
95 | // 用密匙初始化Cipher对象
96 | cipher.init(Cipher.DECRYPT_MODE, securekey, random);
97 | // 真正开始解密操作
98 | return cipher.doFinal(src);
99 | }
100 | }
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/IDEADemo.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import java.security.Key;
4 | import java.security.Security;
5 |
6 | import javax.crypto.Cipher;
7 | import javax.crypto.KeyGenerator;
8 | import javax.crypto.SecretKey;
9 | import javax.crypto.spec.SecretKeySpec;
10 |
11 | import org.apache.commons.codec.binary.Base64;
12 | import org.bouncycastle.jce.provider.BouncyCastleProvider;
13 |
14 | public class IDEADemo {
15 | public static void main(String args[]) {
16 | bcIDEA();
17 | }
18 | public static void bcIDEA() {
19 | String src = "www.xttblog.com security idea";
20 | try {
21 | Security.addProvider(new BouncyCastleProvider());
22 |
23 | //生成key
24 | KeyGenerator keyGenerator = KeyGenerator.getInstance("IDEA");
25 | keyGenerator.init(128);
26 | SecretKey secretKey = keyGenerator.generateKey();
27 | byte[] keyBytes = secretKey.getEncoded();
28 |
29 | //转换密钥
30 | Key key = new SecretKeySpec(keyBytes, "IDEA");
31 |
32 | //加密
33 | Cipher cipher = Cipher.getInstance("IDEA/ECB/ISO10126Padding");
34 | cipher.init(Cipher.ENCRYPT_MODE, key);
35 | byte[] result = cipher.doFinal(src.getBytes());
36 | System.out.println("bc idea encrypt : " + Base64.encodeBase64String(result));
37 |
38 | //解密
39 | cipher.init(Cipher.DECRYPT_MODE, key);
40 | result = cipher.doFinal(result);
41 | System.out.println("bc idea decrypt : " + new String(result));
42 | } catch (Exception e) {
43 | e.printStackTrace();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | public class MD5{
4 | /*
5 | *四个链接变量
6 | */
7 | private final int A=0x67452301;
8 | private final int B=0xefcdab89;
9 | private final int C=0x98badcfe;
10 | private final int D=0x10325476;
11 | /*
12 | *ABCD的临时变量
13 | */
14 | private int Atemp,Btemp,Ctemp,Dtemp;
15 |
16 | /*
17 | *常量ti
18 | *公式:floor(abs(sin(i+1))×(2pow32)
19 | */
20 | private final int K[]={
21 | 0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
22 | 0xf57c0faf,0x4787c62a,0xa8304613,0xfd469501,0x698098d8,
23 | 0x8b44f7af,0xffff5bb1,0x895cd7be,0x6b901122,0xfd987193,
24 | 0xa679438e,0x49b40821,0xf61e2562,0xc040b340,0x265e5a51,
25 | 0xe9b6c7aa,0xd62f105d,0x02441453,0xd8a1e681,0xe7d3fbc8,
26 | 0x21e1cde6,0xc33707d6,0xf4d50d87,0x455a14ed,0xa9e3e905,
27 | 0xfcefa3f8,0x676f02d9,0x8d2a4c8a,0xfffa3942,0x8771f681,
28 | 0x6d9d6122,0xfde5380c,0xa4beea44,0x4bdecfa9,0xf6bb4b60,
29 | 0xbebfbc70,0x289b7ec6,0xeaa127fa,0xd4ef3085,0x04881d05,
30 | 0xd9d4d039,0xe6db99e5,0x1fa27cf8,0xc4ac5665,0xf4292244,
31 | 0x432aff97,0xab9423a7,0xfc93a039,0x655b59c3,0x8f0ccc92,
32 | 0xffeff47d,0x85845dd1,0x6fa87e4f,0xfe2ce6e0,0xa3014314,
33 | 0x4e0811a1,0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391};
34 | /*
35 | *向左位移数,计算方法未知
36 | */
37 | private final int s[]={7,12,17,22,7,12,17,22,7,12,17,22,7,
38 | 12,17,22,5,9,14,20,5,9,14,20,5,9,14,20,5,9,14,20,
39 | 4,11,16,23,4,11,16,23,4,11,16,23,4,11,16,23,6,10,
40 | 15,21,6,10,15,21,6,10,15,21,6,10,15,21};
41 |
42 |
43 | /*
44 | *初始化函数
45 | */
46 | private void init(){
47 | Atemp=A;
48 | Btemp=B;
49 | Ctemp=C;
50 | Dtemp=D;
51 | }
52 | /*
53 | *移动一定位数
54 | */
55 | private int shift(int a,int s){
56 | return(a<>>(32-s));//右移的时候,高位一定要补零,而不是补充符号位
57 | }
58 | /*
59 | *主循环
60 | */
61 | private void MainLoop(int M[]){
62 | int F,g;
63 | int a=Atemp;
64 | int b=Btemp;
65 | int c=Ctemp;
66 | int d=Dtemp;
67 | for(int i = 0; i < 64; i ++){
68 | if(i<16){
69 | F=(b&c)|((~b)&d);
70 | g=i;
71 | }else if(i<32){
72 | F=(d&b)|((~d)&c);
73 | g=(5*i+1)%16;
74 | }else if(i<48){
75 | F=b^c^d;
76 | g=(3*i+5)%16;
77 | }else{
78 | F=c^(b|(~d));
79 | g=(7*i)%16;
80 | }
81 | int tmp=d;
82 | d=c;
83 | c=b;
84 | b=b+shift(a+F+K[i]+M[g],s[i]);
85 | a=tmp;
86 | }
87 | Atemp=a+Atemp;
88 | Btemp=b+Btemp;
89 | Ctemp=c+Ctemp;
90 | Dtemp=d+Dtemp;
91 |
92 | }
93 | /*
94 | *填充函数
95 | *处理后应满足bits≡448(mod512),字节就是bytes≡56(mode64)
96 | *填充方式为先加一个0,其它位补零
97 | *最后加上64位的原来长度
98 | */
99 | private int[] add(String str){
100 | int num=((str.length()+8)/64)+1;//以512位,64个字节为一组
101 | int strByte[]=new int[num*16];//64/4=16,所以有16个整数
102 | for(int i=0;i>2]|=str.charAt(i)<<((i%4)*8);//一个整数存储四个字节,小端序
108 | }
109 | strByte[i>>2]|=0x80<<((i%4)*8);//尾部添加1
110 | /*
111 | *添加原长度,长度指位的长度,所以要乘8,然后是小端序,所以放在倒数第二个,这里长度只用了32位
112 | */
113 | strByte[num*16-2]=str.length()*8;
114 | return strByte;
115 | }
116 | /*
117 | *调用函数
118 | */
119 | public String getMD5(String source){
120 | init();
121 | int strByte[]=add(source);
122 | for(int i=0;i>i*8)%(1<<8))&0xff)).replace(' ', '0');
139 |
140 | }
141 | return str;
142 | }
143 | /*
144 | *单例
145 | */
146 | private static MD5 instance;
147 | public static MD5 getInstance(){
148 | if(instance==null){
149 | instance=new MD5();
150 | }
151 | return instance;
152 | }
153 |
154 | private MD5(){};
155 |
156 | public static void main(String[] args){
157 | String str=MD5.getInstance().getMD5("你若安好,便是晴天");
158 | System.out.println(str);
159 | }
160 | }
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/MD5Demo.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import java.security.MessageDigest;
4 |
5 | public class MD5Demo {
6 |
7 | // test
8 | public static void main(String[] args) {
9 | System.out.println(getMD5Code("你若安好,便是晴天"));
10 | }
11 |
12 | private MD5Demo() {
13 | }
14 |
15 | // md5加密
16 | public static String getMD5Code(String message) {
17 | String md5Str = "";
18 | try {
19 | //创建MD5算法消息摘要
20 | MessageDigest md = MessageDigest.getInstance("MD5");
21 | //生成的哈希值的字节数组
22 | byte[] md5Bytes = md.digest(message.getBytes());
23 | md5Str = bytes2Hex(md5Bytes);
24 | }catch(Exception e) {
25 | e.printStackTrace();
26 | }
27 | return md5Str;
28 | }
29 |
30 | // 2进制转16进制
31 | public static String bytes2Hex(byte[] bytes) {
32 | StringBuffer result = new StringBuffer();
33 | int temp;
34 | try {
35 | for (int i = 0; i < bytes.length; i++) {
36 | temp = bytes[i];
37 | if(temp < 0) {
38 | temp += 256;
39 | }
40 | if (temp < 16) {
41 | result.append("0");
42 | }
43 | result.append(Integer.toHexString(temp));
44 | }
45 | } catch (Exception e) {
46 | e.printStackTrace();
47 | }
48 | return result.toString();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/SHA1Demo.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.security.MessageDigest;
5 | import java.security.NoSuchAlgorithmException;
6 |
7 | public class SHA1Demo {
8 |
9 | public static void main(String[] args) {
10 | // TODO Auto-generated method stub
11 | System.out.println(getSha1("你若安好,便是晴天"));
12 |
13 | }
14 |
15 | public static String getSha1(String str) {
16 | if (null == str || 0 == str.length()) {
17 | return null;
18 | }
19 | char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
20 | try {
21 | //创建SHA1算法消息摘要对象
22 | MessageDigest mdTemp = MessageDigest.getInstance("SHA1");
23 | //使用指定的字节数组更新摘要。
24 | mdTemp.update(str.getBytes("UTF-8"));
25 | //生成的哈希值的字节数组
26 | byte[] md = mdTemp.digest();
27 | //SHA1算法生成信息摘要关键过程
28 | int j = md.length;
29 | char[] buf = new char[j * 2];
30 | int k = 0;
31 | for (int i = 0; i < j; i++) {
32 | byte byte0 = md[i];
33 | buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
34 | buf[k++] = hexDigits[byte0 & 0xf];
35 | }
36 | return new String(buf);
37 | } catch (NoSuchAlgorithmException e) {
38 | e.printStackTrace();
39 | } catch (UnsupportedEncodingException e) {
40 | e.printStackTrace();
41 | }
42 | return "0";
43 |
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/main/java/com/snailclimb/ks/securityAlgorithm/readme:
--------------------------------------------------------------------------------
1 | Des算法参考:http://blog.csdn.net/super_cui/article/details/70820983
2 | IDEA算法参考:https://www.xttblog.com/?p=1121
3 | RSA算法实现参考:https://www.cnblogs.com/xlhan/p/7120488.html
--------------------------------------------------------------------------------
/数据结构与算法/source code/securityAlgorithm/src/test/java/com/snailclimb/ks/securityAlgorithm/AppTest.java:
--------------------------------------------------------------------------------
1 | package com.snailclimb.ks.securityAlgorithm;
2 |
3 | import junit.framework.Test;
4 | import junit.framework.TestCase;
5 | import junit.framework.TestSuite;
6 |
7 | /**
8 | * Unit test for simple App.
9 | */
10 | public class AppTest
11 | extends TestCase
12 | {
13 | /**
14 | * Create the test case
15 | *
16 | * @param testName name of the test case
17 | */
18 | public AppTest( String testName )
19 | {
20 | super( testName );
21 | }
22 |
23 | /**
24 | * @return the suite of tests being tested
25 | */
26 | public static Test suite()
27 | {
28 | return new TestSuite( AppTest.class );
29 | }
30 |
31 | /**
32 | * Rigourous Test :-)
33 | */
34 | public void testApp()
35 | {
36 | assertTrue( true );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/数据结构与算法/数据结构.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | - [Queue](#queue)
4 | - [什么是队列](#什么是队列)
5 | - [队列的种类](#队列的种类)
6 | - [Java 集合框架中的队列 Queue](#java-集合框架中的队列-queue)
7 | - [推荐文章](#推荐文章)
8 | - [Set](#set)
9 | - [什么是 Set](#什么是-set)
10 | - [补充:有序集合与无序集合说明](#补充:有序集合与无序集合说明)
11 | - [HashSet 和 TreeSet 底层数据结构](#hashset-和-treeset-底层数据结构)
12 | - [推荐文章](#推荐文章-1)
13 | - [List](#list)
14 | - [什么是List](#什么是list)
15 | - [List的常见实现类](#list的常见实现类)
16 | - [ArrayList 和 LinkedList 源码学习](#arraylist-和-linkedlist-源码学习)
17 | - [推荐阅读](#推荐阅读)
18 | - [Map](#map)
19 | - [树](#树)
20 |
21 |
22 |
23 |
24 | ## Queue
25 |
26 | ### 什么是队列
27 | 队列是数据结构中比较重要的一种类型,它支持 FIFO,尾部添加、头部删除(先进队列的元素先出队列),跟我们生活中的排队类似。
28 |
29 | ### 队列的种类
30 |
31 | - **单队列**(单队列就是常见的队列, 每次添加元素时,都是添加到队尾,存在“假溢出”的问题也就是明明有位置却不能添加的情况)
32 | - **循环队列**(避免了“假溢出”的问题)
33 |
34 | ### Java 集合框架中的队列 Queue
35 |
36 | Java 集合中的 Queue 继承自 Collection 接口 ,Deque, LinkedList, PriorityQueue, BlockingQueue 等类都实现了它。
37 | Queue 用来存放 等待处理元素 的集合,这种场景一般用于缓冲、并发访问。
38 | 除了继承 Collection 接口的一些方法,Queue 还添加了额外的 添加、删除、查询操作。
39 |
40 | ### 推荐文章
41 |
42 | - [Java 集合深入理解(9):Queue 队列](https://blog.csdn.net/u011240877/article/details/52860924)
43 |
44 | ## Set
45 |
46 | ### 什么是 Set
47 | Set 继承于 Collection 接口,是一个不允许出现重复元素,并且无序的集合,主要 HashSet 和 TreeSet 两大实现类。
48 |
49 | 在判断重复元素的时候,Set 集合会调用 hashCode()和 equal()方法来实现。
50 |
51 | ### 补充:有序集合与无序集合说明
52 | - 有序集合:集合里的元素可以根据 key 或 index 访问 (List、Map)
53 | - 无序集合:集合里的元素只能遍历。(Set)
54 |
55 |
56 | ### HashSet 和 TreeSet 底层数据结构
57 |
58 | **HashSet** 是哈希表结构,主要利用 HashMap 的 key 来存储元素,计算插入元素的 hashCode 来获取元素在集合中的位置;
59 |
60 | **TreeSet** 是红黑树结构,每一个元素都是树中的一个节点,插入的元素都会进行排序;
61 |
62 |
63 | ### 推荐文章
64 |
65 | - [Java集合--Set(基础)](https://www.jianshu.com/p/b48c47a42916)
66 |
67 | ## List
68 |
69 | ### 什么是List
70 |
71 | 在 List 中,用户可以精确控制列表中每个元素的插入位置,另外用户可以通过整数索引(列表中的位置)访问元素,并搜索列表中的元素。 与 Set 不同,List 通常允许重复的元素。 另外 List 是有序集合而 Set 是无序集合。
72 |
73 | ### List的常见实现类
74 |
75 | **ArrayList** 是一个数组队列,相当于动态数组。它由数组实现,随机访问效率高,随机插入、随机删除效率低。
76 |
77 | **LinkedList** 是一个双向链表。它也可以被当作堆栈、队列或双端队列进行操作。LinkedList随机访问效率低,但随机插入、随机删除效率高。
78 |
79 | **Vector** 是矢量队列,和ArrayList一样,它也是一个动态数组,由数组实现。但是ArrayList是非线程安全的,而Vector是线程安全的。
80 |
81 | **Stack** 是栈,它继承于Vector。它的特性是:先进后出(FILO, First In Last Out)。相关阅读:[java数据结构与算法之栈(Stack)设计与实现](https://blog.csdn.net/javazejian/article/details/53362993)
82 |
83 | ### ArrayList 和 LinkedList 源码学习
84 | - [ArrayList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/ArrayList.md)
85 | - [LinkedList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/LinkedList.md)
86 |
87 | ### 推荐阅读
88 |
89 | - [java 数据结构与算法之顺序表与链表深入分析](https://blog.csdn.net/javazejian/article/details/52953190)
90 |
91 |
92 | ## Map
93 |
94 |
95 | - [集合框架源码学习之 HashMap(JDK1.8)](https://juejin.im/post/5ab0568b5188255580020e56)
96 | - [ConcurrentHashMap 实现原理及源码分析](https://link.juejin.im/?target=http%3A%2F%2Fwww.cnblogs.com%2Fchengxiao%2Fp%2F6842045.html)
97 |
98 | ## 树
99 | * ### 1 二叉树
100 |
101 | [二叉树](https://baike.baidu.com/item/%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科)
102 |
103 | (1)[完全二叉树](https://baike.baidu.com/item/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91)——若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。
104 |
105 | (2)[满二叉树](https://baike.baidu.com/item/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91)——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。
106 |
107 | (3)[平衡二叉树](https://baike.baidu.com/item/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91/10421057)——平衡二叉树又被称为AVL树(区别于AVL算法),它是一棵二叉排序树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
108 |
109 | * ### 2 完全二叉树
110 |
111 | [完全二叉树](https://baike.baidu.com/item/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科)
112 |
113 | 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
114 | * ### 3 满二叉树
115 |
116 | [满二叉树](https://baike.baidu.com/item/%E6%BB%A1%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科,国内外的定义不同)
117 |
118 | 国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
119 | * ### 堆
120 |
121 | [数据结构之堆的定义](https://blog.csdn.net/qq_33186366/article/details/51876191)
122 |
123 | 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
124 | * ### 4 二叉查找树(BST)
125 |
126 | [浅谈算法和数据结构: 七 二叉查找树](http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html)
127 |
128 | 二叉查找树的特点:
129 |
130 | 1. 若任意节点的左子树不空,则左子树上所有结点的 值均小于它的根结点的值;
131 | 2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
132 | 3. 任意节点的左、右子树也分别为二叉查找树。
133 | 4. 没有键值相等的节点(no duplicate nodes)。
134 |
135 | * ### 5 平衡二叉树(Self-balancing binary search tree)
136 |
137 | [ 平衡二叉树](https://baike.baidu.com/item/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科,平衡二叉树的常用实现方法有红黑树、AVL、替罪羊树、Treap、伸展树等)
138 | * ### 6 红黑树
139 |
140 | - 红黑树特点:
141 | 1. 每个节点非红即黑;
142 | 2. 根节点总是黑色的;
143 | 3. 每个叶子节点都是黑色的空节点(NIL节点);
144 | 4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
145 | 5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)
146 |
147 | - 红黑树的应用:
148 |
149 | TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。
150 |
151 | - 为什么要用红黑树
152 |
153 | 简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。详细了解可以查看 [漫画:什么是红黑树?](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
154 |
155 | - 推荐文章:
156 | - [漫画:什么是红黑树?](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
157 | - [寻找红黑树的操作手册](http://dandanlove.com/2018/03/18/red-black-tree/)(文章排版以及思路真的不错)
158 | - [红黑树深入剖析及Java实现](https://zhuanlan.zhihu.com/p/24367771)(美团点评技术团队)
159 | * ### 7 B-,B+,B*树
160 |
161 | [二叉树学习笔记之B树、B+树、B*树 ](https://yq.aliyun.com/articles/38345)
162 |
163 | [《B-树,B+树,B*树详解》](https://blog.csdn.net/aqzwss/article/details/53074186)
164 |
165 | [《B-树,B+树与B*树的优缺点比较》](https://blog.csdn.net/bigtree_3721/article/details/73632405)
166 |
167 | B-树(或B树)是一种平衡的多路查找(又称排序)树,在文件系统中有所应用。主要用作文件的索引。其中的B就表示平衡(Balance)
168 | 1. B+ 树的叶子节点链表结构相比于 B- 树便于扫库,和范围检索。
169 | 2. B+树支持range-query(区间查询)非常方便,而B树不支持。这是数据库选用B+树的最主要原因。
170 | 3. B\*树 是B+树的变体,B\*树分配新结点的概率比B+树要低,空间使用率更高;
171 | * ### 8 LSM 树
172 |
173 | [[HBase] LSM树 VS B+树](https://blog.csdn.net/dbanote/article/details/8897599)
174 |
175 | B+树最大的性能问题是会产生大量的随机IO
176 |
177 | 为了克服B+树的弱点,HBase引入了LSM树的概念,即Log-Structured Merge-Trees。
178 |
179 | [LSM树由来、设计思想以及应用到HBase的索引](http://www.cnblogs.com/yanghuahui/p/3483754.html)
180 |
181 |
182 | ## 图
183 |
184 |
185 |
186 |
187 | ## BFS及DFS
188 |
189 | - [《使用BFS及DFS遍历树和图的思路及实现》](https://blog.csdn.net/Gene1994/article/details/85097507)
190 |
191 |
--------------------------------------------------------------------------------
/数据结构与算法/算法.md:
--------------------------------------------------------------------------------
1 |
2 | ## LeetCode
3 | [LeetCode(中国)官网](https://leetcode-cn.com/)
4 |
5 | [如何高效地使用 LeetCode](https://leetcode-cn.com/articles/%E5%A6%82%E4%BD%95%E9%AB%98%E6%95%88%E5%9C%B0%E4%BD%BF%E7%94%A8-leetcode/)
6 |
7 |
8 | ## 牛客网:
9 |
10 | [牛客网首页](https://www.nowcoder.com)
11 |
12 |
13 | > ### **[剑指offer编程题](https://www.nowcoder.com/ta/coding-interviews)**
14 |
15 | **分类解析:**
16 | - [(1)斐波那契数列问题和跳台阶问题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(1)斐波那契数列问题和跳台阶问题.md)
17 | - [(2)二维数组查找和替换空格问题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(2)二维数组查找和替换空格问题.md)
18 | - [(3)数值的整数次方和调整数组元素顺序](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(3)数值的整数次方和调整数组元素顺序.md)
19 | - [(4)链表相关编程题](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(4)链表相关编程题.md)
20 | - [(5)栈变队列和栈的压入、弹出序列](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/剑指offer/(5)栈变队列和栈的压入、弹出序列.md)
21 |
22 | > ### [2017校招真题](https://www.nowcoder.com/ta/2017test)
23 |
24 | > ### [华为机试题](https://www.nowcoder.com/ta/huawei)
25 |
26 |
27 | ## 公司真题
28 |
29 | > [ 网易2018校园招聘编程题真题集合](https://www.nowcoder.com/test/6910869/summary)
30 |
31 | **解析:**
32 | - [ 网易2018校招编程题1-3](https://github.com/Snailclimb/Java-Guide/tree/master/数据结构与算法/算法题解析/公司真题/网易2018校招编程题1-3.md)
33 |
34 | > [ 网易2018校招内推编程题集合](https://www.nowcoder.com/test/6291726/summary)
35 |
36 | > [2017年校招全国统一模拟笔试(第五场)编程题集合](https://www.nowcoder.com/test/5986669/summary)
37 |
38 | > [2017年校招全国统一模拟笔试(第四场)编程题集合](https://www.nowcoder.com/test/5507925/summary)
39 |
40 | > [2017年校招全国统一模拟笔试(第三场)编程题集合](https://www.nowcoder.com/test/5217106/summary)
41 |
42 | > [2017年校招全国统一模拟笔试(第二场)编程题集合](https://www.nowcoder.com/test/4546329/summary)
43 |
44 | > [ 2017年校招全国统一模拟笔试(第一场)编程题集合](https://www.nowcoder.com/test/4236887/summary)
45 |
46 |
47 | > [百度2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4998655/summary)
48 |
49 | > [网易2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4575457/summary)
50 |
51 | > [网易2017秋招编程题集合](https://www.nowcoder.com/test/2811407/summary)
52 |
53 | > [网易有道2017内推编程题](https://www.nowcoder.com/test/2385858/summary)
54 |
55 | > [ 滴滴出行2017秋招笔试真题-编程题汇总](https://www.nowcoder.com/test/3701760/summary)
56 |
57 | > [腾讯2017暑期实习生编程题](https://www.nowcoder.com/test/1725829/summary)
58 |
59 | > [今日头条2017客户端工程师实习生笔试题](https://www.nowcoder.com/test/1649301/summary)
60 |
61 | > [今日头条2017后端工程师实习生笔试题](https://www.nowcoder.com/test/1649268/summary)
62 |
63 |
64 |
65 | ## 排序算法:
66 | [图解排序算法(一)之3种简单排序(选择,冒泡,直接插入)](http://www.cnblogs.com/chengxiao/p/6103002.html)
67 |
68 | [图解排序算法(二)之希尔排序](https://www.cnblogs.com/chengxiao/p/6104371.html)
69 |
70 | [图解排序算法(三)之堆排序](http://www.cnblogs.com/chengxiao/p/6129630.html)
71 |
72 | [图解排序算法(四)之归并排序](http://www.cnblogs.com/chengxiao/p/6194356.html)
73 |
74 | [图解排序算法(五)之快速排序——三数取中法](http://www.cnblogs.com/chengxiao/p/6262208.html)
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/数据结构与算法/算法题解析/公司真题/网易2018校招编程题1-3.md:
--------------------------------------------------------------------------------
1 | 下面三道编程题来自网易2018校招编程题,这三道应该来说是非常简单的编程题了,这些题目大家稍微有点编程和数学基础的话应该没什么问题。看答案之前一定要自己先想一下如果是自己做的话会怎么去做,然后再对照这我的答案看看,和你自己想的有什么区别?那一种方法更好?
2 |
3 | 
4 | > # 问题
5 |
6 | ## 一 获得特定数量硬币问题
7 |
8 | 小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。
9 |
10 | 魔法机器1:如果投入x个魔法币,魔法机器会将其变为2x+1个魔法币
11 |
12 | 魔法机器2:如果投入x个魔法币,魔法机器会将其变为2x+2个魔法币
13 |
14 | 小易采购魔法神器总共需要n个魔法币,所以小易只能通过两台魔法机器产生恰好n个魔法币,小易需要你帮他设计一个投入方案使他最后恰好拥有n个魔法币。
15 |
16 | **输入描述:** 输入包括一行,包括一个正整数n(1 ≤ n ≤ 10^9),表示小易需要的魔法币数量。
17 |
18 |
19 | **输出描述:** 输出一个字符串,每个字符表示该次小易选取投入的魔法机器。其中只包含字符'1'和'2'。
20 |
21 | **输入例子1:** 10
22 |
23 | **输出例子1:** 122
24 |
25 | ## 二 求“相反数”问题
26 |
27 | 为了得到一个数的"相反数",我们将这个数的数字顺序颠倒,然后再加上原先的数得到"相反数"。例如,为了得到1325的"相反数",首先我们将该数的数字顺序颠倒,我们得到5231,之后再加上原先的数,我们得到5231+1325=6556.如果颠倒之后的数字有前缀零,前缀零将会被忽略。例如n = 100, 颠倒之后是1.
28 |
29 | **输入描述:** 输入包括一个整数n,(1 ≤ n ≤ 10^5)
30 |
31 |
32 | **输出描述:** 输出一个整数,表示n的相反数
33 |
34 | **输入例子1:** 1325
35 |
36 | **输出例子1:** 6556
37 |
38 | ## 三 字符串碎片的平均长度
39 |
40 | 一个由小写字母组成的字符串可以看成一些同一字母的最大碎片组成的。例如,"aaabbaaac"是由下面碎片组成的:'aaa','bb','c'。牛牛现在给定一个字符串,请你帮助计算这个字符串的所有碎片的平均长度是多少。
41 |
42 | **输入描述:** 输入包括一个字符串s,字符串s的长度length(1 ≤ length ≤ 50),s只含小写字母('a'-'z')
43 |
44 |
45 | **输出描述:** 输出一个整数,表示所有碎片的平均长度,四舍五入保留两位小数。
46 |
47 | **如样例所示:** s = "aaabbaaac"
48 | 所有碎片的平均长度 = (3 + 2 + 3 + 1) / 4 = 2.25
49 |
50 | **输入例子1:** aaabbaaac
51 |
52 | **输出例子1:** 2.25
53 |
54 | 
55 |
56 | > # 答案
57 |
58 | ## 一 获得特定数量硬币问题
59 |
60 | ### 分析:
61 |
62 | 作为该试卷的第一题,这道题应该只要思路正确就很简单了。
63 |
64 | 解题关键:明确魔法机器1只能产生奇数,魔法机器2只能产生偶数即可。我们从后往前一步一步推回去即可。
65 |
66 | ### 示例代码
67 | 注意:由于用户的输入不确定性,一般是为了程序高可用性使需要将捕获用户输入异常然后友好提示用户输入类型错误并重新输入的。所以下面我给了两个版本,这两个版本都是正确的。这里只是给大家演示如何捕获输入类型异常,后面的题目中我给的代码没有异常处理的部分,参照下面两个示例代码,应该很容易添加。(PS:企业面试中没有明确就不用添加异常处理,当然你有的话也更好)
68 |
69 | **不带输入异常处理判断的版本:**
70 |
71 | ```java
72 | import java.util.Scanner;
73 |
74 | public class Main2 {
75 | // 解题关键:明确魔法机器1只能产生奇数,魔法机器2只能产生偶数即可。我们从后往前一步一步推回去即可。
76 |
77 | public static void main(String[] args) {
78 | System.out.println("请输入要获得的硬币数量:");
79 | Scanner scanner = new Scanner(System.in);
80 | int coincount = scanner.nextInt();
81 | StringBuilder sb = new StringBuilder();
82 | while (coincount >= 1) {
83 | // 偶数的情况
84 | if (coincount % 2 == 0) {
85 | coincount = (coincount - 2) / 2;
86 | sb.append("2");
87 | // 奇数的情况
88 | } else {
89 | coincount = (coincount - 1) / 2;
90 | sb.append("1");
91 | }
92 | }
93 | // 输出反转后的字符串
94 | System.out.println(sb.reverse());
95 |
96 | }
97 | }
98 | ```
99 |
100 | **带输入异常处理判断的版本(当输入的不是整数的时候会提示重新输入):**
101 |
102 | ```java
103 | import java.util.InputMismatchException;
104 | import java.util.Scanner;
105 |
106 |
107 | public class Main {
108 | // 解题关键:明确魔法机器1只能产生奇数,魔法机器2只能产生偶数即可。我们从后往前一步一步推回去即可。
109 |
110 | public static void main(String[] args) {
111 | System.out.println("请输入要获得的硬币数量:");
112 | Scanner scanner = new Scanner(System.in);
113 | boolean flag = true;
114 | while (flag) {
115 | try {
116 | int coincount = scanner.nextInt();
117 | StringBuilder sb = new StringBuilder();
118 | while (coincount >= 1) {
119 | // 偶数的情况
120 | if (coincount % 2 == 0) {
121 | coincount = (coincount - 2) / 2;
122 | sb.append("2");
123 | // 奇数的情况
124 | } else {
125 | coincount = (coincount - 1) / 2;
126 | sb.append("1");
127 | }
128 | }
129 | // 输出反转后的字符串
130 | System.out.println(sb.reverse());
131 | flag=false;//程序结束
132 | } catch (InputMismatchException e) {
133 | System.out.println("输入数据类型不匹配,请您重新输入:");
134 | scanner.nextLine();
135 | continue;
136 | }
137 | }
138 |
139 | }
140 | }
141 |
142 | ```
143 |
144 |
145 | ## 二 求“相反数”问题
146 |
147 | ### 分析:
148 |
149 | 解决本道题有几种不同的方法,但是最快速的方法就是利用reverse()方法反转字符串然后再将字符串转换成int类型的整数,这个方法是快速解决本题关键。我们先来回顾一下下面两个知识点:
150 |
151 | **1)String转int;**
152 |
153 | 在 Java 中要将 String 类型转化为 int 类型时,需要使用 Integer 类中的 parseInt() 方法或者 valueOf() 方法进行转换.
154 | ```java
155 | String str = "123";
156 | int a = Integer.parseInt(str);
157 | ```
158 | 或
159 | ```java
160 | String str = "123";
161 | int a = Integer.valueOf(str).intValue();
162 | ```
163 |
164 |
165 | **2)next()和nextLine()的区别**
166 |
167 | 在Java中输入字符串有两种方法,就是next()和nextLine().两者的区别就是:nextLine()的输入是碰到回车就终止输入,而next()方法是碰到空格,回车,Tab键都会被视为终止符。所以next()不会得到带空格的字符串,而nextLine()可以得到带空格的字符串。
168 |
169 | ### 示例代码:
170 |
171 | ```java
172 | import java.util.Scanner;
173 |
174 | /**
175 | * 本题关键:①String转int;②next()和nextLine()的区别
176 | */
177 | public class Main {
178 |
179 | public static void main(String[] args) {
180 |
181 | System.out.println("请输入一个整数:");
182 | Scanner scanner = new Scanner(System.in);
183 | String s=scanner.next();
184 | //将字符串转换成数字
185 | int number1=Integer.parseInt(s);
186 | //将字符串倒序后转换成数字
187 | //因为Integer.parseInt()的参数类型必须是字符串所以必须加上toString()
188 | int number2=Integer.parseInt(new StringBuilder(s).reverse().toString());
189 | System.out.println(number1+number2);
190 |
191 | }
192 | }
193 | ```
194 |
195 | ## 三 字符串碎片的平均长度
196 |
197 | ### 分析:
198 |
199 | 这道题的意思也就是要求:(字符串的总长度)/(相同字母团构成的字符串的个数)。
200 |
201 | 这样就很简单了,就变成了字符串的字符之间的比较。如果需要比较字符串的字符的话,我们可以利用charAt(i)方法:取出特定位置的字符与后一个字符比较,或者利用toCharArray()方法将字符串转换成字符数组采用同样的方法做比较。
202 |
203 | ### 示例代码
204 |
205 | **利用charAt(i)方法:**
206 |
207 | ```java
208 | import java.util.Scanner;
209 |
210 | public class Main {
211 |
212 | public static void main(String[] args) {
213 |
214 | Scanner sc = new Scanner(System.in);
215 | while (sc.hasNext()) {
216 | String s = sc.next();
217 | //个数至少为一个
218 | float count = 1;
219 | for (int i = 0; i < s.length() - 1; i++) {
220 | if (s.charAt(i) != s.charAt(i + 1)) {
221 | count++;
222 | }
223 | }
224 | System.out.println(s.length() / count);
225 | }
226 | }
227 |
228 | }
229 | ```
230 |
231 | **利用toCharArray()方法:**
232 |
233 | ```java
234 | import java.util.Scanner;
235 |
236 | public class Main2 {
237 |
238 | public static void main(String[] args) {
239 |
240 | Scanner sc = new Scanner(System.in);
241 | while (sc.hasNext()) {
242 | String s = sc.next();
243 | //个数至少为一个
244 | float count = 1;
245 | char [] stringArr = s.toCharArray();
246 | for (int i = 0; i < stringArr.length - 1; i++) {
247 | if (stringArr[i] != stringArr[i + 1]) {
248 | count++;
249 | }
250 | }
251 | System.out.println(s.length() / count);
252 | }
253 | }
254 |
255 | }
256 | ```
--------------------------------------------------------------------------------
/数据结构与算法/算法题解析/剑指offer/(1)斐波那契数列问题和跳台阶问题.md:
--------------------------------------------------------------------------------
1 | ### 一 斐波那契数列
2 | #### **题目描述:**
3 | 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
4 | n<=39
5 |
6 | #### **问题分析:**
7 | 可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有一个很大的问题,那就是递归大量的重复计算会导致内存溢出。另外可以使用迭代法,用fn1和fn2保存计算过程中的结果,并复用起来。下面我会把两个方法示例代码都给出来并给出两个方法的运行时间对比。
8 |
9 | #### **示例代码:**
10 | **采用迭代法:**
11 |
12 | ```java
13 |
14 | int Fibonacci(int number) {
15 | if (number <= 0) {
16 | return 0;
17 | }
18 | if (number == 1 || number == 2) {
19 | return 1;
20 | }
21 | int first = 1, second = 1, third = 0;
22 | for (int i = 3; i <= number; i++) {
23 | third = first + second;
24 | first = second;
25 | second = third;
26 | }
27 | return third;
28 | }
29 | ```
30 | **采用递归:**
31 | ```java
32 | public int Fibonacci(int n) {
33 |
34 | if (n <= 0) {
35 | return 0;
36 | }
37 | if (n == 1||n==2) {
38 | return 1;
39 | }
40 |
41 | return Fibonacci(n - 2) + Fibonacci(n - 1);
42 |
43 | }
44 | ```
45 |
46 | #### **运行时间对比:**
47 | 假设n为40我们分别使用迭代法和递归法计算,计算结果如下:
48 | 1. 迭代法
49 | 
50 | 2. 递归法
51 | 
52 |
53 |
54 | ### 二 跳台阶问题
55 | #### **题目描述:**
56 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
57 | #### **问题分析:**
58 | **正常分析法:**
59 | a.如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1);
60 | b.假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2)
61 | c.由a,b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2)
62 | d.然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2
63 | **找规律分析法:**
64 | f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5, 可以总结出f(n) = f(n-1) + f(n-2)的规律。
65 | 但是为什么会出现这样的规律呢?假设现在6个台阶,我们可以从第5跳一步到6,这样的话有多少种方案跳到5就有多少种方案跳到6,另外我们也可以从4跳两步跳到6,跳到4有多少种方案的话,就有多少种方案跳到6,其他的不能从3跳到6什么的啦,所以最后就是f(6) = f(5) + f(4);这样子也很好理解变态跳台阶的问题了。
66 |
67 | **所以这道题其实就是斐波那契数列的问题。**
68 | 代码只需要在上一题的代码稍做修改即可。和上一题唯一不同的就是这一题的初始元素变为 1 2 3 5 8.....而上一题为1 1 2 3 5 .......。另外这一题也可以用递归做,但是递归效率太低,所以我这里只给出了迭代方式的代码。
69 | #### **示例代码:**
70 | ```java
71 |
72 | int jumpFloor(int number) {
73 | if (number <= 0) {
74 | return 0;
75 | }
76 | if (number == 1) {
77 | return 1;
78 | }
79 | if (number == 2) {
80 | return 2;
81 | }
82 | int first = 1, second = 2, third = 0;
83 | for (int i = 3; i <= number; i++) {
84 | third = first + second;
85 | first = second;
86 | second = third;
87 | }
88 | return third;
89 | }
90 | ```
91 |
92 |
93 | ### 三 变态跳台阶问题
94 | #### **题目描述:**
95 | 一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
96 |
97 | #### **问题分析:**
98 | 假设n>=2,第一步有n种跳法:跳1级、跳2级、到跳n级
99 | 跳1级,剩下n-1级,则剩下跳法是f(n-1)
100 | 跳2级,剩下n-2级,则剩下跳法是f(n-2)
101 | ......
102 | 跳n-1级,剩下1级,则剩下跳法是f(1)
103 | 跳n级,剩下0级,则剩下跳法是f(0)
104 | 所以在n>=2的情况下:
105 | f(n)=f(n-1)+f(n-2)+...+f(1)
106 | 因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
107 | 所以f(n)=2*f(n-1) 又f(1)=1,所以可得**f(n)=2^(number-1)**
108 |
109 | #### **示例代码:**
110 |
111 | ```java
112 | int JumpFloorII(int number) {
113 | return 1 << --number;//2^(number-1)用位移操作进行,更快
114 | }
115 | ```
116 | #### **补充:**
117 | **java中有三种移位运算符:**
118 |
119 | 1. “<<” : **左移运算符**,等同于乘2的n次方
120 | 2. “>>”: **右移运算符**,等同于除2的n次方
121 | 3. “>>>” **无符号右移运算符**,不管移动前最高位是0还是1,右移后左侧产生的空位部分都以0来填充。与>>类似。
122 | 例:
123 | int a = 16;
124 | int b = a << 2;//左移2,等同于16 * 2的2次方,也就是16 * 4
125 | int c = a >> 2;//右移2,等同于16 / 2的2次方,也就是16 / 4
126 |
127 |
128 |
--------------------------------------------------------------------------------
/数据结构与算法/算法题解析/剑指offer/(2)二维数组查找和替换空格问题.md:
--------------------------------------------------------------------------------
1 | ### 一 二维数组查找
2 | #### **题目描述:**
3 | 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
4 | #### **问题解析:**
5 | 这一道题还是比较简单的,我们需要考虑的是如何做,效率最快。这里有一种很好理解的思路:
6 |
7 | > 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
8 | 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
9 | 要查找数字比左下角数字小时,上移。这样找的速度最快。
10 |
11 | #### **示例代码:**
12 | ```java
13 | public boolean Find(int target, int [][] array) {
14 | //基本思路从左下角开始找,这样速度最快
15 | int row = array.length-1;//行
16 | int column = 0;//列
17 | //当行数大于0,当前列数小于总列数时循环条件成立
18 | while((row >= 0)&& (column< array[0].length)){
19 | if(array[row][column] > target){
20 | row--;
21 | }else if(array[row][column] < target){
22 | column++;
23 | }else{
24 | return true;
25 | }
26 | }
27 | return false;
28 | }
29 | ```
30 | ### 二 替换空格
31 | #### **题目描述:**
32 | 请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
33 | #### **问题分析:**
34 | 这道题不难,我们可以通过循环判断字符串的字符是否为空格,是的话就利用append()方法添加追加“%20”,否则还是追加原字符。
35 |
36 | 或者最简单的方法就是利用: replaceAll(String regex,String replacement)方法了,一行代码就可以解决。
37 |
38 | #### **示例代码:**
39 | **常规做法:**
40 | ```java
41 | public String replaceSpace(StringBuffer str) {
42 | StringBuffer out=new StringBuffer();
43 | for (int i = 0; i < str.toString().length(); i++) {
44 | char b=str.charAt(i);
45 | if(String.valueOf(b).equals(" ")){
46 | out.append("%20");
47 | }else{
48 | out.append(b);
49 | }
50 | }
51 | return out.toString();
52 | }
53 | ```
54 | **一行代码解决:**
55 | ```java
56 | public String replaceSpace(StringBuffer str) {
57 | //return str.toString().replaceAll(" ", "%20");
58 | //public String replaceAll(String regex,String replacement)
59 | //用给定的替换替换与给定的regular expression匹配的此字符串的每个子字符串。
60 | //\ 转义字符. 如果你要使用 "\" 本身, 则应该使用 "\\". String类型中的空格用“\s”表示,所以我这里猜测"\\s"就是代表空格的意思
61 | return str.toString().replaceAll("\\s", "%20");
62 | }
63 |
64 | ```
65 |
--------------------------------------------------------------------------------
/数据结构与算法/算法题解析/剑指offer/(3)数值的整数次方和调整数组元素顺序.md:
--------------------------------------------------------------------------------
1 | ### 一 数值的整数次方
2 | #### **题目描述:**
3 | 给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
4 | #### **问题解析:**
5 | 这道题算是比较麻烦和难一点的一个了。我这里采用的是**二分幂**思想,当然也可以采用**快速幂**。
6 | 更具剑指offer书中细节,该题的解题思路如下:
7 | 1.当底数为0且指数<0时,会出现对0求倒数的情况,需进行错误处理,设置一个全局变量;
8 | 2.判断底数是否等于0,由于base为double型,所以不能直接用==判断
9 | 3.优化求幂函数(二分幂)。
10 | 当n为偶数,a^n =(a^n/2)*(a^n/2);
11 | 当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a。时间复杂度O(logn)
12 |
13 | **时间复杂度**:O(logn)
14 | #### **示例代码:**
15 | ```java
16 | public class Solution {
17 | boolean invalidInput=false;
18 | public double Power(double base, int exponent) {
19 | //如果底数等于0并且指数小于0
20 | //由于base为double型,不能直接用==判断
21 | if(equal(base,0.0)&&exponent<0){
22 | invalidInput=true;
23 | return 0.0;
24 | }
25 | int absexponent=exponent;
26 | //如果指数小于0,将指数转正
27 | if(exponent<0)
28 | absexponent=-exponent;
29 | //getPower方法求出base的exponent次方。
30 | double res=getPower(base,absexponent);
31 | //如果指数小于0,所得结果为上面求的结果的倒数
32 | if(exponent<0)
33 | res=1.0/res;
34 | return res;
35 | }
36 | //比较两个double型变量是否相等的方法
37 | boolean equal(double num1,double num2){
38 | if(num1-num2>-0.000001&&num1-num2<0.000001)
39 | return true;
40 | else
41 | return false;
42 | }
43 | //求出b的e次方的方法
44 | double getPower(double b,int e){
45 | //如果指数为0,返回1
46 | if(e==0)
47 | return 1.0;
48 | //如果指数为1,返回b
49 | if(e==1)
50 | return b;
51 | //e>>1相等于e/2,这里就是求a^n =(a^n/2)*(a^n/2)
52 | double result=getPower(b,e>>1);
53 | result*=result;
54 | //如果指数n为奇数,则要再乘一次底数base
55 | if((e&1)==1)
56 | result*=b;
57 | return result;
58 | }
59 | }
60 | ```
61 |
62 | 当然这一题也可以采用笨方法:累乘。不过这种方法的时间复杂度为O(n),这样没有前一种方法效率高。
63 | ```java
64 | // 使用累乘
65 | public double powerAnother(double base, int exponent) {
66 | double result = 1.0;
67 | for (int i = 0; i < Math.abs(exponent); i++) {
68 | result *= base;
69 | }
70 | if (exponent >= 0)
71 | return result;
72 | else
73 | return 1 / result;
74 | }
75 | ```
76 | ### 二 调整数组顺序使奇数位于偶数前面
77 | #### **题目描述:**
78 | 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
79 |
80 | #### **问题解析:**
81 | 这道题有挺多种解法的,给大家介绍一种我觉得挺好理解的方法:
82 | 我们首先统计奇数的个数假设为n,然后新建一个等长数组,然后通过循环判断原数组中的元素为偶数还是奇数。如果是则从数组下标0的元素开始,把该奇数添加到新数组;如果是偶数则从数组下标为n的元素开始把该偶数添加到新数组中。
83 |
84 | #### **示例代码:**
85 | 时间复杂度为O(n),空间复杂度为O(n)的算法
86 | ```java
87 | public class Solution {
88 | public void reOrderArray(int [] array) {
89 | //如果数组长度等于0或者等于1,什么都不做直接返回
90 | if(array.length==0||array.length==1)
91 | return;
92 | //oddCount:保存奇数个数
93 | //oddBegin:奇数从数组头部开始添加
94 | int oddCount=0,oddBegin=0;
95 | //新建一个数组
96 | int[] newArray=new int[array.length];
97 | //计算出(数组中的奇数个数)开始添加元素
98 | for(int i=0;i stack1 = new Stack();
25 | Stack stack2 = new Stack();
26 |
27 | //当执行push操作时,将元素添加到stack1
28 | public void push(int node) {
29 | stack1.push(node);
30 | }
31 |
32 | public int pop() {
33 | //如果两个队列都为空则抛出异常,说明用户没有push进任何元素
34 | if(stack1.empty()&&stack2.empty()){
35 | throw new RuntimeException("Queue is empty!");
36 | }
37 | //如果stack2不为空直接对stack2执行pop操作,
38 | if(stack2.empty()){
39 | while(!stack1.empty()){
40 | //将stack1的元素按后进先出push进stack2里面
41 | stack2.push(stack1.pop());
42 | }
43 | }
44 | return stack2.pop();
45 | }
46 | }
47 | ```
48 |
49 | ### 二 栈的压入、弹出序列
50 | #### **题目描述:**
51 | 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
52 | #### **题目分析:**
53 | 这道题想了半天没有思路,参考了Alias的答案,他的思路写的也很详细应该很容易看懂。
54 | 作者:Alias
55 | https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
56 | 来源:牛客网
57 |
58 | 【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
59 |
60 | 举例:
61 |
62 | 入栈1,2,3,4,5
63 |
64 | 出栈4,5,3,2,1
65 |
66 | 首先1入辅助栈,此时栈顶1≠4,继续入栈2
67 |
68 | 此时栈顶2≠4,继续入栈3
69 |
70 | 此时栈顶3≠4,继续入栈4
71 |
72 | 此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
73 |
74 | 此时栈顶3≠5,继续入栈5
75 |
76 | 此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
77 |
78 | ….
79 | 依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
80 |
81 |
82 |
83 | #### **考察内容:**
84 | 栈
85 |
86 | #### **示例代码:**
87 | ```java
88 | import java.util.ArrayList;
89 | import java.util.Stack;
90 | //这道题没想出来,参考了Alias同学的答案:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
91 | public class Solution {
92 | public boolean IsPopOrder(int [] pushA,int [] popA) {
93 | if(pushA.length == 0 || popA.length == 0)
94 | return false;
95 | Stack s = new Stack();
96 | //用于标识弹出序列的位置
97 | int popIndex = 0;
98 | for(int i = 0; i< pushA.length;i++){
99 | s.push(pushA[i]);
100 | //如果栈不为空,且栈顶元素等于弹出序列
101 | while(!s.empty() &&s.peek() == popA[popIndex]){
102 | //出栈
103 | s.pop();
104 | //弹出序列向后一位
105 | popIndex++;
106 | }
107 | }
108 | return s.empty();
109 | }
110 | }
111 | ```
--------------------------------------------------------------------------------
/架构/8 张图读懂大型网站技术架构.md:
--------------------------------------------------------------------------------
1 | > 本文是作者读 《大型网站技术架构》所做的思维导图,在这里分享给各位,公众号(JavaGuide)后台回复:“架构”。即可获得下面图片的源文件以及思维导图源文件!
2 |
3 |
4 |
5 | - [1. 大型网站架构演化](#1-大型网站架构演化)
6 | - [2. 大型架构模式](#2-大型架构模式)
7 | - [3. 大型网站核心架构要素](#3-大型网站核心架构要素)
8 | - [4. 瞬时响应:网站的高性能架构](#4-瞬时响应网站的高性能架构)
9 | - [5. 万无一失:网站的高可用架构](#5-万无一失网站的高可用架构)
10 | - [6. 永无止境:网站的伸缩性架构](#6-永无止境网站的伸缩性架构)
11 | - [7. 随机应变:网站的可扩展性架构](#7-随机应变网站的可扩展性架构)
12 | - [8. 固若金汤:网站的安全机构](#8-固若金汤网站的安全机构)
13 |
14 |
15 |
16 |
17 | ### 1. 大型网站架构演化
18 |
19 | 
20 |
21 | ### 2. 大型架构模式
22 |
23 | 
24 |
25 | ### 3. 大型网站核心架构要素
26 |
27 | 
28 |
29 | ### 4. 瞬时响应:网站的高性能架构
30 |
31 | 
32 |
33 | ### 5. 万无一失:网站的高可用架构
34 |
35 | 
36 |
37 | ### 6. 永无止境:网站的伸缩性架构
38 |
39 | 
40 |
41 | ### 7. 随机应变:网站的可扩展性架构
42 |
43 | 
44 |
45 | ### 8. 固若金汤:网站的安全机构
46 |
47 | 
48 |
--------------------------------------------------------------------------------
/架构/分布式.md:
--------------------------------------------------------------------------------
1 | - ### 一 分布式系统的经典基础理论
2 |
3 | [分布式系统的经典基础理论](https://blog.csdn.net/qq_34337272/article/details/80444032)
4 |
5 | 本文主要是简单的介绍了三个常见的概念: **分布式系统设计理念** 、 **CAP定理** 、 **BASE理论** ,关于分布式系统的还有很多很多东西。
6 | 
7 |
8 | - ### 二 分布式事务
9 | 分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。以上是百度百科的解释,简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
10 | * [深入理解分布式事务](http://www.codeceo.com/article/distributed-transaction.html)
11 | * [分布式事务?No, 最终一致性](https://zhuanlan.zhihu.com/p/25933039)
12 | * [聊聊分布式事务,再说说解决方案](https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html)
13 |
14 |
15 | - ### 三 分布式系统一致性
16 | [分布式服务化系统一致性的“最佳实干”](https://www.jianshu.com/p/1156151e20c8)
17 |
18 | - ### 四 一致性协议/算法
19 | 早在1898年就诞生了著名的 **Paxos经典算法** (**Zookeeper就采用了Paxos算法的近亲兄弟Zab算法**),但由于Paxos算法非常难以理解、实现、排错。所以不断有人尝试简化这一算法,直到2013年才有了重大突破:斯坦福的Diego Ongaro、John Ousterhout以易懂性为目标设计了新的一致性算法—— **Raft算法** ,并发布了对应的论文《In Search of an Understandable Consensus Algorithm》,到现在有十多种语言实现的Raft算法框架,较为出名的有以Go语言实现的Etcd,它的功能类似于Zookeeper,但采用了更为主流的Rest接口。
20 | * [图解 Paxos 一致性协议](http://blog.xiaohansong.com/2016/09/30/Paxos/)
21 | * [图解分布式协议-RAFT](http://ifeve.com/raft/)
22 | * [Zookeeper ZAB 协议分析](http://blog.xiaohansong.com/2016/08/25/zab/)
23 |
24 | - ### 五 分布式存储
25 |
26 | **分布式存储系统将数据分散存储在多台独立的设备上**。传统的网络存储系统采用集中的存储服务器存放所有数据,存储服务器成为系统性能的瓶颈,也是可靠性和安全性的焦点,不能满足大规模存储应用的需要。分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,它不但提高了系统的可靠性、可用性和存取效率,还易于扩展。
27 |
28 | * [分布式存储系统概要](http://witchiman.top/2017/05/05/distributed-system/)
29 |
30 | - ### 六 分布式计算
31 |
32 | **所谓分布式计算是一门计算机科学,它研究如何把一个需要非常巨大的计算能力才能解决的问题分成许多小的部分,然后把这些部分分配给许多计算机进行处理,最后把这些计算结果综合起来得到最终的结果。**
33 | 分布式网络存储技术是将数据分散的存储于多台独立的机器设备上。分布式网络存储系统采用可扩展的系统结构,利用多台存储服务器分担存储负荷,利用位置服务器定位存储信息,不但解决了传统集中式存储系统中单存储服务器的瓶颈问题,还提高了系统的可靠性、可用性和扩展性。
34 |
35 | * [关于分布式计算的一些概念](https://blog.csdn.net/qq_34337272/article/details/80549020)
36 |
37 |
--------------------------------------------------------------------------------
/计算机网络与数据通信/HTTPS中的TLS.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | - [1. SSL 与 TLS](#1-ssl-%E4%B8%8E-tls)
4 | - [2. 从网络协议的角度理解 HTTPS](#2-%E4%BB%8E%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%A7%92%E5%BA%A6%E7%90%86%E8%A7%A3-https)
5 | - [3. 从密码学的角度理解 HTTPS](#3-%E4%BB%8E%E5%AF%86%E7%A0%81%E5%AD%A6%E7%9A%84%E8%A7%92%E5%BA%A6%E7%90%86%E8%A7%A3-https)
6 | - [3.1. TLS 工作流程](#31-tls-%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B)
7 | - [3.2. 密码基础](#32-%E5%AF%86%E7%A0%81%E5%9F%BA%E7%A1%80)
8 | - [3.2.1. 伪随机数生成器](#321-%E4%BC%AA%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%94%9F%E6%88%90%E5%99%A8)
9 | - [3.2.2. 消息认证码](#322-%E6%B6%88%E6%81%AF%E8%AE%A4%E8%AF%81%E7%A0%81)
10 | - [3.2.3. 数字签名](#323-%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D)
11 | - [3.2.4. 公钥密码](#324-%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81)
12 | - [3.2.5. 证书](#325-%E8%AF%81%E4%B9%A6)
13 | - [3.2.6. 密码小结](#326-%E5%AF%86%E7%A0%81%E5%B0%8F%E7%BB%93)
14 | - [3.3. TLS 使用的密码技术](#33-tls-%E4%BD%BF%E7%94%A8%E7%9A%84%E5%AF%86%E7%A0%81%E6%8A%80%E6%9C%AF)
15 | - [3.4. TLS 总结](#34-tls-%E6%80%BB%E7%BB%93)
16 | - [4. RSA 简单示例](#4-rsa-%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B)
17 | - [5. 参考](#5-%E5%8F%82%E8%80%83)
18 |
19 |
20 |
21 | # 1. SSL 与 TLS
22 |
23 | SSL:(Secure Socket Layer) 安全套接层,于 1994 年由网景公司设计,并于 1995 年发布了 3.0 版本
24 | TLS:(Transport Layer Security)传输层安全性协议,是 IETF 在 SSL3.0 的基础上设计的协议
25 | 以下全部使用 TLS 来表示
26 |
27 | # 2. 从网络协议的角度理解 HTTPS
28 |
29 | ![此图并不准确][1]
30 | HTTP:HyperText Transfer Protocol 超文本传输协议
31 | HTTPS:Hypertext Transfer Protocol Secure 超文本传输安全协议
32 | TLS:位于 HTTP 和 TCP 之间的协议,其内部有 TLS握手协议、TLS记录协议
33 | HTTPS 经由 HTTP 进行通信,但利用 TLS 来保证安全,即 HTTPS = HTTP + TLS
34 |
35 | # 3. 从密码学的角度理解 HTTPS
36 |
37 | HTTPS 使用 TLS 保证安全,这里的“安全”分两部分,一是传输内容加密、二是服务端的身份认证
38 |
39 | ## 3.1. TLS 工作流程
40 |
41 | ![此图并不准确][2]
42 | 此为服务端单向认证,还有客户端/服务端双向认证,流程类似,只不过客户端也有自己的证书,并发送给服务器进行验证
43 |
44 | ## 3.2. 密码基础
45 |
46 | ### 3.2.1. 伪随机数生成器
47 |
48 | 为什么叫伪随机数,因为没有真正意义上的随机数,具体可以参考 Random/TheadLocalRandom
49 | 它的主要作用在于生成对称密码的秘钥、用于公钥密码生成秘钥对
50 |
51 | ### 3.2.2. 消息认证码
52 |
53 | 消息认证码主要用于验证消息的完整性与消息的认证,其中消息的认证指“消息来自正确的发送者”
54 |
55 | >消息认证码用于验证和认证,而不是加密
56 |
57 | ![消息认证码过程][3]
58 |
59 | 1. 发送者与接收者事先共享秘钥
60 | 2. 发送者根据发送消息计算 MAC 值
61 | 3. 发送者发送消息和 MAC 值
62 | 4. 接收者根据接收到的消息计算 MAC 值
63 | 5. 接收者根据自己计算的 MAC 值与收到的 MAC 对比
64 | 6. 如果对比成功,说明消息完整,并来自与正确的发送者
65 |
66 | ### 3.2.3. 数字签名
67 |
68 | 消息认证码的缺点在于**无法防止否认**,因为共享秘钥被 client、server 两端拥有,server 可以伪造 client 发送给自己的消息(自己给自己发送消息),为了解决这个问题,我们需要它们有各自的秘钥不被第二个知晓(这样也解决了共享秘钥的配送问题)
69 |
70 | ![数字签名过程][4]
71 |
72 | >数字签名和消息认证码都**不是为了加密**
73 | >可以将单向散列函数获取散列值的过程理解为使用 md5 摘要算法获取摘要的过程
74 |
75 | 使用自己的私钥对自己所认可的消息生成一个该消息专属的签名,这就是数字签名,表明我承认该消息来自自己
76 | 注意:**私钥用于加签,公钥用于解签,每个人都可以解签,查看消息的归属人**
77 |
78 | ### 3.2.4. 公钥密码
79 |
80 | 公钥密码也叫非对称密码,由公钥和私钥组成,它是最开始是为了解决秘钥的配送传输安全问题,即,我们不配送私钥,只配送公钥,私钥由本人保管
81 | 它与数字签名相反,公钥密码的私钥用于解密、公钥用于加密,每个人都可以用别人的公钥加密,但只有对应的私钥才能解开密文
82 | client:明文 + 公钥 = 密文
83 | server:密文 + 私钥 = 明文
84 | 注意:**公钥用于加密,私钥用于解密,只有私钥的归属者,才能查看消息的真正内容**
85 |
86 | ### 3.2.5. 证书
87 |
88 | 证书:全称公钥证书(Public-Key Certificate, PKC),里面保存着归属者的基本信息,以及证书过期时间、归属者的公钥,并由认证机构(Certification Authority, **CA**)施加数字签名,表明,某个认证机构认定该公钥的确属于此人
89 |
90 | >想象这个场景:你想在支付宝页面交易,你需要支付宝的公钥进行加密通信,于是你从百度上搜索关键字“支付宝公钥”,你获得了支什宝的公钥,这个时候,支什宝通过中间人攻击,让你访问到了他们支什宝的页面,最后你在这个支什宝页面完美的使用了支什宝的公钥完成了与支什宝的交易
91 | >![证书过程][5]
92 |
93 | 在上面的场景中,你可以理解支付宝证书就是由支付宝的公钥、和给支付宝颁发证书的企业的数字签名组成
94 | 任何人都可以给自己或别人的公钥添加自己的数字签名,表明:我拿我的尊严担保,我的公钥/别人的公钥是真的,至于信不信那是另一回事了
95 |
96 | ### 3.2.6. 密码小结
97 |
98 | | 密码 | 作用 | 组成 |
99 | | :-- | :-- | :-- |
100 | | 消息认证码 | 确认消息的完整、并对消息的来源认证 | 共享秘钥+消息的散列值 |
101 | | 数字签名 | 对消息的散列值签名 | 公钥+私钥+消息的散列值 |
102 | | 公钥密码 | 解决秘钥的配送问题 | 公钥+私钥+消息 |
103 | | 证书 | 解决公钥的归属问题 | 公钥密码中的公钥+数字签名 |
104 |
105 | ## 3.3. TLS 使用的密码技术
106 |
107 | 1. 伪随机数生成器:秘钥生成随机性,更难被猜测
108 | 2. 对称密码:对称密码使用的秘钥就是由伪随机数生成,相较于非对称密码,效率更高
109 | 3. 消息认证码:保证消息信息的完整性、以及验证消息信息的来源
110 | 4. 公钥密码:证书技术使用的就是公钥密码
111 | 5. 数字签名:验证证书的签名,确定由真实的某个 CA 颁发
112 | 6. 证书:解决公钥的真实归属问题,降低中间人攻击概率
113 |
114 | ## 3.4. TLS 总结
115 |
116 | TLS 是一系列密码工具的框架,作为框架,它也是非常的灵活,体现在每个工具套件它都可以替换,即:客户端与服务端之间协商密码套件,从而更难的被攻破,例如使用不同方式的对称密码,或者公钥密码、数字签名生成方式、单向散列函数技术的替换等
117 |
118 | # 4. RSA 简单示例
119 |
120 | RSA 是一种公钥密码算法,我们简单的走一遍它的加密解密过程
121 | 加密算法:密文 = (明文^E) mod N,其中公钥为{E,N},即”求明文的E次方的对 N 的余数“
122 | 解密算法:明文 = (密文^D) mod N,其中秘钥为{D,N},即”求密文的D次方的对 N 的余数“
123 | 例:我们已知公钥为{5,323},私钥为{29,323},明文为300,请写出加密和解密的过程:
124 | >加密:密文 = 123 ^ 5 mod 323 = 225
125 | >解密:明文 = 225 ^ 29 mod 323 = [[(225 ^ 5) mod 323] * [(225 ^ 5) mod 323] * [(225 ^ 5) mod 323] * [(225 ^ 5) mod 323] * [(225 ^ 5) mod 323] * [(225 ^ 4) mod 323]] mod 323 = (4 * 4 * 4 * 4 * 4 * 290) mod 323 = 123
126 |
127 | # 5. 参考
128 |
129 | 1. SSL加密发生在哪里:
130 | 2. TLS工作流程:
131 | 3. 《图解密码技术》: 豆瓣评分 9.5
132 |
133 | [1]: https://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/somephoto/%E4%B8%83%E5%B1%82.png
134 | [2]: https://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/somephoto/tls%E6%B5%81%E7%A8%8B.png
135 | [3]: https://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/somephoto/%E6%B6%88%E6%81%AF%E8%AE%A4%E8%AF%81%E7%A0%81%E8%BF%87%E7%A8%8B.png
136 | [4]: https://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/somephoto/%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D%E8%BF%87%E7%A8%8B.png
137 | [5]: https://leran2deeplearnjavawebtech.oss-cn-beijing.aliyuncs.com/somephoto/dns%E4%B8%AD%E9%97%B4%E4%BA%BA%E6%94%BB%E5%87%BB.png
--------------------------------------------------------------------------------
/计算机网络与数据通信/message-queue.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | - [消息队列其实很简单](#消息队列其实很简单)
4 | - [一 什么是消息队列](#一-什么是消息队列)
5 | - [二 为什么要用消息队列](#二-为什么要用消息队列)
6 | - [\(1\) 通过异步处理提高系统性能(削峰、减少响应所需时间)](#1-通过异步处理提高系统性能削峰减少响应所需时间)
7 | - [\(2\) 降低系统耦合性](#2-降低系统耦合性)
8 | - [三 使用消息队列带来的一些问题](#三-使用消息队列带来的一些问题)
9 | - [四 JMS VS AMQP](#四-jms-vs-amqp)
10 | - [4.1 JMS](#41-jms)
11 | - [4.1.1 JMS 简介](#411-jms-简介)
12 | - [4.1.2 JMS两种消息模型](#412-jms两种消息模型)
13 | - [4.1.3 JMS 五种不同的消息正文格式](#413-jms-五种不同的消息正文格式)
14 | - [4.2 AMQP](#42-amqp)
15 | - [4.3 JMS vs AMQP](#43-jms-vs-amqp)
16 | - [五 常见的消息队列对比](#五-常见的消息队列对比)
17 |
18 |
19 |
20 |
21 | # 消息队列其实很简单
22 |
23 | “RabbitMQ?”“Kafka?”“RocketMQ?”...在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。
24 |
25 | ## 一 什么是消息队列
26 |
27 | 我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,我们后面会一一对比这些消息队列。
28 |
29 | 另外,我们知道队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3...对于消费者就会按照1,2,3...的顺序来消费。但是偶尔也会出现消息被消费的顺序不对的情况,比如某个消息消费失败又或者一个 queue 多个consumer 也会导致消息被消费的顺序不对,我们一定要保证消息被消费的顺序正确。
30 |
31 | 除了上面说的消息消费顺序的问题,使用消息队列,我们还要考虑如何保证消息不被重复消费?如何保证消息的可靠性传输(如何处理消息丢失的问题)?......等等问题。所以说使用消息队列也不是十全十美的,使用它也会让系统可用性降低、复杂度提高,另外需要我们保障一致性等问题。
32 |
33 | ## 二 为什么要用消息队列
34 |
35 | 我觉得使用消息队列主要有两点好处:1.通过异步处理提高系统性能(削峰、减少响应所需时间);2.降低系统耦合性。如果在面试的时候你被面试官问到这个问题的话,一般情况是你在你的简历上涉及到消息队列这方面的内容,这个时候推荐你结合你自己的项目来回答。
36 |
37 |
38 | 《大型网站技术架构》第四章和第七章均有提到消息队列对应用性能及扩展性的提升。
39 |
40 | ### (1) 通过异步处理提高系统性能(削峰、减少响应所需时间)
41 |
42 | 
43 | 如上图,**在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列之后,用户的请求数据发送给消息队列之后立即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。**
44 |
45 | 通过以上分析我们可以得出**消息队列具有很好的削峰作用的功能**——即**通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。** 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。如下图所示:
46 | 
47 |
48 | 因为**用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败**。因此使用消息队列进行异步处理之后,需要**适当修改业务流程进行配合**,比如**用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功**,以免交易纠纷。这就类似我们平时手机订火车票和电影票。
49 |
50 | ### (2) 降低系统耦合性
51 |
52 | 我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。
53 |
54 | 我们最常见的**事件驱动架构**类似生产者消费者模式,在大型网站中通常用利用消息队列实现事件驱动结构。如下图所示:
55 |
56 | 
57 |
58 | **消息队列使利用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。** 从上图可以看到**消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合**,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。**对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计**。
59 |
60 | 消息接受者对消息进行过滤、处理、包装后,构造成一个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是一系列流程。
61 |
62 | **另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息。**
63 |
64 | **备注:** 不要认为消息队列只能利用发布-订阅模式工作,只不过在解耦这个特定业务环境下是使用发布-订阅模式的。**除了发布-订阅模式,还有点对点订阅模式(一个消息只有一个消费者),我们比较常用的是发布-订阅模式。** 另外,这两种消息模型是 JMS 提供的,AMQP 协议还提供了 5 种消息模型。
65 |
66 | ## 三 使用消息队列带来的一些问题
67 |
68 | - **系统可用性降低:** 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!
69 | - **系统复杂性提高:** 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
70 | - **一致性问题:** 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!
71 |
72 | ## 四 JMS VS AMQP
73 |
74 | ### 4.1 JMS
75 |
76 | #### 4.1.1 JMS 简介
77 |
78 | JMS(JAVA Message Service,java消息服务)是java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。**JMS(JAVA Message Service,Java消息服务)API是一个消息服务的标准或者说是规范**,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
79 |
80 | **ActiveMQ 就是基于 JMS 规范实现的。**
81 |
82 | #### 4.1.2 JMS两种消息模型
83 |
84 | ①点到点(P2P)模型
85 |
86 | 
87 | 使用**队列(Queue)**作为消息通信载体;满足**生产者与消费者模式**,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送100条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)
88 |
89 | ② 发布/订阅(Pub/Sub)模型
90 |
91 | 
92 | 发布订阅模型(Pub/Sub) 使用**主题(Topic)**作为消息通信载体,类似于**广播模式**;发布者发布一条消息,该消息通过主题传递给所有的订阅者,**在一条消息广播之后才订阅的用户则是收不到该条消息的**。
93 |
94 | #### 4.1.3 JMS 五种不同的消息正文格式
95 |
96 | JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。
97 |
98 | - StreamMessage -- Java原始值的数据流
99 | - MapMessage--一套名称-值对
100 | - TextMessage--一个字符串对象
101 | - ObjectMessage--一个序列化的 Java对象
102 | - BytesMessage--一个字节的数据流
103 |
104 |
105 | ### 4.2 AMQP
106 |
107 | AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准 **高级消息队列协议**(二进制应用层协议),是应用层协议的一个开放标准,为面向消息的中间件设计,兼容 JMS。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件同产品,不同的开发语言等条件的限制。
108 |
109 | **RabbitMQ 就是基于 AMQP 协议实现的。**
110 |
111 |
112 |
113 | ### 4.3 JMS vs AMQP
114 |
115 |
116 | |对比方向| JMS | AMQP |
117 | | :-------- | --------:| :--: |
118 | | 定义| Java API | 协议 |
119 | | 跨语言 | 否 | 是 |
120 | | 跨平台 | 否 | 是 |
121 | | 支持消息类型 | 提供两种消息模型:①Peer-2-Peer;②Pub/sub| 提供了五种消息模型:①direct exchange;②fanout exchange;③topic change;④headers exchange;⑤system exchange。本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分;|
122 | |支持消息类型| 支持多种消息类型 ,我们在上面提到过| byte[](二进制)|
123 |
124 | **总结:**
125 |
126 | - AMQP 为消息定义了线路层(wire-level protocol)的协议,而JMS所定义的是API规范。在 Java 体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差。而AMQP天然具有跨平台、跨语言特性。
127 | - JMS 支持TextMessage、MapMessage 等复杂的消息类型;而 AMQP 仅支持 byte[] 消息类型(复杂的类型可序列化后发送)。
128 | - 由于Exchange 提供的路由算法,AMQP可以提供多样化的路由方式来传递消息到消息队列,而 JMS 仅支持 队列 和 主题/订阅 方式两种。
129 |
130 |
131 | ## 五 常见的消息队列对比
132 |
133 |
134 |
135 | 对比方向 |概要
136 | -------- | ---
137 | 吞吐量| 万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。
138 | 可用性| 都可以实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。 kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
139 | 时效性| RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。其他三个都是 ms 级。
140 | 功能支持| 除了 Kafka,其他三个功能都较为完备。 Kafka 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准
141 | 消息丢失| ActiveMQ 和 RabbitMQ 丢失的可能性非常低, RocketMQ 和 Kafka 理论上不会丢失。
142 |
143 |
144 | **总结:**
145 |
146 | - ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。
147 | - RabbitMQ 在吞吐量方面虽然稍逊于 Kafka 和 RocketMQ ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为 RabbitMQ 基于 erlang 开发,所以国内很少有公司有实力做erlang源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ 一定是你的首选。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
148 | - RocketMQ 阿里出品,Java 系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的MQ,并且 RocketMQ 有阿里巴巴的实际业务场景的实战考验。RocketMQ 社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ 挺好的
149 | - kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。
150 |
151 |
152 | 参考:《Java工程师面试突击第1季-中华石杉老师》
153 |
--------------------------------------------------------------------------------
/计算机网络与数据通信/数据通信(RESTful、RPC、消息队列).md:
--------------------------------------------------------------------------------
1 | > ## RPC
2 |
3 | **RPC(Remote Procedure Call)—远程过程调用** ,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发分布式程序就像开发本地程序一样简单。
4 |
5 | **RPC采用客户端(服务调用方)/服务器端(服务提供方)模式,** 都运行在自己的JVM中。客户端只需要引入要使用的接口,接口的实现和运行都在服务器端。RPC主要依赖的技术包括序列化、反序列化和数据传输协议,这是一种定义与实现相分离的设计。
6 |
7 | **目前Java使用比较多的RPC方案主要有RMI(JDK自带)、Hessian、Dubbo以及Thrift等。**
8 |
9 | **注意: RPC主要指内部服务之间的调用,RESTful也可以用于内部服务之间的调用,但其主要用途还在于外部系统提供服务,因此没有将其包含在本知识点内。**
10 |
11 | ### 常见RPC框架:
12 |
13 | - **RMI(JDK自带):** JDK自带的RPC
14 |
15 | 详细内容可以参考:[从懵逼到恍然大悟之Java中RMI的使用](https://blog.csdn.net/lmy86263/article/details/72594760)
16 |
17 | - **Dubbo:** Dubbo是 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成。
18 |
19 | 详细内容可以参考:
20 |
21 | - [ 高性能优秀的服务框架-dubbo介绍](https://blog.csdn.net/qq_34337272/article/details/79862899)
22 |
23 | - [Dubbo是什么?能做什么?](https://blog.csdn.net/houshaolin/article/details/76408399)
24 |
25 |
26 | - **Hessian:** Hessian是一个轻量级的remotingonhttp工具,使用简单的方法提供了RMI的功能。 相比WebService,Hessian更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。
27 |
28 | 详细内容可以参考: [Hessian的使用以及理解](https://blog.csdn.net/sunwei_pyw/article/details/74002351)
29 |
30 | - **Thrift:** Apache Thrift是Facebook开源的跨语言的RPC通信框架,目前已经捐献给Apache基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于thrift研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。
31 |
32 |
33 | 详细内容可以参考: [【Java】分布式RPC通信框架Apache Thrift 使用总结](https://www.cnblogs.com/zeze/p/8628585.html)
34 |
35 | ### 如何进行选择:
36 |
37 | - **是否允许代码侵入:** 即需要依赖相应的代码生成器生成代码,比如Thrift。
38 | - **是否需要长连接获取高性能:** 如果对于性能需求较高的haul,那么可以果断选择基于TCP的Thrift、Dubbo。
39 | - **是否需要跨越网段、跨越防火墙:** 这种情况一般选择基于HTTP协议的Hessian和Thrift的HTTP Transport。
40 |
41 | 此外,Google推出的基于HTTP2.0的gRPC框架也开始得到应用,其序列化协议基于Protobuf,网络框架使用的是Netty4,但是其需要生成代码,可扩展性也比较差。
42 |
43 | > ## 消息中间件
44 |
45 | **消息中间件,也可以叫做中央消息队列或者是消息队列(区别于本地消息队列,本地消息队列指的是JVM内的队列实现)**,是一种独立的队列系统,消息中间件经常用来解决内部服务之间的 **异步调用问题** 。请求服务方把请求队列放到队列中即可返回,然后等待服务提供方去队列中获取请求进行处理,之后通过回调等机制把结果返回给请求服务方。
46 |
47 | 异步调用只是消息中间件一个非常常见的应用场景。此外,常用的消息队列应用场景还偷如下几个:
48 | - **解耦 :** 一个业务的非核心流程需要依赖其他系统,但结果并不重要,有通知即可。
49 | - **最终一致性 :** 指的是两个系统的状态保持一致,可以有一定的延迟,只要最终达到一致性即可。经常用在解决分布式事务上。
50 | - **广播 :** 消息队列最基本的功能。生产者只负责生产消息,订阅者接收消息。
51 | - **错峰和流控**
52 |
53 |
54 | 具体可以参考:
55 |
56 | [《消息队列深入解析》](https://blog.csdn.net/qq_34337272/article/details/80029918)
57 |
58 | 当前使用较多的消息队列有ActiveMQ(性能差,不推荐使用)、RabbitMQ、RocketMQ、Kafka等等,我们之前提到的redis数据库也可以实现消息队列,不过不推荐,redis本身设计就不是用来做消息队列的。
59 |
60 | - **ActiveMQ:** ActiveMQ是Apache出品,最流行的,能力强劲的开源消息总线。ActiveMQ是一个完全支持JMS1.1和J2EE 1.4规范的JMSProvider实现,尽管JMS规范出台已经是很久的事情了,但是JMS在当今的J2EE应用中间仍然扮演着特殊的地位。
61 |
62 | 具体可以参考:
63 |
64 | [《消息队列ActiveMQ的使用详解》](https://blog.csdn.net/qq_34337272/article/details/80031702)
65 |
66 | - **RabbitMQ:** RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。RabbitMQ 最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗
67 | > AMQP :Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。
68 |
69 |
70 | 具体可以参考:
71 |
72 | [《消息队列之 RabbitMQ》](https://www.jianshu.com/p/79ca08116d57)
73 |
74 | - **RocketMQ:**
75 |
76 | 具体可以参考:
77 |
78 | [《RocketMQ 实战之快速入门》](https://www.jianshu.com/p/824066d70da8)
79 |
80 | [《十分钟入门RocketMQ》](http://jm.taobao.org/2017/01/12/rocketmq-quick-start-in-10-minutes/) (阿里中间件团队博客)
81 |
82 |
83 | - **Kafka**:Kafka是一个分布式的、可分区的、可复制的、基于发布/订阅的消息系统(现在官方的描述是“一个分布式流平台”),Kafka主要用于大数据领域,当然在分布式系统中也有应用。目前市面上流行的消息队列RocketMQ就是阿里借鉴Kafka的原理、用Java开发而得。
84 |
85 | 具体可以参考:
86 |
87 | [《Kafka应用场景》](http://book.51cto.com/art/201801/565244.htm)
88 |
89 | [《初谈Kafka》](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484106&idx=1&sn=aa1999895d009d91eb3692a3e6429d18&chksm=fd9854abcaefddbd1101ca5dc2c7c783d7171320d6300d9b2d8e68b7ef8abd2b02ea03e03600#rd)
90 |
91 | **推荐阅读:**
92 |
93 | [《Kafka、RabbitMQ、RocketMQ等消息中间件的对比 —— 消息发送性能和区别》](https://mp.weixin.qq.com/s?__biz=MzU5OTMyODAyNg==&mid=2247484721&idx=1&sn=11e4e29886e581dd328311d308ccc068&chksm=feb7d144c9c058529465b02a4e26a25ef76b60be8984ace9e4a0f5d3d98ca52e014ecb73b061&scene=21#wechat_redirect)
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/闲谈/2018 秋招.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 秋招历程流水账总结
4 |
5 | 笔主大四准毕业生,在秋招末流比较幸运地进入了一家自己非常喜欢一家公司——ThoughtWorks.
6 |
7 | 
8 |
9 | 从9-6号投递出去第一份简历,到10-18号左右拿到第一份 offer ,中间差不多有 1 个半月的时间了。可能自己比较随缘,而且自己所在的大学所处的位置并不是互联网比较发达的城市的原因。所以,很少会有公司愿意跑到我们学校那边来宣讲,来的公司也大多是一些自己没听过或者不太喜欢的公司。所以,在前期,我仅仅能够通过网上投递简历的方式来找工作。
10 |
11 | 零零总总算了一下,自己在网上投了大概有 10 份左右的简历,都是些自己还算喜欢的公司。简单说一下自己投递的一些公司:网上投递的公司有:ThoughtWorks、网易、小米、携程、爱奇艺、知乎、小红书、搜狐、欢聚时代、京东;直接邮箱投递的有:烽火、中电数据、蚂蚁金服花呗部门、今日头条;线下宣讲会投递的有:玄武科技。
12 |
13 | 网上投递的大部分简历都是在做完笔试之后就没有了下文了,即使有几场笔试自我感觉做的很不错的情况下,还是没有收到后续的面试邀请。还有些邮箱投递的简历,后面也都没了回应。所以,我总共也只参加了3个公司的面试,ThoughtWorks、玄武科技和中电数据,都算是拿到了 offer。拿到 ThoughtWorks 的 offer之后,后面的一些笔试和少部分面试都拒了。决定去 ThoughtWorks 了,春招的大部队会没有我的存在。
14 |
15 |
16 | 我个人对 ThoughtWorks 最有好感,ThoughtWorks 也是我自己之前很想去的一家公司。不光是因为我投递简历的时候可以不用重新填一遍表格可以直接发送我已经编辑好的PDF格式简历的友好,这个公司的文化也让我很喜欢。每次投递一家公司几乎都要重新填写一遍简历真的很让人头疼,即使是用牛客网的简历助手也还是有很多东西需要自己重新填写。
17 |
18 | 说句实话,自己在拿到第一份 offer 之前心里还是比较空的,虽然说对自己还是比较自信。包括自己当时来到武汉的原因,也是因为自己没有 offer ,就感觉心里空空的,我相信很多人在这个时候与我也有一样的感觉。然后,我就想到武汉参加一下别的学校宣讲会。现在看来,这个决定也是不必要的,因为我最后去的公司 ThoughtWorks,虽然就在我租的房子的附近,但之前投递的时候,选择的还是远程面试。来到武汉,简单的修整了一下之后,我就去参加了玄武科技在武理工的宣讲会,顺便做了笔试,然后接着就是技术面、HR面、高管面。总体来说,玄武科技的 HR 真的很热情,为他们点个赞,虽然自己最后没能去玄武科技,然后就是技术面非常简单,HR面和高管面也都还好,不会有压抑的感觉,总体聊得很愉快。需要注意的是 玄武科技和很多公司一样都有笔试中有逻辑题,我之前没有做过类似的题,所以当时第一次做有点懵逼。高管面的时候,高管还专门在我做的逻辑题上聊了一会,让我重新做了一些做错的题,并且给他讲一些题的思路,可以看出高层对于应聘者的这项能力还是比较看重的。
19 |
20 |
21 |
22 | 中电数据的技术面试是电话进行的,花了1个多小时一点,个人感觉问的还是比较深的,感觉自己总体回答的还是比较不错的。
23 |
24 | 这里我着重说一下 ThoughtWorks,也算是给想去 ThoughtWorks 的同学一点小小的提示。我是 9.11 号在官网:https://join.thoughtworks.cn/ 投递的简历,9.20 日邮件通知官网下载作业,作业总体来说不难,9.21 号花了半天多的时间做完,然后就直接在9.21 号下午提交了。然后等了挺长时间的,可能是因为 ThoughtWorks 在管理方面比较扁平化的原因,所以总体来说效率可能不算高。因为我选的是远程面试,所以直接下载好 zoom 之后,等HR打电话过来告诉你一个房间号,你就可以直接进去面试就好,一般技术面试有几个人看着你。技术面试的内容,首先就是在面试官让你在你之前做的作业的基础上新增加一个或者两个功能(20分钟)。所以,你在技术面试之前一定要保证你的程序的扩展性是不错的,另外就是你在技术面试之前最好能重构一下自己写的程序。重构本身就是你自己对你写的程序的理解加强很好的一种方式,另外重构也能让你发现你的程序的一些小问题。然后,这一步完成之后,面试官可能会问你一些基础问题,比较简单,所以我觉得 ThoughtWorks 可能更看重你的代码质量。ThoughtWorks 的 HR 面和其他公司的唯一不同可能在于,他会让你用英语介绍一下自己或者说自己的技术栈啊这些。
25 |
26 | 
27 |
28 |
29 | # 关于面试一些重要的问题总结
30 | 另外,再给大家总结一些我个人想到一些关于面试非常重要的一些问题。
31 |
32 | ### 面试前
33 |
34 | **如何准备**
35 |
36 |
37 | 运筹帷幄之后,决胜千里之外!不打毫无准备的仗,我觉得大家可以先从下面几个方面来准备面试:
38 |
39 | 1. 自我介绍。(你可千万这样介绍:“我叫某某,性别,来自哪里,学校是那个,自己爱干什么”,记住:多说点简历上没有的,多说点自己哪里比别人强!)
40 | 2. 自己面试中可能涉及哪些知识点、那些知识点是重点。
41 | 3. 面试中哪些问题会被经常问到、面试中自己改如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
42 | 4. 自己的简历该如何写。
43 |
44 |
45 |
46 | 另外,如果你想去类似阿里巴巴、腾讯这种比较大的互联网公司的话,一定要尽早做打算。像阿里巴巴在7月份左右就开始了提前批招聘,到了9月份差不多就已经招聘完毕了。所以,秋招没有参加到阿里的面试还是很遗憾的,毕竟面试即使失败了,也能从阿里难度Max的面试中学到很多东西。
47 |
48 | **关于着装**
49 |
50 | 穿西装、打领带、小皮鞋?NO!NO!NO!这是互联网公司面试又不是去走红毯,所以你只需要穿的简单大方就好,不需要太正式。
51 |
52 | **关于自我介绍**
53 |
54 | 如果你简历上写的基本信息就不要说了,比如性别、年龄、学校。另外,你也不要一上来就说自己爱好什么这方面内容。因为,面试官根本不关心这些东西。你直接挑和你岗位相关的重要经历和自己最突出的特点讲就好了。
55 |
56 |
57 |
58 | **提前准备**
59 |
60 | 面试之前可以在网上找找有没有你要面试的公司的面经。在我面试 ThoughtWorks 的前几天我就在网上找了一些关于 ThoughtWorks 的技术面的一些文章。然后知道了 ThoughtWorks 的技术面会让我们在之前做的作业的基础上增加一个或两个功能,所以我提前一天就把我之前做的程序重新重构了一下。然后在技术面的时候,简单的改了几行代码之后写个测试就完事了。如果没有提前准备,我觉得 20 分钟我很大几率会完不成这项任务。
61 |
62 |
63 | ### 面试中
64 |
65 | 面试的时候一定要自信,千万不要怕自己哪里会答不出来,或者说某个问题自己忘记怎么回答了。面试过程中,很多问题可能是你之前没有碰到过的,这个时候你就要通过自己构建的知识体系来思考这些问题。如果某些问题你回答不上来,你也可以让面试官给你简单的提示一下。总之,你要自信,你自信的前提是自己要做好充分的准备。下面给大家总结一些面试非常常见的问题:
66 |
67 | - SpringMVC 工作原理
68 | - 说一下自己对 IOC 、AOP 的理解
69 | - Spring 中用到了那些设计模式,讲一下自己对于这些设计模式的理解
70 | - Spring Bean 的作用域和生命周期了解吗
71 | - Spring 事务中的隔离级别
72 | - Spring 事务中的事务传播行为
73 | - 手写一个 LRU 算法
74 | - 知道那些排序算法,简单介绍一下快排的原理,能不能手写一下快排
75 | - String 为什么是不可变的?String为啥要设计为不可变的?
76 | - Arraylist 与 LinkedList 异同
77 | - HashMap的底层实现
78 | - HashMap 的长度为什么是2的幂次方
79 | - ConcurrentHashMap 和 Hashtable 的区别
80 | - ConcurrentHashMap线程安全的具体实现方式/底层具体实现
81 | - 如果你的简历写了redis 、dubbo、zookeeper、docker的话,面试官还会问一下这些东西。比如redis可能会问你:为什么要用 redis、为什么要用 redis 而不用 map/guava 做缓存、redis 常见数据结构以及使用场景分析、 redis 设置过期时间、redis 内存淘汰机制、 redis 持久化机制、 缓存雪崩和缓存穿透问题、如何解决 Redis 的并发竞争 Key 问题、如何保证缓存与数据库双写时的数据一致性。
82 | - 一些简单的 Linux 命令。
83 | - 为什么要用 消息队列
84 | - 关于 Java多线程,在面试的时候,问的比较多的就是①悲观锁和乐观锁②synchronized 和 ReenTrantLock 区别以及 volatile 和 synchronized 的区别,③可重入锁与非可重入锁的区别、④多线程是解决什么问题的、⑤线程池解决什么问题,为什么要用线程池 ⑥Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 ReenTrantLock 对比;⑦线程池使用时的注意事项、⑧AQS 原理以及 AQS 同步组件:Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock、⑨ReentranLock源码,设计原理,整体过程 等等问题。
85 | - 关于 Java 虚拟机问的比较多的是:①Java内存区域、②虚拟机垃圾算法、③虚拟机垃圾收集器、④JVM内存管理、⑤JVM调优这些问题。
86 |
87 |
88 | ### 面试后
89 |
90 | 如果失败,不要灰心;如果通过,切勿狂喜。面试和工作实际上是两回事,可能很多面试未通过的人,工作能力比你强的多,反之亦然。我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/闲谈/JavaGithubTrending/2018-12.md:
--------------------------------------------------------------------------------
1 | 本文数据统计于 1.1 号凌晨,由 SnailClimb 整理。
2 |
3 | ### 1. JavaGuide
4 |
5 | - **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
6 | - **star**: 18.2k
7 | - **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
8 |
9 | 
10 |
11 | 概览:
12 |
13 | 
14 |
15 | ### 2. mall
16 |
17 | - **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
18 | - **star**: 3.3k
19 | - **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
20 |
21 | 
22 |
23 | 概览:
24 |
25 | 
26 |
27 | ### 3. advanced-java
28 |
29 | - **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
30 | - **star**: 3.3k
31 | - **介绍**: 互联网 Java 工程师进阶知识完全扫盲
32 |
33 | 
34 |
35 | 概览:
36 |
37 | 
38 |
39 | ### 4. matrix
40 |
41 | - **Github地址**:[https://github.com/Tencent/matrix](https://github.com/Tencent/matrix)
42 | - **star**: 2.5k
43 | - **介绍**: Matrix 是一款微信研发并日常使用的 APM(Application Performance Manage),当前主要运行在 Android 平台上。 Matrix 的目标是建立统一的应用性能接入框架,通过各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。
44 |
45 | 
46 |
47 | ### 5. miaosha
48 |
49 | - **Github地址**:[https://github.com/qiurunze123/miaosha](https://github.com/qiurunze123/miaosha)
50 | - **star**: 2.4k
51 | - **介绍**: 高并发大流量如何进行秒杀架构,我对这部分知识做了一个系统的整理,写了一套系统。
52 |
53 | 
54 |
55 | ### 6. arthas
56 |
57 | - **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
58 | - **star**: 8.2k
59 | - **介绍**: Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
60 |
61 | 
62 |
63 | ### 7 spring-boot
64 |
65 | - **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
66 | - **star:** 32.6k
67 | - **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
68 |
69 | **关于Spring Boot官方的介绍:**
70 |
71 | > Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”…Most Spring Boot applications need very little Spring configuration.(Spring Boot可以轻松创建独立的生产级基于Spring的应用程序,只要通过 “just run”(可能是run ‘Application’或java -jar 或 tomcat 或 maven插件run 或 shell脚本)便可以运行项目。大部分Spring Boot项目只需要少量的配置即可)
72 |
73 | 
74 |
75 | ### 8. tutorials
76 |
77 | - **Github地址**:[https://github.com/eugenp/tutorials](https://github.com/eugenp/tutorials)
78 | - **star**: 10k
79 | - **介绍**: 该项目是一系列小而专注的教程 - 每个教程都涵盖Java生态系统中单一且定义明确的开发领域。 当然,它们的重点是Spring Framework - Spring,Spring Boot和Spring Securiyt。 除了Spring之外,还有以下技术:核心Java,Jackson,HttpClient,Guava。
80 |
81 | 
82 |
83 | ### 9. qmq
84 |
85 | - **Github地址**:[https://github.com/qunarcorp/qmq](https://github.com/qunarcorp/qmq)
86 | - **star**: 1.1k
87 | - **介绍**: QMQ是去哪儿网内部广泛使用的消息中间件,自2012年诞生以来在去哪儿网所有业务场景中广泛的应用,包括跟交易息息相关的订单场景; 也包括报价搜索等高吞吐量场景。
88 |
89 | 
90 |
91 | ### 10. symphony
92 |
93 | - **Github地址**:[https://github.com/b3log/symphony](https://github.com/b3log/symphony)
94 | - **star**: 9k
95 | - **介绍**: 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台。
96 |
97 | 
98 |
99 | ### 11. incubator-dubbo
100 |
101 | - **Github地址**:[https://github.com/apache/incubator-dubbo](https://github.com/apache/incubator-dubbo)
102 | - **star**: 23.6k
103 | - **介绍**: 阿里开源的一个基于Java的高性能开源RPC框架。
104 |
105 | 
106 |
107 | ### 12. apollo
108 |
109 | - **Github地址**:[https://github.com/ctripcorp/apollo](https://github.com/ctripcorp/apollo)
110 | - **star**: 10k
111 | - **介绍**: Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
112 |
113 | 
--------------------------------------------------------------------------------
/闲谈/JavaGithubTrending/2019-1.md:
--------------------------------------------------------------------------------
1 | ### 1. JavaGuide
2 |
3 | - **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
4 | - **star**: 22.8k
5 | - **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
6 |
7 | 
8 |
9 | **概览:**
10 |
11 | 
12 |
13 | ### 2. advanced-java
14 |
15 | - **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
16 | - **star**: 7.9k
17 | - **介绍**: 互联网 Java 工程师进阶知识完全扫盲
18 |
19 | 
20 |
21 | **概览:**
22 |
23 | 
24 |
25 | ### 3. fescar
26 |
27 | - **Github地址**:[https://github.com/alibaba/fescar](https://github.com/alibaba/fescar)
28 | - **star**: 4.6k
29 | - **介绍**: 具有 **高性能** 和 **易用性** 的 **微服务架构** 的 **分布式事务** 的解决方案。(特点:高性能且易于使用,旨在实现简单并快速的事务提交与回滚。)关于 fescar 的更详细介绍可以查看:[Github 上日获 800多 star 的阿里微服务架构分布式事务解决方案 FESCAR开源啦](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484888&idx=2&sn=ff9fe077c95959ec777c866a425bddbe&chksm=fd9853b9caefdaaf52a1b7caecc697938c2c1c5f6916527d1309ef01aba70c6546bdba6a9657&token=96044853&lang=zh_CN#rd)
30 |
31 | 
32 |
33 | ### 4. mall
34 |
35 | - **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
36 | - **star**: 5.6 k
37 | - **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
38 |
39 | 
40 |
41 | **概览:**
42 |
43 | 
44 |
45 | ### 5. miaosha
46 |
47 | - **Github地址**:[https://github.com/qiurunze123/miaosha](https://github.com/qiurunze123/miaosha)
48 | - **star**: 4.4k
49 | - **介绍**: 高并发大流量如何进行秒杀架构,我对这部分知识做了一个系统的整理,写了一套系统。
50 |
51 | 
52 |
53 | ### 6. flink
54 |
55 | - **Github地址**:[https://github.com/apache/flink](https://github.com/apache/flink)
56 | - **star**: 7.1 k
57 | - **介绍**: Apache Flink是一个开源流处理框架,具有强大的流和批处理功能。
58 |
59 | 
60 |
61 | 关于Flink 更加详细的介绍可以查看这篇文章:https://www.cnblogs.com/feiyudemeng/p/8998772.html
62 |
63 | ### 7. cim
64 |
65 | - **Github地址**:[https://github.com/crossoverJie/cim](https://github.com/crossoverJie/cim)
66 | - **star**: 1.8 k
67 | - **介绍**: cim(cross IM) 适用于开发者的即时通讯系统。
68 |
69 | 
70 |
71 | **系统架构:**
72 |
73 | 
74 |
75 | ### 8. symphony
76 |
77 | - **Github地址**:[https://github.com/b3log/symphony](https://github.com/b3log/symphony)
78 | - **star**: 10k
79 | - **介绍**: 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台。
80 |
81 | 
82 |
83 | ### 9. spring-boot
84 |
85 | - **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
86 | - **star:** 32.6k
87 | - **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
88 |
89 | **关于Spring Boot官方的介绍:**
90 |
91 | > Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”…Most Spring Boot applications need very little Spring configuration.(Spring Boot可以轻松创建独立的生产级基于Spring的应用程序,只要通过 “just run”(可能是run ‘Application’或java -jar 或 tomcat 或 maven插件run 或 shell脚本)便可以运行项目。大部分Spring Boot项目只需要少量的配置即可)
92 |
93 | 
94 |
95 | ### 10. arthas
96 |
97 | - **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
98 | - **star**: 9.5k
99 | - **介绍**: Arthas 是Alibaba开源的Java诊断工具。
100 |
101 | 
102 |
103 | **概览:**
104 |
105 | 当你遇到以下类似问题而束手无策时,`Arthas`可以帮助你解决:
106 |
107 | 0. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
108 | 1. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
109 | 2. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
110 | 3. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
111 | 4. 是否有一个全局视角来查看系统的运行状况?
112 | 5. 有什么办法可以监控到JVM的实时运行状态?
113 |
114 | `Arthas`支持JDK 6+,支持Linux/Mac/Winodws,采用命令行交互模式,同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。
--------------------------------------------------------------------------------
/闲谈/JavaGithubTrending/2019-2.md:
--------------------------------------------------------------------------------
1 | ### 1. JavaGuide
2 |
3 | - **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
4 | - **Star**: 27.2k (4,437 stars this month)
5 | - **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
6 |
7 | ### 2.DoraemonKit
8 |
9 | - **Github地址**:
10 | - **Star**: 5.2k (3,786 stars this month)
11 | - **介绍**: 简称 "DoKit" 。一款功能齐全的客户端( iOS 、Android )研发助手,你值得拥有。
12 |
13 | ### 3.advanced-java
14 |
15 | - **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
16 | - **Star**:11.2k (3,042 stars this month)
17 | - **介绍**: 互联网 Java 工程师进阶知识完全扫盲。
18 |
19 | ### 4. spring-boot-examples
20 |
21 | - **Github地址**:
22 | - **star**: 9.6 k (1,764 stars this month)
23 | - **介绍**: Spring Boot 教程、技术栈示例代码,快速简单上手教程。
24 |
25 | ### 5. mall
26 |
27 | - **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
28 | - **star**: 7.4 k (1,736 stars this month)
29 | - **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
30 |
31 | ### 6. fescar
32 |
33 | - **Github地址**:[https://github.com/alibaba/fescar](https://github.com/alibaba/fescar)
34 | - **star**: 6.0 k (1,308 stars this month)
35 | - **介绍**: 具有 **高性能** 和 **易用性** 的 **微服务架构** 的 **分布式事务** 的解决方案。(特点:高性能且易于使用,旨在实现简单并快速的事务提交与回滚。)
36 |
37 | ### 7. h4cker
38 |
39 | - **Github地址**:
40 | - **star**: 2.1 k (1,303 stars this month)
41 | - **介绍**: 该仓库主要由Omar Santos维护,包括与道德黑客/渗透测试,数字取证和事件响应(DFIR),漏洞研究,漏洞利用开发,逆向工程等相关的资源。
42 |
43 | ### 8. spring-boot
44 |
45 | - **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
46 | - **star:** 34.8k (1,073 stars this month)
47 | - **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
48 |
49 | **关于Spring Boot官方的介绍:**
50 |
51 | > Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can “just run”…Most Spring Boot applications need very little Spring configuration.(Spring Boot可以轻松创建独立的生产级基于Spring的应用程序,只要通过 “just run”(可能是run ‘Application’或java -jar 或 tomcat 或 maven插件run 或 shell脚本)便可以运行项目。大部分Spring Boot项目只需要少量的配置即可)
52 |
53 | ### 9. arthas
54 |
55 | - **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
56 | - **star**: 10.5 k (970 stars this month)
57 | - **介绍**: Arthas 是Alibaba开源的Java诊断工具。
58 |
59 | ### 10. tutorials
60 |
61 | - **Github地址**:[https://github.com/eugenp/tutorials](https://github.com/eugenp/tutorials)
62 | - **star**: 12.1 k (789 stars this month)
63 | - **介绍**: 该项目是一系列小而专注的教程 - 每个教程都涵盖Java生态系统中单一且定义明确的开发领域。 当然,它们的重点是Spring Framework - Spring,Spring Boot和Spring Securiyt。 除了Spring之外,还有以下技术:核心Java,Jackson,HttpClient,Guava。
64 |
65 |
--------------------------------------------------------------------------------
/闲谈/JavaGithubTrending/JavaGithubTrending.md:
--------------------------------------------------------------------------------
1 | - [2018 年 12 月](https://github.com/Snailclimb/JavaGuide/blob/master/闲谈/JavaGithubTrending/2018-12.md)
2 | - [2019 年 1 月](https://github.com/Snailclimb/JavaGuide/blob/master/闲谈/JavaGithubTrending/2019-1.md)
3 | - [2019 年 2 月](https://github.com/Snailclimb/JavaGuide/blob/master/闲谈/JavaGithubTrending/2019-2.md)
4 |
5 |
--------------------------------------------------------------------------------
/闲谈/个人阅读书籍清单.md:
--------------------------------------------------------------------------------
1 | 下面是个人阅读书籍的部分清单,我比较建议阅读的书籍前都加上了:thumbsup: 表情。
2 | > ### 核心基础知识
3 |
4 | - :thumbsup: [《图解HTTP》](https://book.douban.com/subject/25863515/)
5 |
6 | 讲漫画一样的讲HTTP,很有意思,不会觉得枯燥,大概也涵盖也HTTP常见的知识点。因为篇幅问题,内容可能不太全面。不过,如果不是专门做网络方向研究的小伙伴想研究HTTP相关知识的话,读这本书的话应该来说就差不多了。
7 |
8 | > ### Java相关
9 |
10 | - :thumbsup: [《Head First Java.第二版》](https://book.douban.com/subject/2000732/)
11 |
12 | 可以说是我的Java启蒙书籍了,特别适合新手读当然也适合我们用来温故Java知识点。
13 |
14 | - [《Java多线程编程核心技术》](https://book.douban.com/subject/26555197/)
15 |
16 | Java多线程入门级书籍还不错,但是说实话,质量不是很高,很快就可以阅读完。
17 |
18 | - [《JAVA网络编程 第4版》](https://book.douban.com/subject/26259017/)
19 |
20 | 可以系统的学习一下网络的一些概念以及网络编程在Java中的使用。
21 |
22 | - :thumbsup: [《Java核心技术卷1+卷2》](https://book.douban.com/subject/25762168/)
23 |
24 | 很棒的两本书,建议有点Java基础之后再读,介绍的还是比较深入的,非常推荐。这两本书我一般也会用来巩固知识点,是两本适合放在自己身边的好书。
25 |
26 | - :thumbsup: [《Java编程思想(第4版)》](https://book.douban.com/subject/2130190/)
27 |
28 | 这本书要常读,初学者可以快速概览,中等程序员可以深入看看java,老鸟还可以用之回顾java的体系。这本书之所以厉害,因为它在无形中整合了设计模式,这本书之所以难读,也恰恰在于他对设计模式的整合是无形的。
29 |
30 | - :thumbsup: [《Java并发编程的艺术》](https://book.douban.com/subject/26591326/)
31 |
32 | 这本书不是很适合作为Java并发入门书籍,需要具备一定的JVM基础。我感觉有些东西讲的还是挺深入的,推荐阅读。
33 | - :thumbsup: [《实战Java高并发程序设计》](https://book.douban.com/subject/26663605/)
34 |
35 | 豆瓣评分 8.3 ,书的质量没的说,推荐大家好好看一下。
36 |
37 | - [《Java程序员修炼之道》](https://book.douban.com/subject/24841235/)
38 |
39 | 很杂,我只看了前面几章,不太推荐阅读。
40 |
41 | - :thumbsup: [《深入理解Java虚拟机(第2版)周志明》](https://book.douban.com/subject/24722612/)
42 |
43 | 神书!神书!神书!建议多刷几遍,书中的所有知识点可以通过JAVA运行时区域和JAVA的内存模型与线程两个大模块罗列完全。
44 |
45 | > ### JavaWeb相关
46 |
47 | - :thumbsup: [《深入分析Java Web技术内幕》](https://book.douban.com/subject/25953851/)
48 |
49 | 感觉还行,涉及的东西也蛮多,推荐阅读。
50 |
51 | - :thumbsup: [《Spring实战(第4版)》](https://book.douban.com/subject/26767354/)
52 |
53 | 不建议当做入门书籍读,入门的话可以找点国人的书或者视频看。这本定位就相当于是关于Spring的新华字典,只有一些基本概念的介绍和示例,涵盖了Spring的各个方面,但都不够深入。就像作者在最后一页写的那样:“学习Spring,这才刚刚开始”。
54 |
55 | - [《Java Web整合开发王者归来》](https://book.douban.com/subject/4189495/)
56 |
57 | 当时刚开始学的时候就是开的这本书,基本上是完完整整的看完了。不过,我不是很推荐大家看。这本书比较老了,里面很多东西都已经算是过时了。不过,这本书的一个很大优点是:基础知识点概括全面。
58 |
59 | - :thumbsup: [《Redis实战》](https://book.douban.com/subject/26612779/)
60 |
61 | 如果你想了解Redis的一些概念性知识的话,这本书真的非常不错。
62 |
63 | > ### 架构相关
64 |
65 | - :thumbsup: [《大型网站技术架构:核心原理与案例分析+李智慧》](https://book.douban.com/subject/25723064/)
66 |
67 | 这本书我读过,基本不需要你有什么基础啊~读起来特别轻松,但是却可以学到很多东西,非常推荐了。另外我写过这本书的思维导图,关注我的微信公众号:“Java面试通关手册”回复“大型网站技术架构”即可领取思维导图。
68 |
69 | - [《架构解密从分布式到微服务(Leaderus著)》](https://book.douban.com/subject/27081188/)
70 |
71 | 很一般的书籍,我就是当做课后图书来阅读的。
72 |
73 | > ### 代码优化
74 |
75 | - :thumbsup: [《重构_改善既有代码的设计》](https://book.douban.com/subject/4262627/)
76 |
77 | 豆瓣 9.1 分,重构书籍的开山鼻祖。
78 | > ### linux操作系统相关
79 | - :thumbsup:[<>](https://book.douban.com/subject/25900403/) :thumbsup: [<>](https://book.douban.com/subject/1500149/)
80 |
81 | 对于理解linux操作系统原理非常有用,同时可以打好个人的基本功力,面试中很多公司也会问到linux知识。
82 | > ### 课外书籍
83 |
84 | 《技术奇点》 :thumbsup:《追风筝的人》 :thumbsup:《穆斯林的葬礼》 :thumbsup:《三体》 《人工智能——李开复》
85 | :thumbsup:《活着——余华》
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/闲谈/选择技术方向都要考虑哪些因素.md:
--------------------------------------------------------------------------------
1 | 本文主要是作者读安晓辉老师的《程序员程序员职场进阶 32 讲 》中关于“选择技术方向都要考虑哪些因素”这部分做的一些笔记和自己的思考。在这里分享给各位!
2 |
3 | ### 选择一种技术可能会考虑到的决定因素
4 |
5 | 1. 就业机会
6 |
7 | 选择一门就业面广的技术还是比较重要的。我的很多学PHP的同学现在都在培训班学Java,真的!!!
8 | 2. 难易程度
9 |
10 | 我当时是在C/C++语言与Java中选择了Java,因为我感觉Java学起来确实要比C++简单一些。
11 | 3. 个人兴趣
12 |
13 | 兴趣是你能坚持下来的一个很重要的条件。
14 | 4. 薪资水平
15 |
16 | 薪资虽然不是人的唯一追求,但是一定是必备的追求。
17 | 5. 发展前景
18 |
19 | 你肯定不愿意看到这种情况发生:选择了一门技术,结果一年后它就没人用、没市场了。所以我们在选择时就要考虑这一点,做一些预判。
20 |
21 | 选择技术时存在两种考虑:一种是选择稳定的、经典的技术;一种是卡位将来的市场缺口,选择将来可能需要用到的技术。
22 | 6. 他人推荐
23 |
24 | 我们在懵懵懂懂的时候,往往最容易听从别人的推荐,然后选择某种技术。
25 | 7. 相近原则
26 |
27 | 当我们已经掌握了一些技术,要学习新技术时,就可以根据一种新技术是否和自己已经掌握的技术比较接近来判断选择。相近的技术,学起来会更容易上手。
28 | 8. 互补原则
29 |
30 | 和相近性类似,互补性也常用在拓展我们技术能力的情景下。它指的是,有一些技术可以和你已经掌握的技术互相补充,组合在一起,形成更完整、更系统的技术图谱,给你带来更大的竞争力。关于相近原则与互补原则,我们也会在后面的文章里具体解读。
31 | 9. 团队技术图谱
32 |
33 | 我觉得这个可能就是团队开发过程中的需要。比如在做一个项目的时候,这个项目需要你去学习一下某个你没有接触过的新技术。
34 |
35 | ### 入行时如何选择技术方向
36 |
37 | 为了明确自己的求职目标,可以问问自己下面的问题:
38 | - 我想在哪个城市工作?
39 | - 我想在哪些行业、领域发展?
40 | - 我想去什么样的公司?
41 | - 我想做什么样的产品?
42 |
43 | 另外你要知道的是热门技术会有更多机会,相应竞争压力也会更大,并不能保证你找到合适的工作。
44 | 冷门技术,机会相对较少,而且机会相对确定 。
45 |
46 | ### 构建技能树时如何选择技术方向
47 |
48 | 当我们过了专项能力提升的初级阶段之后,就应该开始构建自己的技能体系了。在为搭建技能树而选择技术时,通常考虑下面两个原则:
49 | - 相近原则
50 | - 互补原则
51 |
52 | “学习技术时一定要学对自己以后发展有用的技术”是我经常对自己强调的,另外我觉得很误导人同时也很错误的一个思想是:“只要是技术学了就会有用的”,这句话在我刚学编程时经常听到有人对我说。希望大家不要被误导,很多技术过时了就是过时了,没有必要再去花时间学。
53 |
54 | 我觉得相近原则和互补原则互补原则就是你主精和自己技术方向相同的的东西或者对自己技术领域有提升的东西。比如我目前暂时选择了Java为我的主要发展语言,所以我就要求自己大部分时间还是搞和Java相关的东西比如:Spring、SpingBoot、Dubbo、Mybatis等等。但是千万不要被语言所束缚,在业余时间我学的比较多的就是Python以及JS、C/C++/C#也会偶尔接触。因为我经常会接触前端另外我自己偶尔有爬虫需求或者需要用Python的一些第三库解决一些问题,所以我业余学Pyton以及JS就比较多一点,我觉得这两门技术也是对我现有技术的一个补充了。
55 |
56 |
57 | ### 技术转型时的方向选择
58 |
59 | 我觉得对于技术转型主要有一下几点建议
60 |
61 | - 与自己当前技术栈跨度不太大的领域,比如你做安卓的话转型可以选择做Java后端。
62 | - 真正适合自己去做的,并不是一味看着这个领域火了(比如人工智能),然后自己就不考虑实际的去转型到这个领域里去。
63 | - 技术转型方向尽量对自己以后的发展需要有帮助。
64 |
--------------------------------------------------------------------------------