diff --git a/.gitattributes b/.gitattributes
index 05d15409683..2ab2d3c5962 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,5 +1,4 @@
-# Auto detect text files and perform LF normalization
* text=auto
*.js linguist-language=java
*.css linguist-language=java
-*.html linguist-language=java
\ No newline at end of file
+*.html linguist-language=java
diff --git "a/Java\347\233\270\345\205\263/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/Java\347\233\270\345\205\263/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
deleted file mode 100644
index 17335c950ef..00000000000
--- "a/Java\347\233\270\345\205\263/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
+++ /dev/null
@@ -1,440 +0,0 @@
-
-
-- [1. 面向对象和面向过程的区别](#1-面向对象和面向过程的区别)
- - [面向过程](#面向过程)
- - [面向对象](#面向对象)
-- [2. Java 语言有哪些特点](#2-java-语言有哪些特点)
-- [3. 什么是 JDK 什么是 JRE 什么是 JVM 三者之间的联系与区别](#3-什么是-jdk-什么是-jre-什么是-jvm-三者之间的联系与区别)
-- [4. 什么是字节码 采用字节码的最大好处是什么](#4-什么是字节码-采用字节码的最大好处是什么)
- - [先看下 java 中的编译器和解释器:](#先看下-java-中的编译器和解释器:)
- - [采用字节码的好处:](#采用字节码的好处:)
-- [5. Java和C++的区别](#5-java和c的区别)
-- [6. 什么是 Java 程序的主类 应用程序和小程序的主类有何不同](#6-什么是-java-程序的主类-应用程序和小程序的主类有何不同)
-- [7. Java 应用程序与小程序之间有那些差别](#7-java-应用程序与小程序之间有那些差别)
-- [8. 字符型常量和字符串常量的区别](#8-字符型常量和字符串常量的区别)
-- [9. 构造器 Constructor 是否可被 override](#9-构造器-constructor-是否可被-override)
-- [10. 重载和重写的区别](#10-重载和重写的区别)
-- [11. Java 面向对象编程三大特性:封装、继承、多态](#11-java-面向对象编程三大特性封装、继承、多态)
- - [封装](#封装)
- - [继承](#继承)
- - [多态](#多态)
-- [12. String 和 StringBuffer、StringBuilder 的区别是什么 String 为什么是不可变的](#12-string-和-stringbuffer、stringbuilder-的区别是什么-string-为什么是不可变的)
-- [13. 自动装箱与拆箱](#13-自动装箱与拆箱)
-- [14. 在一个静态方法内调用一个非静态成员为什么是非法的](#14-在一个静态方法内调用一个非静态成员为什么是非法的)
-- [15. 在 Java 中定义一个不做事且没有参数的构造方法的作用](#15-在-java-中定义一个不做事且没有参数的构造方法的作用)
-- [16. import java和javax有什么区别](#16-import-java和javax有什么区别)
-- [17. 接口和抽象类的区别是什么](#17-接口和抽象类的区别是什么)
-- [18. 成员变量与局部变量的区别有那些](#18-成员变量与局部变量的区别有那些)
-- [19. 创建一个对象用什么运算符?对象实体与对象引用有何不同?](#19-创建一个对象用什么运算符?对象实体与对象引用有何不同?)
-- [20. 什么是方法的返回值?返回值在类的方法里的作用是什么?](#20-什么是方法的返回值?返回值在类的方法里的作用是什么?)
-- [21. 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 为什么](#21-一个类的构造方法的作用是什么-若一个类没有声明构造方法,该程序能正确执行吗-为什么)
-- [22. 构造方法有哪些特性](#22-构造方法有哪些特性)
-- [23. 静态方法和实例方法有何不同](#23-静态方法和实例方法有何不同)
-- [24. 对象的相等与指向他们的引用相等,两者有什么不同?](#24-对象的相等与指向他们的引用相等,两者有什么不同?)
-- [25. 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?](#25-在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?)
-- [26. == 与 equals\(重要\)](#26--与-equals重要)
-- [27. hashCode 与 equals(重要)](#27-hashcode-与-equals(重要))
- - [hashCode()介绍](#hashcode()介绍)
- - [为什么要有 hashCode](#为什么要有-hashcode)
- - [hashCode()与equals()的相关规定](#hashcode()与equals()的相关规定)
-- [28. 为什么Java中只有值传递](#28-为什么java中只有值传递)
-- [29. 简述线程,程序、进程的基本概念。以及他们之间关系是什么](#29-简述线程,程序、进程的基本概念。以及他们之间关系是什么)
-- [30. 线程有哪些基本状态?这些状态是如何定义的?](#30-线程有哪些基本状态?这些状态是如何定义的)
-- [31 关于 final 关键字的一些总结](#31-关于-final-关键字的一些总结)
-- [32 Java 中的异常处理](#32-java-中的异常处理)
- - [Java异常类层次结构图](#java异常类层次结构图)
- - [Trowable类常用方法](#trowable类常用方法)
- - [异常处理总结](#异常处理总结)
-- [33 Java序列话中如果有些字段不想进行序列化 怎么办](#33-java序列话中如果有些字段不想进行序列化-怎么办)
-- [Java基础学习书籍推荐](#java基础学习书籍推荐)
-
-
-
-## 1. 面向对象和面向过程的区别
-
-### 面向过程
-
-**优点:** 性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
-
-**缺点:** 没有面向对象易维护、易复用、易扩展
-
-### 面向对象
-
-**优点:** 易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
-
-**缺点:** 性能比面向过程低
-
-## 2. Java 语言有哪些特点
-
-1. 简单易学;
-2. 面向对象(封装,继承,多态);
-3. 平台无关性( Java 虚拟机实现平台无关性);
-4. 可靠性;
-5. 安全性;
-6. 支持多线程( C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);
-7. 支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);
-8. 编译与解释并存;
-
-## 3. 什么是 JDK 什么是 JRE 什么是 JVM 三者之间的联系与区别
-
-这几个是Java中很基本很基本的东西,但是我相信一定还有很多人搞不清楚!为什么呢?因为我们大多数时候在使用现成的编译工具以及环境的时候,并没有去考虑这些东西。
-
-**JDK:** 顾名思义它是给开发者提供的开发工具箱,是给程序开发者用的。它除了包括完整的JRE(Java Runtime Environment),Java运行环境,还包含了其他供开发者使用的工具包。
-
-**JRE:** 普通用户而只需要安装 JRE(Java Runtime Environment)来运行 Java 程序。而程序开发者必须安装JDK来编译、调试程序。
-
-**JVM:** 当我们运行一个程序时,JVM 负责将字节码转换为特定机器代码,JVM 提供了内存管理/垃圾回收和安全机制等。这种独立于硬件和操作系统,正是 java 程序可以一次编写多处执行的原因。
-
-**区别与联系:**
-
- 1. JDK 用于开发,JRE 用于运行java程序 ;
- 2. JDK 和 JRE 中都包含 JVM ;
- 3. JVM 是 java 编程语言的核心并且具有平台独立性。
-
-## 4. 什么是字节码 采用字节码的最大好处是什么
-
-### 先看下 java 中的编译器和解释器:
-
-Java 中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。
-
-编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在 Java 中,这种供虚拟机理解的代码叫做`字节码`(即扩展名为 `.class` 的文件),它不面向任何特定的处理器,只面向虚拟机。
-
-每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java 源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。这也就是解释了 Java 的编译与解释并存的特点。
-
- Java 源代码---->编译器---->jvm 可执行的 Java 字节码(即虚拟指令)---->jvm---->jvm 中解释器----->机器可执行的二进制机器码---->程序运行。
-
-### 采用字节码的好处:
-
-**Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。**
-
-> 解释性语言:解释型语言,是在运行的时候将程序翻译成机器语言。解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。——百度百科
-
-## 5. Java和C++的区别
-
-我知道很多人没学过 C++,但是面试官就是没事喜欢拿咱们 Java 和 C++ 比呀!没办法!!!就算没学过C++,也要记下来!
-
-- 都是面向对象的语言,都支持封装、继承和多态
-- Java 不提供指针来直接访问内存,程序内存更加安全
-- Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。
-- Java 有自动内存管理机制,不需要程序员手动释放无用内存
-
-
-## 6. 什么是 Java 程序的主类 应用程序和小程序的主类有何不同
-
-一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这个主类是指包含 main()方法的类。而在 Java 小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是 public 类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点。
-
-## 7. Java 应用程序与小程序之间有那些差别
-
-简单说应用程序是从主线程启动(也就是 main() 方法)。applet 小程序没有main方法,主要是嵌在浏览器页面上运行(调用init()线程或者run()来启动),嵌入浏览器这点跟 flash 的小游戏类似。
-
-## 8. 字符型常量和字符串常量的区别
-
-1. 形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的若干个字符
-2. 含义上: 字符常量相当于一个整形值( ASCII 值),可以参加表达式运算 字符串常量代表一个地址值(该字符串在内存中存放位置)
-3. 占内存大小 字符常量只占2个字节 字符串常量占若干个字节(至少一个字符结束标志) (**注意: char在Java中占两个字节**)
-
-> java编程思想第四版:2.2.2节
-
-
-## 9. 构造器 Constructor 是否可被 override
-
-在讲继承的时候我们就知道父类的私有属性和构造方法并不能被继承,所以 Constructor 也就不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。
-
-## 10. 重载和重写的区别
-
-**重载:** 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
-
-**重写:** 发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
-
-## 11. Java 面向对象编程三大特性:封装、继承、多态
-
-### 封装
-
-封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
-
-
-### 继承
-继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。
-
-**关于继承如下 3 点请记住:**
-
-1. 子类拥有父类非 private 的属性和方法。
-2. 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
-3. 子类可以用自己的方式实现父类的方法。(以后介绍)。
-
-### 多态
-
-所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
-
-在Java中有两种形式可以实现多态:继承(多个子类对同一方法的重写)和接口(实现接口并覆盖接口中同一方法)。
-
-## 12. String 和 StringBuffer、StringBuilder 的区别是什么 String 为什么是不可变的
-
-**可变性**
-
-
-简单的来说:String 类中使用 final 关键字字符数组保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串`char[]value` 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
-
-StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以自行查阅源码。
-
-AbstractStringBuilder.java
-
-```java
-abstract class AbstractStringBuilder implements Appendable, CharSequence {
- char[] value;
- int count;
- AbstractStringBuilder() {
- }
- AbstractStringBuilder(int capacity) {
- value = new char[capacity];
- }
-```
-
-
-**线程安全性**
-
-String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
-
-
-**性能**
-
-每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
-
-**对于三者使用的总结:**
-1. 操作少量的数据 = String
-2. 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
-3. 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
-
-## 13. 自动装箱与拆箱
-**装箱**:将基本类型用它们对应的引用类型包装起来;
-
-**拆箱**:将包装类型转换为基本数据类型;
-
-## 14. 在一个静态方法内调用一个非静态成员为什么是非法的
-
-由于静态方法可以不通过对象进行调用,因此在静态方法里,不能调用其他非静态变量,也不可以访问非静态变量成员。
-
-## 15. 在 Java 中定义一个不做事且没有参数的构造方法的作用
- Java 程序在执行子类的构造方法之前,如果没有用 super() 来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 super() 来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
-
-## 16. import java和javax有什么区别
-
-刚开始的时候 JavaAPI 所必需的包是 java 开头的包,javax 当时只是扩展 API 包来说使用。然而随着时间的推移,javax 逐渐的扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包将是太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准API的一部分。
-
-所以,实际上java和javax没有区别。这都是一个名字。
-
-## 17. 接口和抽象类的区别是什么
-
-1. 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),抽象类可以有非抽象的方法
-2. 接口中的实例变量默认是 final 类型的,而抽象类中则不一定
-3. 一个类可以实现多个接口,但最多只能实现一个抽象类
-4. 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
-5. 接口不能用 new 实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
-
-## 18. 成员变量与局部变量的区别有那些
-
-1. 从语法形式上,看成员变量是属于类的,而局部变量是在方法中定义的变量或是方法的参数;成员变量可以被 public,private,static 等修饰符所修饰,而局部变量不能被访问控制修饰符及 static 所修饰;但是,成员变量和局部变量都能被 final 所修饰;
-2. 从变量在内存中的存储方式来看,成员变量是对象的一部分,而对象存在于堆内存,局部变量存在于栈内存
-3. 从变量在内存中的生存时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变量随着方法的调用而自动消失。
-4. 成员变量如果没有被赋初值,则会自动以类型的默认值而赋值(一种情况例外被 final 修饰但没有被 static 修饰的成员变量必须显示地赋值);而局部变量则不会自动赋值。
-
-## 19. 创建一个对象用什么运算符?对象实体与对象引用有何不同?
-
-new运算符,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)。一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球);一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)。
-
-## 20. 什么是方法的返回值?返回值在类的方法里的作用是什么?
-
-方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作!
-
-## 21. 一个类的构造方法的作用是什么 若一个类没有声明构造方法,该程序能正确执行吗 为什么
-
-主要作用是完成对类对象的初始化工作。可以执行。因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。
-
-## 22. 构造方法有哪些特性
-
-1. 名字与类名相同;
-2. 没有返回值,但不能用void声明构造函数;
-3. 生成类的对象时自动执行,无需调用。
-
-## 23. 静态方法和实例方法有何不同
-
-1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
-
-2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制.
-
-## 24. 对象的相等与指向他们的引用相等,两者有什么不同?
-
-对象的相等,比的是内存中存放的内容是否相等。而引用相等,比较的是他们指向的内存地址是否相等。
-
-## 25. 在调用子类构造方法之前会先调用父类没有参数的构造方法,其目的是?
-
-帮助子类做初始化工作。
-
-## 26. == 与 equals(重要)
-
-**==** : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
-
-**equals()** : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
-- 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
-- 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
-
-
-**举个例子:**
-
-```java
-public class test1 {
- public static void main(String[] args) {
- String a = new String("ab"); // a 为一个引用
- String b = new String("ab"); // b为另一个引用,对象的内容一样
- String aa = "ab"; // 放在常量池中
- String bb = "ab"; // 从常量池中查找
- if (aa == bb) // true
- System.out.println("aa==bb");
- if (a == b) // false,非同一对象
- System.out.println("a==b");
- if (a.equals(b)) // true
- System.out.println("aEQb");
- if (42 == 42.0) { // true
- System.out.println("true");
- }
- }
-}
-```
-
-**说明:**
-- String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
-- 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。
-
-
-
-## 27. hashCode 与 equals(重要)
-
-面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”
-
-### hashCode()介绍
-hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。
-
-散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
-
-### 为什么要有 hashCode
-
-
-**我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode:**
-
-当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head fist java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
-
-
-
-### hashCode()与equals()的相关规定
-
-1. 如果两个对象相等,则hashcode一定也是相同的
-2. 两个对象相等,对两个对象分别调用equals方法都返回true
-3. 两个对象有相同的hashcode值,它们也不一定是相等的
-4. **因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖**
-5. hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
-
-
-## 28. 为什么Java中只有值传递
-
- [为什么Java中只有值传递?](https://github.com/Snailclimb/Java-Guide/blob/master/%E9%9D%A2%E8%AF%95%E5%BF%85%E5%A4%87/%E6%9C%80%E6%9C%80%E6%9C%80%E5%B8%B8%E8%A7%81%E7%9A%84Java%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93/%E7%AC%AC%E4%B8%80%E5%91%A8%EF%BC%882018-8-7%EF%BC%89.md)
-
-
-## 29. 简述线程,程序、进程的基本概念。以及他们之间关系是什么
-
-**线程**与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
-
-**程序**是含有指令和数据的文件,被存储在磁盘或其他的数据存储设备中,也就是说程序是静态的代码。
-
-**进程**是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。简单来说,一个进程就是一个执行中的程序,它在计算机中一个指令接着一个指令地执行着,同时,每个进程还占有某些系统资源如CPU时间,内存空间,文件,文件,输入输出设备的使用权等等。换句话说,当程序在执行时,将会被操作系统载入内存中。
-线程是进程划分成的更小的运行单位。线程和进程最大的不同在于基本上各进程是独立的,而各线程则不一定,因为同一进程中的线程极有可能会相互影响。从另一角度来说,进程属于操作系统的范畴,主要是同一段时间内,可以同时执行一个以上的程序,而线程则是在同一程序内几乎同时执行一个以上的程序段。
-
-## 30. 线程有哪些基本状态?这些状态是如何定义的?
-
-1. **新建(new)**:新创建了一个线程对象。
-2. **可运行(runnable)**:线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取cpu的使用权。
-3. **运行(running)**:可运行状态(runnable)的线程获得了cpu时间片(timeslice),执行程序代码。
-4. **阻塞(block)**:阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有 机会再次获得cpu timeslice转到运行(running)状态。阻塞的情况分三种:
-(一). 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放 入等待队列(waitting queue)中。
-(二). 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁 被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
-(三). 其他阻塞: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
-5. **死亡(dead)**:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
-
-
-
-备注: 可以用早起坐地铁来比喻这个过程:
-
-还没起床:sleeping
-
-起床收拾好了,随时可以坐地铁出发:Runnable
-
-等地铁来:Waiting
-
-地铁来了,但要排队上地铁:I/O阻塞
-
-上了地铁,发现暂时没座位:synchronized阻塞
-
-地铁上找到座位:Running
-
-到达目的地:Dead
-
-## 31 关于 final 关键字的一些总结
-
-final关键字主要用在三个地方:变量、方法、类。
-
-1. 对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
-2. 当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。
-3. 使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为fianl。
-
-## 32 Java 中的异常处理
-
-### Java异常类层次结构图
-
-
- 在 Java 中,所有的异常都有一个共同的祖先java.lang包中的 **Throwable类**。Throwable: 有两个重要的子类:**Exception(异常)** 和 **Error(错误)** ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。
-
-**Error(错误):是程序无法处理的错误**,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
-
-这些错误表示故障发生于虚拟机自身、或者发生在虚拟机试图执行应用时,如Java虚拟机运行错误(Virtual MachineError)、类定义错误(NoClassDefFoundError)等。这些错误是不可查的,因为它们在应用程序的控制和处理能力之 外,而且绝大多数是程序运行时不允许出现的状况。对于设计合理的应用程序来说,即使确实发生了错误,本质上也不应该试图去处理它所引起的异常状况。在 Java中,错误通过Error的子类描述。
-
-**Exception(异常):是程序本身可以处理的异常**。Exception 类有一个重要的子类 **RuntimeException**。RuntimeException 异常由Java虚拟机抛出。**NullPointerException**(要访问的变量没有引用任何对象时,抛出该异常)、**ArithmeticException**(算术运算异常,一个整数除以0时,抛出该异常)和 **ArrayIndexOutOfBoundsException** (下标越界异常)。
-
-**注意:异常和错误的区别:异常能被程序本身可以处理,错误是无法处理。**
-
-### Throwable类常用方法
-
-- **public string getMessage()**:返回异常发生时的详细信息
-- **public string toString()**:返回异常发生时的简要描述
-- **public string getLocalizedMessage()**:返回异常对象的本地化信息。使用Throwable的子类覆盖这个方法,可以声称本地化信息。如果子类没有覆盖该方法,则该方法返回的信息与getMessage()返回的结果相同
-- **public void printStackTrace()**:在控制台上打印Throwable对象封装的异常信息
-
-### 异常处理总结
-
-- try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
-- catch 块:用于处理try捕获到的异常。
-- finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。
-
-**在以下4种特殊情况下,finally块不会被执行:**
-
-1. 在finally语句块中发生了异常。
-2. 在前面的代码中用了System.exit()退出程序。
-3. 程序所在的线程死亡。
-4. 关闭CPU。
-
-## 33 Java序列话中如果有些字段不想进行序列化 怎么办
-
-对于不想进行序列化的变量,使用transient关键字修饰。
-
-transient关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。transient只能修饰变量,不能修饰类和方法。
-
-# Java基础学习书籍推荐
-
-**《Head First Java.第二版》:**
-可以说是我的 Java 启蒙书籍了,特别适合新手读当然也适合我们用来温故Java知识点。
-
-**《Java核心技术卷1+卷2》:**
-很棒的两本书,建议有点 Java 基础之后再读,介绍的还是比较深入的,非常推荐。
-
-**《Java编程思想(第4版)》:**
-这本书要常读,初学者可以快速概览,中等程序员可以深入看看 Java,老鸟还可以用之回顾 Java 的体系。这本书之所以厉害,因为它在无形中整合了设计模式,这本书之所以难读,也恰恰在于他对设计模式的整合是无形的。
-
-
diff --git "a/Java\347\233\270\345\205\263/Java\350\231\232\346\213\237\346\234\272\357\274\210jvm\357\274\211.md" "b/Java\347\233\270\345\205\263/Java\350\231\232\346\213\237\346\234\272\357\274\210jvm\357\274\211.md"
deleted file mode 100644
index 238e7c8b5df..00000000000
--- "a/Java\347\233\270\345\205\263/Java\350\231\232\346\213\237\346\234\272\357\274\210jvm\357\274\211.md"
+++ /dev/null
@@ -1,67 +0,0 @@
-Java面试通关手册(Java学习指南)github地址(欢迎star和pull):[https://github.com/Snailclimb/Java_Guide](https://github.com/Snailclimb/Java_Guide)
-
-
-
-下面是按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)这两篇文章。
-
-
-> ### 常见面试题
-
-[深入理解虚拟机之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)
-
-1. 介绍下Java内存区域(运行时数据区)。
-
-2. 对象的访问定位的两种方式。
-
-
-[深入理解虚拟机之垃圾回收](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)
-
-1. 如何判断对象是否死亡(两种方法)。
-
-2. 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。
-
-3. 垃圾收集有哪些算法,各自的特点?
-
-4. HotSpot为什么要分为新生代和老年代?
-
-5. 常见的垃圾回收器有那些?
-
-6. 介绍一下CMS,G1收集器。
-
-7. Minor Gc和Full GC 有什么不同呢?
-
-
-
-[虚拟机性能监控和故障处理工具](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)
-
-1. JVM调优的常见命令行工具有哪些?
-
-[深入理解虚拟机之类文件结构](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)
-
-1. 简单介绍一下Class类文件结构(常量池主要存放的是那两大常量?Class文件的继承关系是如何确定的?字段表、方法表、属性表主要包含那些信息?)
-
-[深入理解虚拟机之虚拟机类加载机制](http://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247483934&idx=1&sn=f247f9bee4e240f5e7fac25659da3bff&chksm=fd98547fcaefdd6996e1a7046e03f29df9308bdf82ceeffd111112766ffd3187892700f64b40#rd)
-
-1. 简单说说类加载过程,里面执行了哪些操作?
-
-2. 对类加载器有了解吗?
-
-3. 什么是双亲委派模型?
-
-4. 双亲委派模型的工作过程以及使用它的好处。
-
-
-
-
-
-> ### 推荐阅读
-
-[深入理解虚拟机之虚拟机字节码执行引擎](https://juejin.im/post/5aebcb076fb9a07a9a10b5f3)
-
-[《深入理解 Java 内存模型》读书笔记](http://www.54tianzhisheng.cn/2018/02/28/Java-Memory-Model/) (非常不错的文章)
-
-[全面理解Java内存模型(JMM)及volatile关键字 ](https://blog.csdn.net/javazejian/article/details/72772461)
-
-**欢迎关注我的微信公众号:"Java面试通关手册"(一个有温度的微信公众号,期待与你共同进步~~~坚持原创,分享美文,分享各种Java学习资源):**
-
-
diff --git "a/Java\347\233\270\345\205\263/final\343\200\201static\343\200\201this\343\200\201super.md" "b/Java\347\233\270\345\205\263/final\343\200\201static\343\200\201this\343\200\201super.md"
deleted file mode 100644
index d891cc3346e..00000000000
--- "a/Java\347\233\270\345\205\263/final\343\200\201static\343\200\201this\343\200\201super.md"
+++ /dev/null
@@ -1,84 +0,0 @@
-## final 关键字
-
-**final关键字主要用在三个地方:变量、方法、类。**
-
-1. **对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。**
-
-2. **当用final修饰一个类时,表明这个类不能被继承。final类中的所有成员方法都会被隐式地指定为final方法。**
-
-3. 使用final方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的Java版本已经不需要使用final方法进行这些优化了)。类中所有的private方法都隐式地指定为final。
-
-## static 关键字
-
-**static 关键字主要有以下四种使用场景:**
-
-1. **修饰成员变量和成员方法:** 被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。调用格式:`类名.静态变量名` `类名.静态方法名()`
-2. **静态代码块:** 静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
-3. **静态内部类(static修饰类的话只能修饰内部类):** 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:1. 它的创建是不需要依赖外围类的创建。2. 它不能使用任何外围类的非static成员变量和方法。
-4. **静态导包(用来导入类中的静态资源,1.5之后的新特性):** 格式为:`import static` 这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法。
-
-## this 关键字
-
-this关键字用于引用类的当前实例。 例如:
-
-```java
-class Manager {
- Employees[] employees;
-
- void manageEmployees() {
- int totalEmp = this.employees.length;
- System.out.println("Total employees: " + totalEmp);
- this.report();
- }
-
- void report() { }
-}
-```
-
-在上面的示例中,this关键字用于两个地方:
-
-- this.employees.length:访问类Manager的当前实例的变量。
-- this.report():调用类Manager的当前实例的方法。
-
-此关键字是可选的,这意味着如果上面的示例在不使用此关键字的情况下表现相同。 但是,使用此关键字可能会使代码更易读或易懂。
-
-
-
-## super 关键字
-
-super关键字用于从子类访问父类的变量和方法。 例如:
-
-```java
-public class Super {
- protected int number;
-
- protected showNumber() {
- System.out.println("number = " + number);
- }
-}
-
-public class Sub extends Super {
- void bar() {
- super.number = 10;
- super.showNumber();
- }
-}
-```
-
-在上面的例子中,Sub 类访问父类成员变量 number 并调用其其父类 Super 的 `showNumber()` 方法。
-
-**使用 this 和 super 要注意的问题:**
-
-- super 调用父类中的其他构造方法时,调用时要放在构造方法的首行!this 调用本类中的其他构造方法时,也要放在首行。
-- this、super不能用在static方法中。
-
-**简单解释一下:**
-
-被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享。而 this 代表对本类对象的引用,指向本类对象;而 super 代表对父类对象的引用,指向父类对象;所以, **this和super是属于对象范畴的东西,而静态方法是属于类范畴的东西**。
-
-
-
-## 参考
-
-- https://www.codejava.net/java-core/the-java-language/java-keywords
-- https://blog.csdn.net/u013393958/article/details/79881037
diff --git "a/Java\347\233\270\345\205\263/\345\217\257\350\203\275\346\230\257\346\212\212Java\345\206\205\345\255\230\345\214\272\345\237\237\350\256\262\347\232\204\346\234\200\346\270\205\346\245\232\347\232\204\344\270\200\347\257\207\346\226\207\347\253\240.md" "b/Java\347\233\270\345\205\263/\345\217\257\350\203\275\346\230\257\346\212\212Java\345\206\205\345\255\230\345\214\272\345\237\237\350\256\262\347\232\204\346\234\200\346\270\205\346\245\232\347\232\204\344\270\200\347\257\207\346\226\207\347\253\240.md"
deleted file mode 100644
index ddd844266b4..00000000000
--- "a/Java\347\233\270\345\205\263/\345\217\257\350\203\275\346\230\257\346\212\212Java\345\206\205\345\255\230\345\214\272\345\237\237\350\256\262\347\232\204\346\234\200\346\270\205\346\245\232\347\232\204\344\270\200\347\257\207\346\226\207\347\253\240.md"
+++ /dev/null
@@ -1,341 +0,0 @@
-
-
-## 写在前面(常见面试题)
-
-### 基本问题:
-
-- **介绍下 Java 内存区域(运行时数据区)**
-- **Java 对象的创建过程(五步,建议能默写出来并且要知道每一步虚拟机做了什么)**
-- **对象的访问定位的两种方式(句柄和直接指针两种方式)**
-
-### 拓展问题:
-
-- **String类和常量池**
-- **8种基本类型的包装类和常量池**
-
-
-## 1 概述
-
-对于 Java 程序员来说,在虚拟机自动内存管理机制下,不再需要像C/C++程序开发程序员这样为内一个 new 操作去写对应的 delete/free 操作,不容易出现内存泄漏和内存溢出问题。正是因为 Java 程序员把内存控制权利交给 Java 虚拟机,一旦出现内存泄漏和溢出方面的问题,如果不了解虚拟机是怎样使用内存的,那么排查错误将会是一个非常艰巨的任务。
-
-
-## 2 运行时数据区域
-Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。
-
-这些组成部分一些事线程私有的,其他的则是线程共享的。
-
-**线程私有的:**
-
-- 程序计数器
-- 虚拟机栈
-- 本地方法栈
-
-**线程共享的:**
-
-- 堆
-- 方法区
-- 直接内存
-
-
-### 2.1 程序计数器
-程序计数器是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。**字节码解释器工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完。**
-
-另外,**为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。**
-
-**从上面的介绍中我们知道程序计数器主要有两个作用:**
-
-1. 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
-2. 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。
-
-**注意:程序计数器是唯一一个不会出现OutOfMemoryError的内存区域,它的生命周期随着线程的创建而创建,随着线程的结束而死亡。**
-
-### 2.2 Java 虚拟机栈
-
-**与程序计数器一样,Java虚拟机栈也是线程私有的,它的生命周期和线程相同,描述的是 Java 方法执行的内存模型。**
-
-**Java 内存可以粗糙的区分为堆内存(Heap)和栈内存(Stack),其中栈就是现在说的虚拟机栈,或者说是虚拟机栈中局部变量表部分。** (实际上,Java虚拟机栈是由一个个栈帧组成,而每个栈帧中都拥有:局部变量表、操作数栈、动态链接、方法出口信息。)
-
-**局部变量表主要存放了编译器可知的各种数据类型**(boolean、byte、char、short、int、float、long、double)、**对象引用**(reference类型,它不同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象相关的位置)。
-
-**Java 虚拟机栈会出现两种异常:StackOverFlowError 和 OutOfMemoryError。**
-
-- **StackOverFlowError:** 若Java虚拟机栈的内存大小不允许动态扩展,那么当线程请求栈的深度超过当前Java虚拟机栈的最大深度的时候,就抛出StackOverFlowError异常。
-- **OutOfMemoryError:** 若 Java 虚拟机栈的内存大小允许动态扩展,且当线程请求栈时内存用完了,无法再动态扩展了,此时抛出OutOfMemoryError异常。
-
-Java 虚拟机栈也是线程私有的,每个线程都有各自的Java虚拟机栈,而且随着线程的创建而创建,随着线程的死亡而死亡。
-
-### 2.3 本地方法栈
-
-和虚拟机栈所发挥的作用非常相似,区别是: **虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。** 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
-
-本地方法被执行的时候,在本地方法栈也会创建一个栈帧,用于存放该本地方法的局部变量表、操作数栈、动态链接、出口信息。
-
-方法执行完毕后相应的栈帧也会出栈并释放内存空间,也会出现 StackOverFlowError 和 OutOfMemoryError 两种异常。
-
-### 2.4 堆
-Java 虚拟机所管理的内存中最大的一块,Java 堆是所有线程共享的一块内存区域,在虚拟机启动时创建。**此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例以及数组都在这里分配内存。**
-
-Java 堆是垃圾收集器管理的主要区域,因此也被称作**GC堆(Garbage Collected Heap)**.从垃圾回收的角度,由于现在收集器基本都采用分代垃圾收集算法,所以Java堆还可以细分为:新生代和老年代:在细致一点有:Eden空间、From Survivor、To Survivor空间等。**进一步划分的目的是更好地回收内存,或者更快地分配内存。**
-
-
-
-**在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)。**
-
-推荐阅读:
-
-- 《Java8内存模型—永久代(PermGen)和元空间(Metaspace)》:[http://www.cnblogs.com/paddix/p/5309550.html](http://www.cnblogs.com/paddix/p/5309550.html)
-
-### 2.5 方法区
-
-**方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。**
-
-HotSpot 虚拟机中方法区也常被称为 **“永久代”**,本质上两者并不等价。仅仅是因为 HotSpot 虚拟机设计团队用永久代来实现方法区而已,这样 HotSpot 虚拟机的垃圾收集器就可以像管理 Java 堆一样管理这部分内存了。但是这并不是一个好主意,因为这样更容易遇到内存溢出问题。
-
-
-
-**相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入方法区后就“永久存在”了。**
-
-### 2.6 运行时常量池
-
-运行时常量池是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有常量池信息(用于存放编译期生成的各种字面量和符号引用)
-
-既然运行时常量池时方法区的一部分,自然受到方法区内存的限制,当常量池无法再申请到内存时会抛出 OutOfMemoryError 异常。
-
-**JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。**
-
-
-——图片来源:https://blog.csdn.net/wangbiao007/article/details/78545189
-
-
-
-推荐阅读:
-
-- 《Java 中几种常量池的区分》: [https://blog.csdn.net/qq_26222859/article/details/73135660](https://blog.csdn.net/qq_26222859/article/details/73135660)
-
-
-### 2.7 直接内存
-
-直接内存并不是虚拟机运行时数据区的一部分,也不是虚拟机规范中定义的内存区域,但是这部分内存也被频繁地使用。而且也可能导致OutOfMemoryError异常出现。
-
-JDK1.4中新加入的 **NIO(New Input/Output) 类**,引入了一种基于**通道(Channel)** 与**缓存区(Buffer)** 的 I/O 方式,它可以直接使用Native函数库直接分配堆外内存,然后通过一个存储在 Java 堆中的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样就能在一些场景中显著提高性能,因为**避免了在 Java 堆和 Native 堆之间来回复制数据**。
-
-本机直接内存的分配不会收到 Java 堆的限制,但是,既然是内存就会受到本机总内存大小以及处理器寻址空间的限制。
-
-
-## 3 HotSpot 虚拟机对象探秘
-通过上面的介绍我们大概知道了虚拟机的内存情况,下面我们来详细的了解一下 HotSpot 虚拟机在 Java 堆中对象分配、布局和访问的全过程。
-
-### 3.1 对象的创建
-下图便是 Java 对象的创建过程,我建议最好是能默写出来,并且要掌握每一步在做什么。
-
-
-**①类加载检查:** 虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
-
-**②分配内存:** 在**类加载检查**通过后,接下来虚拟机将为新生对象**分配内存**。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。**分配方式**有 **“指针碰撞”** 和 **“空闲列表”** 两种,**选择那种分配方式由 Java 堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定**。
-
-
-**内存分配的两种方式:(补充内容,需要掌握)**
-
-选择以上两种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器的算法是"标记-清除",还是"标记-整理"(也称作"标记-压缩"),值得注意的是,复制算法内存也是规整的
-
-
-
-**内存分配并发问题(补充内容,需要掌握)**
-
-在创建对象的时候有一个很重要的问题,就是线程安全,因为在实际开发过程中,创建对象是很频繁的事情,作为虚拟机来说,必须要保证线程是安全的,通常来讲,虚拟机采用两种方式来保证线程安全:
-
-- **CAS+失败重试:** CAS 是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。**虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。**
-- **TLAB:** 为每一个线程预先在Eden区分配一块儿内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配
-
-
-
-**③初始化零值:** 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。
-
-**④设置对象头:** 初始化零值完成之后,**虚拟机要对对象进行必要的设置**,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。 **这些信息存放在对象头中。** 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
-
-
-**⑤执行 init 方法:** 在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,`` 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 `` 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。
-
-
-### 3.2 对象的内存布局
-
-在 Hotspot 虚拟机中,对象在内存中的布局可以分为3快区域:**对象头**、**实例数据**和**对齐填充**。
-
-**Hotspot虚拟机的对象头包括两部分信息**,**第一部分用于存储对象自身的自身运行时数据**(哈希吗、GC分代年龄、锁状态标志等等),**另一部分是类型指针**,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是那个类的实例。
-
-**实例数据部分是对象真正存储的有效信息**,也是在程序中所定义的各种类型的字段内容。
-
-**对齐填充部分不是必然存在的,也没有什么特别的含义,仅仅起占位作用。** 因为Hotspot虚拟机的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说就是对象的大小必须是8字节的整数倍。而对象头部分正好是8字节的倍数(1倍或2倍),因此,当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。
-
-### 3.3 对象的访问定位
-建立对象就是为了使用对象,我们的Java程序通过栈上的 reference 数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前主流的访问方式有**①使用句柄**和**②直接指针**两种:
-
-1. **句柄:** 如果使用句柄的话,那么Java堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息;
-
-
-2. **直接指针:** 如果使用直接指针访问,那么 Java 堆对像的布局中就必须考虑如何放置访问类型数据的相关信息,而reference 中存储的直接就是对象的地址。
-
-
-
-**这两种对象访问方式各有优势。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。**
-
-
-
-
-## 四 重点补充内容
-
-### String 类和常量池
-
-**1 String 对象的两种创建方式:**
-
-```java
- String str1 = "abcd";
- String str2 = new String("abcd");
- System.out.println(str1==str2);//false
-```
-
-这两种不同的创建方法是有差别的,第一种方式是在常量池中拿对象,第二种方式是直接在堆内存空间创建一个新的对象。
-
-记住:只要使用new方法,便需要创建新的对象。
-
-
-
-**2 String 类型的常量池比较特殊。它的主要使用方法有两种:**
-
-- 直接使用双引号声明出来的 String 对象会直接存储在常量池中。
-- 如果不是用双引号声明的 String 对象,可以使用 String 提供的 intern 方String.intern() 是一个 Native 方法,它的作用是:如果运行时常量池中已经包含一个等于此 String 对象内容的字符串,则返回常量池中该字符串的引用;如果没有,则在常量池中创建与此 String 内容相同的字符串,并返回常量池中创建的字符串的引用。
-
-```java
- String s1 = new String("计算机");
- String s2 = s1.intern();
- String s3 = "计算机";
- System.out.println(s2);//计算机
- System.out.println(s1 == s2);//false,因为一个是堆内存中的String对象一个是常量池中的String对象,
- System.out.println(s3 == s2);//true,因为两个都是常量池中的String对
-```
-**3 String 字符串拼接**
-```java
- String str1 = "str";
- String str2 = "ing";
-
- String str3 = "str" + "ing";//常量池中的对象
- String str4 = str1 + str2; //在堆上创建的新的对象
- String str5 = "string";//常量池中的对象
- System.out.println(str3 == str4);//false
- System.out.println(str3 == str5);//true
- System.out.println(str4 == str5);//false
-```
-
-
-尽量避免多个字符串拼接,因为这样会重新创建对象。如果需要改变字符串的话,可以使用 StringBuilder 或者 StringBuffer。
-### String s1 = new String("abc");这句话创建了几个对象?
-
-**创建了两个对象。**
-
-**验证:**
-
-```java
- String s1 = new String("abc");// 堆内存的地值值
- String s2 = "abc";
- System.out.println(s1 == s2);// 输出false,因为一个是堆内存,一个是常量池的内存,故两者是不同的。
- System.out.println(s1.equals(s2));// 输出true
-```
-
-**结果:**
-
-```
-false
-true
-```
-
-**解释:**
-
-先有字符串"abc"放入常量池,然后 new 了一份字符串"abc"放入Java堆(字符串常量"abc"在编译期就已经确定放入常量池,而 Java 堆上的"abc"是在运行期初始化阶段才确定),然后 Java 栈的 str1 指向Java堆上的"abc"。
-
-### 8种基本类型的包装类和常量池
-
-- **Java 基本类型的包装类的大部分都实现了常量池技术,即Byte,Short,Integer,Long,Character,Boolean;这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。**
-- **两种浮点数类型的包装类 Float,Double 并没有实现常量池技术。**
-
-```java
- Integer i1 = 33;
- Integer i2 = 33;
- System.out.println(i1 == i2);// 输出true
- Integer i11 = 333;
- Integer i22 = 333;
- System.out.println(i11 == i22);// 输出false
- Double i3 = 1.2;
- Double i4 = 1.2;
- System.out.println(i3 == i4);// 输出false
-```
-
-**Integer 缓存源代码:**
-
-```java
-/**
-*此方法将始终缓存-128到127(包括端点)范围内的值,并可以缓存此范围之外的其他值。
-*/
- public static Integer valueOf(int i) {
- if (i >= IntegerCache.low && i <= IntegerCache.high)
- return IntegerCache.cache[i + (-IntegerCache.low)];
- return new Integer(i);
- }
-
-```
-
-**应用场景:**
-1. Integer i1=40;Java 在编译的时候会直接将代码封装成Integer i1=Integer.valueOf(40);,从而使用常量池中的对象。
-2. Integer i1 = new Integer(40);这种情况下会创建新的对象。
-
-```java
- Integer i1 = 40;
- Integer i2 = new Integer(40);
- System.out.println(i1==i2);//输出false
-```
-**Integer比较更丰富的一个例子:**
-
-```java
- Integer i1 = 40;
- Integer i2 = 40;
- Integer i3 = 0;
- Integer i4 = new Integer(40);
- Integer i5 = new Integer(40);
- Integer i6 = new Integer(0);
-
- System.out.println("i1=i2 " + (i1 == i2));
- System.out.println("i1=i2+i3 " + (i1 == i2 + i3));
- System.out.println("i1=i4 " + (i1 == i4));
- System.out.println("i4=i5 " + (i4 == i5));
- System.out.println("i4=i5+i6 " + (i4 == i5 + i6));
- System.out.println("40=i5+i6 " + (40 == i5 + i6));
-```
-
-结果:
-
-```
-i1=i2 true
-i1=i2+i3 true
-i1=i4 false
-i4=i5 false
-i4=i5+i6 true
-40=i5+i6 true
-```
-
-解释:
-
-语句i4 == i5 + i6,因为+这个操作符不适用于Integer对象,首先i5和i6进行自动拆箱操作,进行数值相加,即i4 == 40。然后Integer对象无法与数值进行直接比较,所以i4自动拆箱转为int值40,最终这条语句转为40 == 40进行数值比较。
-
-
-**参考:**
-
-- 《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版》
-- 《实战java虚拟机》
-- https://www.cnblogs.com/CZDblog/p/5589379.html
-- https://www.cnblogs.com/java-zhao/p/5180492.html
-- https://blog.csdn.net/qq_26222859/article/details/73135660
-- https://blog.csdn.net/cugwuhan2014/article/details/78038254
-
-
-
-
-
diff --git "a/Java\347\233\270\345\205\263/\346\220\236\345\256\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\260\261\346\230\257\350\277\231\344\271\210\347\256\200\345\215\225.md" "b/Java\347\233\270\345\205\263/\346\220\236\345\256\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\260\261\346\230\257\350\277\231\344\271\210\347\256\200\345\215\225.md"
deleted file mode 100644
index 21ed7047dd7..00000000000
--- "a/Java\347\233\270\345\205\263/\346\220\236\345\256\232JVM\345\236\203\345\234\276\345\233\236\346\224\266\345\260\261\346\230\257\350\277\231\344\271\210\347\256\200\345\215\225.md"
+++ /dev/null
@@ -1,374 +0,0 @@
-
-上文回顾:[《可能是把Java内存区域讲的最清楚的一篇文章》](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484303&idx=1&sn=af0fd436cef755463f59ee4dd0720cbd&chksm=fd9855eecaefdcf8d94ac581cfda4e16c8a730bda60c3b50bc55c124b92f23b6217f7f8e58d5&token=506869459&lang=zh_CN#rd)
-## 写在前面
-
-### 本节常见面试题:
-
-问题答案在文中都有提到
-
-- 如何判断对象是否死亡(两种方法)。
-- 简单的介绍一下强引用、软引用、弱引用、虚引用(虚引用与软引用和弱引用的区别、使用软引用能带来的好处)。
-- 如何判断一个常量是废弃常量
-- 如何判断一个类是无用的类
-- 垃圾收集有哪些算法,各自的特点?
-- HotSpot为什么要分为新生代和老年代?
-- 常见的垃圾回收器有那些?
-- 介绍一下CMS,G1收集器。
-- Minor Gc和Full GC 有什么不同呢?
-
-### 本文导火索
-
-
-
-当需要排查各种 内存溢出问题、当垃圾收集称为系统达到更高并发的瓶颈时,我们就需要对这些“自动化”的技术实施必要的监控和调节。
-
-
-
-## 1 揭开JVM内存分配与回收的神秘面纱
-
-Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时,Java 自动内存管理最核心的功能是 **堆** 内存中对象的分配与回收。
-
-**JDK1.8之前的堆内存示意图:**
-
-
-
-从上图可以看出堆内存的分为新生代、老年代和永久代。新生代又被进一步分为:Eden 区+Survior1 区+Survior2 区。值得注意的是,在 JDK 1.8中移除整个永久代,取而代之的是一个叫元空间(Metaspace)的区域(永久代使用的是JVM的堆内存空间,而元空间使用的是物理内存,直接受到本机的物理内存限制)。
-
-
-
-### 1.1 对象优先在eden区分配
-
-目前主流的垃圾收集器都会采用分代回收算法,因此需要将堆内存分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
-
-大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC.下面我们来进行实际测试以下。
-
-在测试之前我们先来看看 **Minor Gc和Full GC 有什么不同呢?**
-
-- **新生代GC(Minor GC)**:指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。
-- **老年代GC(Major GC/Full GC)**:指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。
-
-**测试:**
-
-```java
-public class GCTest {
-
- public static void main(String[] args) {
- byte[] allocation1, allocation2;
- allocation1 = new byte[30900*1024];
- //allocation2 = new byte[900*1024];
- }
-}
-```
-通过以下方式运行:
-
-
-添加的参数:`-XX:+PrintGCDetails`
-
-
-运行结果:
-
-
-
-从上图我们可以看出eden区内存几乎已经被分配完全(即使程序什么也不做,新生代也会使用2000多k内存)。假如我们再为allocation2分配内存会出现什么情况呢?
-
-```java
-allocation2 = new byte[900*1024];
-```
-
-
-**简单解释一下为什么会出现这种情况:** 因为给allocation2分配内存的时候eden区内存几乎已经被分配完了,我们刚刚讲了当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC.GC期间虚拟机又发现allocation1无法存入Survior空间,所以只好通过 **分配担保机制** 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放allocation1,所以不会出现Full GC。执行Minor GC后,后面分配的对象如果能够存在eden区的话,还是会在eden区分配内存。可以执行如下代码验证:
-
-```java
-public class GCTest {
-
- public static void main(String[] args) {
- byte[] allocation1, allocation2,allocation3,allocation4,allocation5;
- allocation1 = new byte[32000*1024];
- allocation2 = new byte[1000*1024];
- allocation3 = new byte[1000*1024];
- allocation4 = new byte[1000*1024];
- allocation5 = new byte[1000*1024];
- }
-}
-
-```
-
-
-### 1.2 大对象直接进入老年代
-大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。
-
-**为什么要这样呢?**
-
-为了避免为大对象分配内存时由于分配担保机制带来的复制而降低效率。
-
-### 1.3 长期存活的对象将进入老年代
-既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别那些对象应放在新生代,那些对象应放在老年代中。为了做到这一点,虚拟机给每个对象一个对象年龄(Age)计数器。
-
-如果对象在 Eden 出生并经过第一次 Minor GC 后仍然能够存活,并且能被 Survivor 容纳的话,将被移动到 Survivor 空间中,并将对象年龄设为1.对象在 Survivor 中每熬过一次 MinorGC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 `-XX:MaxTenuringThreshold` 来设置。
-
-### 1.4 动态对象年龄判定
-
-为了更好的适应不同程序的内存情况,虚拟机不是永远要求对象年龄必须达到了某个值才能进入老年代,如果 Survivor 空间中相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需达到要求的年龄。
-
-
-## 2 对象已经死亡?
-
-堆中几乎放着所有的对象实例,对堆垃圾回收前的第一步就是要判断那些对象已经死亡(即不能再被任何途径使用的对象)。
-
-
-
-### 2.1 引用计数法
-
-给对象中添加一个引用计数器,每当有一个地方引用它,计数器就加1;当引用失效,计数器就减1;任何时候计数器为0的对象就是不可能再被使用的。
-
-**这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。** 所谓对象之间的相互引用问题,如下面代码所示:除了对象objA 和 objB 相互引用着对方之外,这两个对象之间再无任何引用。但是他们因为互相引用对方,导致它们的引用计数器都不为0,于是引用计数算法无法通知 GC 回收器回收他们。
-
-```java
-public class ReferenceCountingGc {
- Object instance = null;
- public static void main(String[] args) {
- ReferenceCountingGc objA = new ReferenceCountingGc();
- ReferenceCountingGc objB = new ReferenceCountingGc();
- objA.instance = objB;
- objB.instance = objA;
- objA = null;
- objB = null;
-
- }
-}
-```
-
-
-
-### 2.2 可达性分析算法
-
-这个算法的基本思想就是通过一系列的称为 **“GC Roots”** 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。
-
-
-
-
-### 2.3 再谈引用
-
-无论是通过引用计数法判断对象引用数量,还是通过可达性分析法判断对象的引用链是否可达,判定对象的存活都与“引用”有关。
-
-JDK1.2之前,Java中引用的定义很传统:如果reference类型的数据存储的数值代表的是另一块内存的起始地址,就称这块内存代表一个引用。
-
-JDK1.2以后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用四种(引用强度逐渐减弱)
-
-
-
-**1.强引用**
-
-以前我们使用的大部分引用实际上都是强引用,这是使用最普遍的引用。如果一个对象具有强引用,那就类似于**必不可少的生活用品**,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
-
-**2.软引用(SoftReference)**
-
-如果一个对象只具有软引用,那就类似于**可有可物的生活用品**。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
-
-软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,JAVA虚拟机就会把这个软引用加入到与之关联的引用队列中。
-
-**3.弱引用(WeakReference)**
-
-如果一个对象只具有弱引用,那就类似于**可有可物的生活用品**。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
-
-弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
-
-**4.虚引用(PhantomReference)**
-
-"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
-
-**虚引用主要用来跟踪对象被垃圾回收的活动**。
-
-**虚引用与软引用和弱引用的一个区别在于:** 虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
-
-特别注意,在程序设计中一般很少使用弱引用与虚引用,使用软引用的情况较多,这是因为**软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生**。
-
-### 2.4 不可达的对象并非“非死不可”
-
-即使在可达性分析法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑阶段”,要真正宣告一个对象死亡,至少要经历两次标记过程;可达性分析法中不可达的对象被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize 方法。当对象没有覆盖 finalize 方法,或 finalize 方法已经被虚拟机调用过时,虚拟机将这两种情况视为没有必要执行。
-
-被判定为需要执行的对象将会被放在一个队列中进行第二次标记,除非这个对象与引用链上的任何一个对象建立关联,否则就会被真的回收。
-
-### 2.5 如何判断一个常量是废弃常量
-
-运行时常量池主要回收的是废弃的常量。那么,我们如何判断一个常量是废弃常量呢?
-
-假如在常量池中存在字符串 "abc",如果当前没有任何String对象引用该字符串常量的话,就说明常量 "abc" 就是废弃常量,如果这时发生内存回收的话而且有必要的话,"abc" 就会被系统清理出常量池。
-
-注意:我们在 [可能是把Java内存区域讲的最清楚的一篇文章](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484303&idx=1&sn=af0fd436cef755463f59ee4dd0720cbd&chksm=fd9855eecaefdcf8d94ac581cfda4e16c8a730bda60c3b50bc55c124b92f23b6217f7f8e58d5&token=506869459&lang=zh_CN#rd) 也讲了JDK1.7及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池。
-
-### 2.6 如何判断一个类是无用的类
-
-方法区主要回收的是无用的类,那么如何判断一个类是无用的类的呢?
-
-判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是 **“无用的类”** :
-
-- 该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。
-- 加载该类的 ClassLoader 已经被回收。
-- 该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。
-
-虚拟机可以对满足上述3个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收。
-
-
-## 3 垃圾收集算法
-
-
-
-### 3.1 标记-清除算法
-
-算法分为“标记”和“清除”阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。它是最基础的收集算法,效率也很高,但是会带来两个明显的问题:
-
-1. **效率问题**
-2. **空间问题(标记清除后会产生大量不连续的碎片)**
-
-
-
-### 3.2 复制算法
-
-为了解决效率问题,“复制”收集算法出现了。它可以将内存分为大小相同的两块,每次使用其中的一块。当这一块的内存使用完后,就将还存活的对象复制到另一块去,然后再把使用的空间一次清理掉。这样就使每次的内存回收都是对内存区间的一半进行回收。
-
-
-
-### 3.3 标记-整理算法
-根据老年代的特点特出的一种标记算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象回收,而是让所有存活的对象向一段移动,然后直接清理掉端边界以外的内存。
-
-
-
-### 3.4 分代收集算法
-
-当前虚拟机的垃圾手机都采用分代收集算法,这种算法没有什么新的思想,只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代,这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。
-
-**比如在新生代中,每次收集都会有大量对象死去,所以可以选择复制算法,只需要付出少量对象的复制成本就可以完成每次垃圾收集。而老年代的对象存活几率是比较高的,而且没有额外的空间对它进行分配担保,所以我们必须选择“标记-清楚”或“标记-整理”算法进行垃圾收集。**
-
-**延伸面试问题:** HotSpot为什么要分为新生代和老年代?
-
-根据上面的对分代收集算法的介绍回答。
-
-## 4 垃圾收集器
-
-
-
-**如果说收集算法是内存回收的方法论,那么垃圾收集器就是内存回收的具体实现。**
-
-虽然我们对各个收集器进行比较,但并非了挑选出一个最好的收集器。因为知道现在位置还没有最好的垃圾收集器出现,更加没有万能的垃圾收集器,**我们能做的就是根据具体应用场景选择适合自己的垃圾收集器**。试想一下:如果有一种四海之内、任何场景下都适用的完美收集器存在,那么我们的HotSpot虚拟机就不会实现那么多不同的垃圾收集器了。
-
-
-### 4.1 Serial收集器
-Serial(串行)收集器收集器是最基本、历史最悠久的垃圾收集器了。大家看名字就知道这个收集器是一个单线程收集器了。它的 **“单线程”** 的意义不仅仅意味着它只会使用一条垃圾收集线程去完成垃圾收集工作,更重要的是它在进行垃圾收集工作的时候必须暂停其他所有的工作线程( **"Stop The World"** ),直到它收集结束。
-
- **新生代采用复制算法,老年代采用标记-整理算法。**
-
-
-虚拟机的设计者们当然知道Stop The World带来的不良用户体验,所以在后续的垃圾收集器设计中停顿时间在不断缩短(仍然还有停顿,寻找最优秀的垃圾收集器的过程仍然在继续)。
-
-但是Serial收集器有没有优于其他垃圾收集器的地方呢?当然有,它**简单而高效(与其他收集器的单线程相比)**。Serial收集器由于没有线程交互的开销,自然可以获得很高的单线程收集效率。Serial收集器对于运行在Client模式下的虚拟机来说是个不错的选择。
-
-
-
-### 4.2 ParNew收集器
-**ParNew收集器其实就是Serial收集器的多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等等)和Serial收集器完全一样。**
-
- **新生代采用复制算法,老年代采用标记-整理算法。**
-
-
-它是许多运行在Server模式下的虚拟机的首要选择,除了Serial收集器外,只有它能与CMS收集器(真正意义上的并发收集器,后面会介绍到)配合工作。
-
-**并行和并发概念补充:**
-
-- **并行(Parallel)** :指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
-
-- **并发(Concurrent)**:指用户线程与垃圾收集线程同时执行(但不一定是并行,可能会交替执行),用户程序在继续运行,而垃圾收集器运行在另一个CPU上。
-
-
-### 4.3 Parallel Scavenge收集器
-
-Parallel Scavenge 收集器类似于ParNew 收集器。 **那么它有什么特别之处呢?**
-
-```
--XX:+UseParallelGC
-
- 使用Parallel收集器+ 老年代串行
-
--XX:+UseParallelOldGC
-
- 使用Parallel收集器+ 老年代并行
-
-```
-
-**Parallel Scavenge收集器关注点是吞吐量(高效率的利用CPU)。CMS等垃圾收集器的关注点更多的是用户线程的停顿时间(提高用户体验)。所谓吞吐量就是CPU中用于运行用户代码的时间与CPU总消耗时间的比值。** Parallel Scavenge收集器提供了很多参数供用户找到最合适的停顿时间或最大吞吐量,如果对于收集器运作不太了解的话,手工优化存在的话可以选择把内存管理优化交给虚拟机去完成也是一个不错的选择。
-
- **新生代采用复制算法,老年代采用标记-整理算法。**
-
-
-
-### 4.4.Serial Old收集器
-**Serial收集器的老年代版本**,它同样是一个单线程收集器。它主要有两大用途:一种用途是在JDK1.5以及以前的版本中与Parallel Scavenge收集器搭配使用,另一种用途是作为CMS收集器的后备方案。
-
-### 4.5 Parallel Old收集器
- **Parallel Scavenge收集器的老年代版本**。使用多线程和“标记-整理”算法。在注重吞吐量以及CPU资源的场合,都可以优先考虑 Parallel Scavenge收集器和Parallel Old收集器。
-
-### 4.6 CMS收集器
-
-**CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。它而非常符合在注重用户体验的应用上使用。**
-
-**CMS(Concurrent Mark Sweep)收集器是HotSpot虚拟机第一款真正意义上的并发收集器,它第一次实现了让垃圾收集线程与用户线程(基本上)同时工作。**
-
-从名字中的**Mark Sweep**这两个词可以看出,CMS收集器是一种 **“标记-清除”算法**实现的,它的运作过程相比于前面几种垃圾收集器来说更加复杂一些。整个过程分为四个步骤:
-
-- **初始标记:** 暂停所有的其他线程,并记录下直接与root相连的对象,速度很快 ;
-- **并发标记:** 同时开启GC和用户线程,用一个闭包结构去记录可达对象。但在这个阶段结束,这个闭包结构并不能保证包含当前所有的可达对象。因为用户线程可能会不断的更新引用域,所以GC线程无法保证可达性分析的实时性。所以这个算法里会跟踪记录这些发生引用更新的地方。
-- **重新标记:** 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短
-- **并发清除:** 开启用户线程,同时GC线程开始对为标记的区域做清扫。
-
-
-
-从它的名字就可以看出它是一款优秀的垃圾收集器,主要优点:**并发收集、低停顿**。但是它有下面三个明显的缺点:
-
-- **对CPU资源敏感;**
-- **无法处理浮动垃圾;**
-- **它使用的回收算法-“标记-清除”算法会导致收集结束时会有大量空间碎片产生。**
-
-### 4.7 G1收集器
-
-
-**G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征.**
-
-被视为JDK1.7中HotSpot虚拟机的一个重要进化特征。它具备一下特点:
-
-- **并行与并发**:G1能充分利用CPU、多核环境下的硬件优势,使用多个CPU(CPU或者CPU核心)来缩短Stop-The-World停顿时间。部分其他收集器原本需要停顿Java线程执行的GC动作,G1收集器仍然可以通过并发的方式让java程序继续执行。
-- **分代收集**:虽然G1可以不需要其他收集器配合就能独立管理整个GC堆,但是还是保留了分代的概念。
-- **空间整合**:与CMS的“标记--清理”算法不同,G1从整体来看是基于“标记整理”算法实现的收集器;从局部上来看是基于“复制”算法实现的。
-- **可预测的停顿**:这是G1相对于CMS的另一个大优势,降低停顿时间是G1 和 CMS 共同的关注点,但G1 除了追求低停顿外,还能建立可预测的停顿时间模型,能让使用者明确指定在一个长度为M毫秒的时间片段内。
-
-
-G1收集器的运作大致分为以下几个步骤:
-
-- **初始标记**
-- **并发标记**
-- **最终标记**
-- **筛选回收**
-
-
-**G1收集器在后台维护了一个优先列表,每次根据允许的收集时间,优先选择回收价值最大的Region(这也就是它的名字Garbage-First的由来)**。这种使用Region划分内存空间以及有优先级的区域回收方式,保证了GF收集器在有限时间内可以尽可能高的收集效率(把内存化整为零)。
-
-
-
-
-
-参考:
-
-- 《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版》
-- https://my.oschina.net/hosee/blog/644618
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git "a/Java\347\233\270\345\205\263/\350\256\276\350\256\241\346\250\241\345\274\217.md" "b/Java\347\233\270\345\205\263/\350\256\276\350\256\241\346\250\241\345\274\217.md"
deleted file mode 100644
index 32a78ea6780..00000000000
--- "a/Java\347\233\270\345\205\263/\350\256\276\350\256\241\346\250\241\345\274\217.md"
+++ /dev/null
@@ -1,116 +0,0 @@
-下面是自己学习设计模式的时候做的总结,有些是自己的原创文章,有些是网上写的比较好的文章,保存下来细细消化吧!
-
-## 创建型模式:
-
-> ### 创建型模式概述:
-
-- 创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
-- 创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。
-
-
-
-> ### 创建型模式系列文章推荐:
-
-- **单例模式:**
-
-[深入理解单例模式——只有一个实例](https://blog.csdn.net/qq_34337272/article/details/80455972)
-
-- **工厂模式:**
-
-[深入理解工厂模式——由对象工厂生成对象](https://blog.csdn.net/qq_34337272/article/details/80472071)
-
-- **建造者模式:**
-
-[深入理解建造者模式 ——组装复杂的实例](http://blog.csdn.net/qq_34337272/article/details/80540059)
-
-- **原型模式:**
-
-[深入理解原型模式 ——通过复制生成实例](https://blog.csdn.net/qq_34337272/article/details/80706444)
-
-
-## 结构型模式:
-
-> ### 结构型模式概述:
-
-- **结构型模式(Structural Pattern):** 描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构
-
-- **结构型模式可以分为类结构型模式和对象结构型模式:**
- - 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
- - 对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
-
-
-
-> ### 结构型模式系列文章推荐:
-
-- **适配器模式:**
-
-[深入理解适配器模式——加个“适配器”以便于复用](https://segmentfault.com/a/1190000011856448)
-
-[适配器模式原理及实例介绍-IBM](https://www.ibm.com/developerworks/cn/java/j-lo-adapter-pattern/index.html)
-
-- **桥接模式:**
-
-[设计模式笔记16:桥接模式(Bridge Pattern)](https://blog.csdn.net/yangzl2008/article/details/7670996)
-
-- **组合模式:**
-
-[大话设计模式—组合模式](https://blog.csdn.net/lmb55/article/details/51039781)
-
-- **装饰模式:**
-
-[java模式—装饰者模式](https://www.cnblogs.com/chenxing818/p/4705919.html)
-
-[Java设计模式-装饰者模式](https://blog.csdn.net/cauchyweierstrass/article/details/48240147)
-
-- **外观模式:**
-
-[java设计模式之外观模式(门面模式)](https://www.cnblogs.com/lthIU/p/5860607.html)
-
-- **享元模式:**
-
-[享元模式](http://www.jasongj.com/design_pattern/flyweight/)
-
-- **代理模式:**
-
-[代理模式原理及实例讲解 (IBM出品,很不错)](https://www.ibm.com/developerworks/cn/java/j-lo-proxy-pattern/index.html)
-
-[轻松学,Java 中的代理模式及动态代理](https://blog.csdn.net/briblue/article/details/73928350)
-
-[Java代理模式及其应用](https://blog.csdn.net/justloveyou_/article/details/74203025)
-
-
-## 行为型模式
-
-> ### 行为型模式概述:
-
-- 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
-- 行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
-- 通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
-
-**行为型模式分为类行为型模式和对象行为型模式两种:**
-
-- **类行为型模式:** 类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
-- **对象行为型模式:** 对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。
-
-
-
-- **职责链模式:**
-
-[Java设计模式之责任链模式、职责链模式](https://blog.csdn.net/jason0539/article/details/45091639)
-
-[责任链模式实现的三种方式](https://www.cnblogs.com/lizo/p/7503862.html)
-
-- **命令模式:**
-
-
-
-- **解释器模式:**
-- **迭代器模式:**
-- **中介者模式:**
-- **备忘录模式:**
-- **观察者模式:**
-- **状态模式:**
-- **策略模式:**
-- **模板方法模式:**
-- **访问者模式:**
-
diff --git a/README.md b/README.md
index 5d5b2f6b679..f68f237afca 100644
--- a/README.md
+++ b/README.md
@@ -1,157 +1,335 @@
-> 福利:看本文之前,推荐给大家一个阿里云双11活动,真的非常非常非常推荐,对于新人福利,阿里云这次真的是下血本了,建议阿里云新人一定一定一定不要错过。如果觉得这单纯是广告的话(阿里云肯找我做广告就好了,嘿嘿),你可以直接跳过看正文。
-
-阿里云双11最新活动(仅限阿里云新用户购买,老用户拉新用户可以获得返现红包,后续有机会平分百万红包),优惠力度非常非常非常大,另外加入拼团,后续还有机会平分100w红包!**目前我的战队已经有40多位新人了,现在是折上5折了也就是1折购买,已经达到了最低折扣!!!!!!。** 划重点了: **1核2G云服务器1年仅需99.5元!!!1核2G云服务器3年仅需298.50元!!!一个月仅需8.2元** 该折扣仅限新人!这是我的拼团团队地址:[https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.hf47liqn](https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.hf47liqn) !
-
-另外,老用户和新用户可以帮忙拉新,拉新你可以获得什么福利呢?①即时红包,即拆即用(最低红包10元,最高1111元);②瓜分百万红包的机会(目前我的战队已经有29位新人,所以冲进前100的可能性非常大!冲进之后即可瓜分百万红包!)③返现奖励,如果你邀请了新人你会获得返现奖励,返现奖励直接到你的账户!(我希望我的团队最后能够冲进前100,别的不多说!!!诚信!)
-
-Gitchat 推荐:[Java 程序员必备:并发知识系统总结](https://gitbook.cn/gitchat/activity/5bc2b6af56f0425673d299bb)
-
-| Ⅰ | Ⅱ | Ⅲ | Ⅳ | Ⅴ | Ⅵ | Ⅶ | Ⅷ | Ⅸ | Ⅹ |
-| :--------: | :----------: | :-----------: | :---------: | :---------: | :---------:| :---------: | :-------: | :-------:| :----:|
-| [Java](#coffee-Java) | [数据结构与算法](#open_file_folder-数据结构与算法)|[计算机网络与数据通信](#computer-计算机网络与数据通信) | [操作系统](#iphone-操作系统)| [主流框架](#pencil2-主流框架)| [数据存储](#floppy_disk-数据存储)|[架构](#punch-架构)| [面试必备](#musical_note-面试必备)| [其他](#art-其他)| [说明](#envelope-该开源文档一些说明)|
-
-## :coffee: Java
-- ### Java/J2EE 基础
- - [Java 基础知识回顾](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/Java基础知识.md)
- - [J2EE 基础知识回顾](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/J2EE基础知识.md)
- - [static、final、this、super关键字总结](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/final、static、this、super.md)
- - [static 关键字详解](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/static.md)
-
-- ### Java 集合框架
- - [这几道Java集合框架面试题几乎必问](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/这几道Java集合框架面试题几乎必问.md)
- - [Java 集合框架常见面试题总结](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/Java集合框架常见面试题总结.md)
- - [ArrayList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/ArrayList.md)
- - [【面试必备】透过源码角度一步一步带你分析 ArrayList 扩容机制](https://github.com/Snailclimb/JavaGuide/blob/master/Java相关/ArrayList-Grow.md)
- - [LinkedList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/LinkedList.md)
- - [HashMap(JDK1.8)源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/HashMap.md)
-
-- ### Java 多线程
- - [多线程系列文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/多线程系列.md)
- - [Synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReenTrantLock 的对比](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/synchronized.md)
-
-- ### Java IO 与 NIO
- - [Java IO 与 NIO系列文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Java%20IO与NIO.md)
-
-- ### Java虚拟机(jvm)
- - [可能是把Java内存区域讲的最清楚的一篇文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/可能是把Java内存区域讲的最清楚的一篇文章.md)
- - [搞定JVM垃圾回收就是这么简单](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/搞定JVM垃圾回收就是这么简单.md)
- - [Java虚拟机(jvm)学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Java虚拟机(jvm).md)
-- ### 设计模式
- - [设计模式系列文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/设计模式.md)
-
-## :open_file_folder: 数据结构与算法
-
-- ### 数据结构
- - [数据结构知识学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/数据结构.md)
-
-
-- ### 算法
- - [算法学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/算法.md)
-
- - [常见安全算法(MD5、SHA1、Base64等等)总结](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/常见安全算法(MD5、SHA1、Base64等等)总结.md)
- - [算法总结——几道常见的子符串算法题 ](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/搞定BAT面试——几道常见的子符串算法题.md)
- - [算法总结——几道常见的链表算法题 ](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/Leetcode-LinkList1.md)
-
-## :computer: 计算机网络与数据通信
-- ### 网络相关
- - [计算机网络常见面试题](https://github.com/Snailclimb/Java_Guide/blob/master/计算机网络与数据通信/计算机网络.md)
- - [计算机网络基础知识总结](https://github.com/Snailclimb/Java_Guide/blob/master/计算机网络与数据通信/干货:计算机网络知识总结.md)
-
-- ### 数据通信(RESTful、RPC、消息队列)
- - [数据通信(RESTful、RPC、消息队列)相关知识点总结](https://github.com/Snailclimb/Java-Guide/blob/master/计算机网络与数据通信/数据通信(RESTful、RPC、消息队列).md)
-
-
-## :iphone: 操作系统
-
-- ### Linux相关
- - [后端程序员必备的 Linux 基础知识](https://github.com/Snailclimb/Java-Guide/blob/master/操作系统/后端程序员必备的Linux基础知识.md)
-
-## :pencil2: 主流框架/软件
-
-- ### Spring
- - [Spring 学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/主流框架/Spring学习与面试.md)
- - [Spring中bean的作用域与生命周期](https://github.com/Snailclimb/Java_Guide/blob/master/主流框架/SpringBean.md)
- - [SpringMVC 工作原理详解](https://github.com/Snailclimb/JavaGuide/blob/master/主流框架/SpringMVC%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3.md)
-- ### ZooKeeper
- - [可能是把 ZooKeeper 概念讲的最清楚的一篇文章](https://github.com/Snailclimb/Java_Guide/blob/master/主流框架/ZooKeeper.md)
-
-## :floppy_disk: 数据存储
-- ### MySQL
- - [MySQL 学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/MySQL.md)
- - [【思维导图-索引篇】搞定数据库索引就是这么简单](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/MySQL%20Index.md)
-- ### Redis
- - [Redis 总结](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/Redis/Redis.md)
- - [Redlock分布式锁](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/Redis/Redlock分布式锁.md)
- - [如何做可靠的分布式锁,Redlock真的可行么](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/Redis/如何做可靠的分布式锁,Redlock真的可行么.md)\
-
-## :punch: 架构
-- ### 分布式相关
- - [分布式学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/架构/分布式.md)
-
-## :musical_note: 面试必备
-
-- ### 面试必备知识点
- - [面试必备之乐观锁与悲观锁](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/面试必备之乐观锁与悲观锁.md)
-- ### 最最最常见的Java面试题总结
- 这里会分享一些出现频率极其极其高的面试题,初定周更一篇,什么时候更完什么时候停止。
-
- - [第一周(2018-8-7)](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/最最最常见的Java面试题总结/第一周(2018-8-7).md) (为什么 Java 中只有值传递、==与equals、 hashCode与equals)
- - [第二周(2018-8-13)](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/最最最常见的Java面试题总结/第二周(2018-8-13).md)(String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?、什么是反射机制?反射机制的应用场景有哪些?......)
- - [第三周(2018-08-22)](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/这几道Java集合框架面试题几乎必问.md) (Arraylist 与 LinkedList 异同、ArrayList 与 Vector 区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体实现、集合框架底层数据结构总结)
- - [第四周(2018-8-30).md](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/最最最常见的Java面试题总结/第四周(2018-8-30).md) (主要内容是几道面试常问的多线程基础题。)
-- ### 程序员如何写简历
- - [程序员的简历之道](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/程序员的简历之道.md)
- - [手把手教你用Markdown写一份高质量的简历](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/手把手教你用Markdown写一份高质量的简历.md)
-
-## :art: 其他
-
-- ### 个人书单推荐
- - [个人阅读书籍清单](https://github.com/Snailclimb/Java-Guide/blob/master/其他/个人阅读书籍清单.md)
-
-- ### 技术方向选择
- - [选择技术方向都要考虑哪些因素](https://github.com/Snailclimb/Java-Guide/blob/master/其他/选择技术方向都要考虑哪些因素.md)
-
-- ### 2018 年秋招简单回顾
- - [结束了我短暂的秋招,说点自己的感受](https://github.com/Snailclimb/JavaGuide/blob/master/%E5%85%B6%E4%BB%96/2018%20%E7%A7%8B%E6%8B%9B.md)
-
+点击订阅[Java面试进阶指南](https://xiaozhuanlan.com/javainterview?rel=javaguide)(专为Java面试方向准备)。[为什么要弄这个专栏?](https://shimo.im/docs/9BJjNsNg7S4dCnz3/)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Special Sponsors
+
+
+
+
+
+
+
+推荐一下我的另外一个正在维护的项目:[programmer-advancement](https://github.com/Snailclimb/programmer-advancement) (技术人员成长必备!)
+
+推荐使用 在线阅读(访问速度慢的话,请使用 ),在线阅读内容本仓库同步一致。这种方式阅读的优势在于:有侧边栏阅读体验更好,Gitee pages 的访问速度相对来说也比较快。
+
+## 目录
+
+- [Java](#java)
+ - [基础](#基础)
+ - [容器](#容器)
+ - [并发](#并发)
+ - [JVM](#jvm)
+ - [I/O](#io)
+ - [Java 8](#java-8)
+ - [编程规范](#编程规范)
+- [网络](#网络)
+- [操作系统](#操作系统)
+ - [Linux相关](#linux相关)
+- [数据结构与算法](#数据结构与算法)
+ - [数据结构](#数据结构)
+ - [算法](#算法)
+- [数据库](#数据库)
+ - [MySQL](#mysql)
+ - [Redis](#redis)
+- [系统设计](#系统设计)
+ - [设计模式](#设计模式)
+ - [常用框架](#常用框架)
+ - [数据通信](#数据通信)
+ - [网站架构](#网站架构)
+- [面试指南](#面试指南)
+ - [备战面试](#备战面试)
+ - [常见面试题总结](#常见面试题总结)
+ - [面经](#面经)
+- [工具](#工具)
+ - [Git](#git)
+ - [Docker](#Docker)
+- [资料](#资料)
+ - [书单](#书单)
+ - [Github榜单](#Github榜单)
+- [待办](#待办)
+- [说明](#说明)
+
+## Java
+
+### 基础
+
+* [Java 基础知识回顾](docs/java/Java基础知识.md)
+* [J2EE 基础知识回顾](docs/java/J2EE基础知识.md)
+* [Collections 工具类和 Arrays 工具类常见方法](docs/java/Basis/Arrays%2CCollectionsCommonMethods.md)
+* [Java常见关键字总结:static、final、this、super](docs/java/Basis/final、static、this、super.md)
+
+### 容器
+
+* **常见问题总结:**
+ * [这几道Java集合框架面试题几乎必问](docs/java/这几道Java集合框架面试题几乎必问.md)
+ * [Java 集合框架常见面试题总结](docs/java/Java集合框架常见面试题总结.md)
+* **源码分析:**
+ * [ArrayList 源码学习](docs/java/ArrayList.md)
+ * [【面试必备】透过源码角度一步一步带你分析 ArrayList 扩容机制](docs/java/ArrayList-Grow.md)
+ * [LinkedList 源码学习](docs/java/LinkedList.md)
+ * [HashMap(JDK1.8)源码学习](docs/java/HashMap.md)
+
+### 并发
+
+* [Java 并发基础常见面试题总结](docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md)
+* [Java 并发进阶常见面试题总结](docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md)
+* [并发编程面试必备:synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReentrantLock 的对比](docs/java/synchronized.md)
+* [并发编程面试必备:乐观锁与悲观锁](docs/essential-content-for-interview/面试必备之乐观锁与悲观锁.md)
+* [并发编程面试必备:JUC 中的 Atomic 原子类总结](docs/java/Multithread/Atomic.md)
+* [并发编程面试必备:AQS 原理以及 AQS 同步组件总结](docs/java/Multithread/AQS.md)
+* [并发容器总结](docs/java/Multithread/并发容器总结.md)
+
+### JVM
+
+* [Java内存区域章](docs/java/可能是把Java内存区域讲的最清楚的一篇文章.md)
+* [JVM垃圾回收](docs/java/搞定JVM垃圾回收就是这么简单.md)
+* [《深入理解Java虚拟机》第2版学习笔记](docs/java/Java虚拟机(jvm).md)
+
+### I/O
+
+* [BIO,NIO,AIO 总结 ](docs/java/BIO-NIO-AIO.md)
+* [Java IO 与 NIO系列文章](docs/java/Java%20IO与NIO.md)
+
+### Java 8
+
+* [Java 8 新特性总结](docs/java/What's%20New%20in%20JDK8/Java8Tutorial.md)
+* [Java 8 学习资源推荐](docs/java/What's%20New%20in%20JDK8/Java8教程推荐.md)
+
+### 编程规范
+
+- [Java 编程规范](docs/java/Java编程规范.md)
+
+## 网络
+
+* [计算机网络常见面试题](docs/network/计算机网络.md)
+* [计算机网络基础知识总结](docs/network/干货:计算机网络知识总结.md)
+* [HTTPS中的TLS](docs/network/HTTPS中的TLS.md)
+
+## 操作系统
+
+### Linux相关
+
+* [后端程序员必备的 Linux 基础知识](docs/operating-system/后端程序员必备的Linux基础知识.md)
+* [Shell 编程入门](docs/operating-system/Shell.md)
+
+## 数据结构与算法
+
+### 数据结构
+
+- [数据结构知识学习与面试](docs/dataStructures-algorithms/数据结构.md)
+
+### 算法
+
+- [算法学习资源推荐](docs/dataStructures-algorithms/算法学习资源推荐.md)
+- [算法总结——几道常见的子符串算法题 ](docs/dataStructures-algorithms/几道常见的子符串算法题.md)
+- [算法总结——几道常见的链表算法题 ](docs/dataStructures-algorithms/几道常见的链表算法题.md)
+- [剑指offer部分编程题](docs/dataStructures-algorithms/剑指offer部分编程题.md)
+- [公司真题](docs/dataStructures-algorithms/公司真题.md)
+- [回溯算法经典案例之N皇后问题](docs/dataStructures-algorithms/Backtracking-NQueens.md)
+
+## 数据库
+
+### MySQL
+
+* [MySQL 学习与面试](docs/database/MySQL.md)
+* [一千行MySQL学习笔记](docs/database/一千行MySQL命令.md)
+* [MySQL高性能优化规范建议](docs/database/MySQL高性能优化规范建议.md)
+* [搞定数据库索引就是这么简单](docs/database/MySQL%20Index.md)
+* [事务隔离级别(图文详解)](docs/database/事务隔离级别(图文详解).md)
+* [一条SQL语句在MySQL中如何执行的](docs/database/一条sql语句在mysql中如何执行的.md)
+
+### Redis
+
+* [Redis 总结](docs/database/Redis/Redis.md)
+* [Redlock分布式锁](docs/database/Redis/Redlock分布式锁.md)
+* [如何做可靠的分布式锁,Redlock真的可行么](docs/database/Redis/如何做可靠的分布式锁,Redlock真的可行么.md)
+
+## 系统设计
+
+### 设计模式
+
+- [设计模式系列文章](docs/system-design/设计模式.md)
+
+### 常用框架
+
+#### Spring
+
+- [Spring 学习与面试](docs/system-design/framework/Spring学习与面试.md)
+- [Spring中bean的作用域与生命周期](docs/system-design/framework/SpringBean.md)
+- [SpringMVC 工作原理详解](docs/system-design/framework/SpringMVC%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3.md)
+
+#### ZooKeeper
+
+- [可能是把 ZooKeeper 概念讲的最清楚的一篇文章](docs/system-design/framework/ZooKeeper.md)
+- [ZooKeeper 数据模型和常见命令了解一下,速度收藏!](docs/system-design/framework/ZooKeeper数据模型和常见命令.md)
+
+### 数据通信
+
+- [数据通信(RESTful、RPC、消息队列)相关知识点总结](docs/system-design/data-communication/数据通信(RESTful、RPC、消息队列).md)
+- [Dubbo 总结:关于 Dubbo 的重要知识点](docs/system-design/data-communication/dubbo.md)
+- [消息队列总结:新手也能看懂,消息队列其实很简单](docs/system-design/data-communication/message-queue.md)
+- [一文搞懂 RabbitMQ 的重要概念以及安装](docs/system-design/data-communication/rabbitmq.md)
+
+### 网站架构
+
+- [一文读懂分布式应该学什么](docs/system-design/website-architecture/分布式.md)
+- [8 张图读懂大型网站技术架构](docs/system-design/website-architecture/8%20张图读懂大型网站技术架构.md)
+- [【面试精选】关于大型网站系统架构你不得不懂的10个问题](docs/system-design/website-architecture/【面试精选】关于大型网站系统架构你不得不懂的10个问题.md)
+
+## 面试指南
+
+### 备战面试
+
+* [【备战面试1】程序员的简历就该这样写](docs/essential-content-for-interview/PreparingForInterview/程序员的简历之道.md)
+* [【备战面试2】初出茅庐的程序员该如何准备面试?](docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md)
+* [【备战面试3】7个大部分程序员在面试前很关心的问题](docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md)
+* [【备战面试4】Github上开源的Java面试/学习相关的仓库推荐](docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md)
+* [【备战面试5】如果面试官问你“你有什么问题问我吗?”时,你该如何回答](docs/essential-content-for-interview/PreparingForInterview/如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md)
+* [【备战面试6】美团面试常见问题总结(附详解答案)](docs/essential-content-for-interview/PreparingForInterview/美团面试常见问题总结.md)
+
+### 常见面试题总结
+
+* [第一周(2018-8-7)](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第一周(2018-8-7).md) (为什么 Java 中只有值传递、==与equals、 hashCode与equals)
+* [第二周(2018-8-13)](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第二周(2018-8-13).md)(String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?、什么是反射机制?反射机制的应用场景有哪些?......)
+* [第三周(2018-08-22)](docs/java/这几道Java集合框架面试题几乎必问.md) (Arraylist 与 LinkedList 异同、ArrayList 与 Vector 区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体实现、集合框架底层数据结构总结)
+* [第四周(2018-8-30).md](docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/第四周(2018-8-30).md) (主要内容是几道面试常问的多线程基础题。)
+
+### 面经
+
+- [5面阿里,终获offer(2018年秋招)](docs/essential-content-for-interview/BATJrealInterviewExperience/5面阿里,终获offer.md)
+- [蚂蚁金服2019实习生面经总结(已拿口头offer)](docs/essential-content-for-interview/BATJrealInterviewExperience/蚂蚁金服实习生面经总结(已拿口头offer).md)
+- [2019年蚂蚁金服、头条、拼多多的面试总结](docs/essential-content-for-interview/BATJrealInterviewExperience/2019alipay-pinduoduo-toutiao.md)
+
+## 工具
+
+### Git
+
+* [Git入门](docs/tools/Git.md)
+
+### Docker
+
+* [Docker 入门](docs/tools/Docker.md)
+* [一文搞懂 Docker 镜像的常用操作!](docs/tools/Docker-Image.md)
+
+## 资料
+
+### 书单
+
+- [Java程序员必备书单](docs/data/java-recommended-books.md)
+
+### Github榜单
+
+- [Java 项目月榜单](docs/github-trending/JavaGithubTrending.md)
***
-> # :envelope: 该开源文档一些说明
+## 待办
+
+- [x] [Java 8 新特性总结](docs/java/What's%20New%20in%20JDK8/Java8Tutorial.md)
+- [x] [Java 8 新特性详解](docs/java/What's%20New%20in%20JDK8/Java8教程推荐.md)
+- [ ] Java 多线程类别知识重构(---正在进行中---)
+- [x] [BIO,NIO,AIO 总结 ](docs/java/BIO-NIO-AIO.md)
+- [ ] Netty 总结(---正在进行中---)
+- [ ] 数据结构总结重构(---正在进行中---)
+
+## 说明
+
+### 介绍
+
+* **对于 Java 初学者来说:** 本文档倾向于给你提供一个比较详细的学习路径,让你对于Java整体的知识体系有一个初步认识。另外,本文的一些文章
+也是你学习和复习 Java 知识不错的实践;
+* **对于非 Java 初学者来说:** 本文档更适合回顾知识,准备面试,搞清面试应该把重心放在那些问题上。要搞清楚这个道理:提前知道那些面试常见,不是为了背下来应付面试,而是为了让你可以更有针对的学习重点。
+
+Markdown 格式参考:[Github Markdown格式](https://guides.github.com/features/mastering-markdown/),表情素材来自:[EMOJI CHEAT SHEET](https://www.webpagefx.com/tools/emoji-cheat-sheet/)。
+
+利用 docsify 生成文档部署在 Github pages: [docsify 官网介绍](https://docsify.js.org/#/)
+
+### 关于转载
+
+如果你需要转载本仓库的一些文章到自己的博客的话,记得注明原文地址就可以了。
+
+### 如何对该开源文档进行贡献
+
+1. 笔记内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。
+2. 很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。
+3. 现有的知识点难免存在不完善或者错误,所以你可以对已有知识点的修改/补充。
+
+### 为什么要做这个开源文档?
-## 介绍
-该文档主要是笔主在学习Java的过程中的一些学习笔记,但是为了能够涉及到大部分后端学习所需的技术知识点我也会偶尔引用一些别人的优秀文章的链接。
-该文档涉及的主要内容包括: Java、 数据结构与算法、计算机网络与数据通信、 操作系统、主流框架、数据存储、架构、面试必备知识点等等。相信不论你是前端还是后端都能在这份文档中收获到东西。
-## 关于转载
+初始想法源于自己的个人那一段比较迷茫的学习经历。主要目的是为了通过这个开源平台来帮助一些在学习 Java 或者面试过程中遇到问题的小伙伴。
-**如果需要引用到本仓库的一些东西,必须注明转载地址!!!毕竟大多都是手敲的,或者引用的是我的原创文章,希望大家尊重一下作者的劳动**:smiley::smiley::smiley:!
+### 投稿
-## 如何对该开源文档进行贡献
+由于我个人能力有限,很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。大家也可以对自己的文章进行自荐,对于不错的文章不仅可以成功在本仓库展示出来更可以获得作者送出的 50 元左右的任意书籍进行奖励(当然你也可以直接折现50元)。
-1. 笔记内容大多是手敲,所以难免会有笔误。
-2. 你对其他知识点的补充。
+### 联系我
-## 为什么要做这个开源文档?
+添加我的微信备注“Github”,回复关键字 **“加群”** 即可入群。
-在我们学习Java的时候,很多人会面临我不知道继续学什么或者面试会问什么的尴尬情况(我本人之前就很迷茫:smile:)。所以,我决定通过这个开源平台来帮助一些有需要的人,通过下面的内容,你会掌握系统的Java学习以及面试的相关知识。本来是想通过Gitbook的形式来制作的,后来想了想觉得可能有点大题小做 :grin: 。另外,我自己一个人的力量毕竟有限,希望各位有想法的朋友可以提issue。
+
-## 最后
+### Contributor
-本人会利用业余时间一直更新下去,目前还有很多地方不完善,一些知识点我会原创总结,还有一些知识点如果说网上有比较好的文章了,我会把这些文章加入进去。您也可以关注我的微信公众号:“Java面试通关手册”,我会在这里分享一些自己的原创文章。 另外该文档格式参考:[Github Markdown格式](https://guides.github.com/features/mastering-markdown/),表情素材来自:[EMOJI CHEAT SHEET](https://www.webpagefx.com/tools/emoji-cheat-sheet/)。
+下面是笔主收集的一些对本仓库提过有价值的pr或者issue的朋友,人数较多,如果你也对本仓库提过不错的pr或者issue的话,你可以加我的微信与我联系。下面的排名不分先后!
-## 阿里云活动推荐
-阿里云双11最新活动(仅限阿里云新用户购买,老用户拉新用户可以获得返现红包,后续有机会平分百万红包),优惠力度非常非常非常大,另外加入拼团,后续还有几乎平分100w红包!划重点了:1核2G云服务器1年仅需99.5元!!!该折扣仅限新人!这是我的拼团团队地址:https://m.aliyun.com/act/team1111/#/share?params=N.FF7yxCciiM.hf47liqn (如果还有不懂的可以加我微信:bwcx9393 咨询) 举个栗子:以原价1020元的云服务器ECS(t5 1c2g+1M+40G高效云盘) 为例,双11新用户专享价为199元,如果您成功拉一个新人拼团,您和团员都将享受折上9折优惠,199*90%=179.1元,将返还您和团员每人19.9元。随着您拉新人数增多,享受折扣将不断叠加, 当您参加的团中有6个及以上新用户时,您和团员即可享受折上5折优惠,即199元的云服务器再打5折,可享受99.5元的优惠价,将返还您和团员购买价减去99.5元的差价。希望大家加入拼团之后尽自己力量邀请时候身边的阿里云新人参团,这样你可以获得最高1111的红包,而且后面如果团队拉的新人在前100名的话就可以平分100w红包。老用户也可以选择参加下面的活动!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-> 阿里云技术有保障,在云服务技术上远远领先于国内其他云服务提供商。大家或者公司如果需要用到云服务器的话,推荐阿里云服务器,下面是阿里云目前正在做的一些活动,错过这波,后续可能多花很多钱:
+### 公众号
-1. [全民云计算:ECS云服务器2折起,1核1G仅需293元/年](https://promotion.aliyun.com/ntms/act/qwbk.html?userCode=hf47liqn)
-2. [高性能企业级性能云服务器限时2折起,2核4G仅需720元/年](https://promotion.aliyun.com/ntms/act/enterprise-discount.html?userCode=hf47liqn)
-3. [拉1人拼团,立享云服务器¥234/年](https://promotion.aliyun.com/ntms/act/vmpt/aliyun-group/home.html?spm=5176.8849694.home.4.27a24b70kENhtV&userCode=hf47liqn)
-4. [最高¥1888云产品通用代金券](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=hf47liqn)
-5. [阿里云建站服务](https://promotion.aliyun.com/ntms/act/jianzhanquan.html?userCode=hf47liqn)(企业官网、电商网站,多种可供选择模板,代金券免费领取)
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
-**你若盛开,清风自来。 欢迎关注我的微信公众号:“Java面试通关手册”,一个有温度的微信公众号。公众号有大量资料,回复关键字“1”你可能看到想要的东西哦!:**
+**Java工程师必备学习资源:** 一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
-
+
diff --git a/docs/.nojekyll b/docs/.nojekyll
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/docs/HomePage.md b/docs/HomePage.md
new file mode 100644
index 00000000000..43c740363e2
--- /dev/null
+++ b/docs/HomePage.md
@@ -0,0 +1,215 @@
+Java后端技术交流群(限工作一年及以上,架构视频免费领取) :[](https://jq.qq.com/?_wv=1027&k=5QqyxIx)
+
+点击订阅[Java面试进阶指南](https://xiaozhuanlan.com/javainterview?rel=javaguide)(专为Java面试方向准备)。[为什么要弄这个专栏?](https://shimo.im/docs/9BJjNsNg7S4dCnz3/)
+
+Java 学习/面试指南
+
+
+
+
+
+Special Sponsors
+
+
+
+
+
+
+
+## Java
+
+### 基础
+
+* [Java 基础知识回顾](java/Java基础知识.md)
+* [J2EE 基础知识回顾](java/J2EE基础知识.md)
+* [Collections 工具类和 Arrays 工具类常见方法](java/Basis/Arrays%2CCollectionsCommonMethods.md)
+* [Java常见关键字总结:static、final、this、super](java/Basis/final、static、this、super.md)
+
+### 容器
+
+* **常见问题总结:**
+ * [这几道Java集合框架面试题几乎必问](java/这几道Java集合框架面试题几乎必问.md)
+ * [Java 集合框架常见面试题总结](java/Java集合框架常见面试题总结.md)
+* **源码分析:**
+ * [ArrayList 源码学习](java/ArrayList.md)
+ * [【面试必备】透过源码角度一步一步带你分析 ArrayList 扩容机制](java/ArrayList-Grow.md)
+ * [LinkedList 源码学习](java/LinkedList.md)
+ * [HashMap(JDK1.8)源码学习](java/HashMap.md)
+
+### 并发
+* [Java 并发基础常见面试题总结](java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md)
+* [Java 并发进阶常见面试题总结](java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md)
+* [并发编程面试必备:synchronized 关键字使用、底层原理、JDK1.6 之后的底层优化以及 和ReentrantLock 的对比](java/synchronized.md)
+* [并发编程面试必备:乐观锁与悲观锁](essential-content-for-interview/面试必备之乐观锁与悲观锁.md)
+* [并发编程面试必备:JUC 中的 Atomic 原子类总结](java/Multithread/Atomic.md)
+* [并发编程面试必备:AQS 原理以及 AQS 同步组件总结](java/Multithread/AQS.md)
+* [并发容器总结](java/Multithread/并发容器总结.md)
+
+### JVM
+
+* [可能是把Java内存区域讲的最清楚的一篇文章](java/可能是把Java内存区域讲的最清楚的一篇文章.md)
+* [搞定JVM垃圾回收就是这么简单](java/搞定JVM垃圾回收就是这么简单.md)
+* [《深入理解Java虚拟机》第2版学习笔记](java/Java虚拟机(jvm).md)
+
+### I/O
+
+* [BIO,NIO,AIO 总结 ](java/BIO-NIO-AIO.md)
+* [Java IO 与 NIO系列文章](java/Java%20IO与NIO.md)
+
+### Java 8
+
+* [Java 8 新特性总结](java/What's%20New%20in%20JDK8/Java8Tutorial.md)
+* [Java 8 学习资源推荐](java/What's%20New%20in%20JDK8/Java8教程推荐.md)
+
+### 编程规范
+
+- [Java 编程规范](java/Java编程规范.md)
+
+## 网络
+
+* [计算机网络常见面试题](network/计算机网络.md)
+* [计算机网络基础知识总结](network/干货:计算机网络知识总结.md)
+* [HTTPS中的TLS](network/HTTPS中的TLS.md)
+
+## 操作系统
+
+### Linux相关
+
+* [后端程序员必备的 Linux 基础知识](operating-system/后端程序员必备的Linux基础知识.md)
+* [Shell 编程入门](operating-system/Shell.md)
+
+## 数据结构与算法
+
+### 数据结构
+
+- [数据结构知识学习与面试](dataStructures-algorithms/数据结构.md)
+
+### 算法
+
+- [算法学习资源推荐](dataStructures-algorithms/算法学习资源推荐.md)
+- [算法总结——几道常见的子符串算法题 ](dataStructures-algorithms/几道常见的子符串算法题.md)
+- [算法总结——几道常见的链表算法题 ](dataStructures-algorithms/几道常见的链表算法题.md)
+- [剑指offer部分编程题](dataStructures-algorithms/剑指offer部分编程题.md)
+- [公司真题](dataStructures-algorithms/公司真题.md)
+- [回溯算法经典案例之N皇后问题](dataStructures-algorithms/Backtracking-NQueens.md)
+
+## 数据库
+
+### MySQL
+
+* [MySQL 学习与面试](database/MySQL.md)
+* [一千行MySQL学习笔记](database/一千行MySQL命令.md)
+* [MySQL高性能优化规范建议](database/MySQL高性能优化规范建议.md)
+* [搞定数据库索引就是这么简单](database/MySQL%20Index.md)
+* [事务隔离级别(图文详解)](database/事务隔离级别(图文详解).md)
+* [一条SQL语句在MySQL中如何执行的](database/一条sql语句在mysql中如何执行的.md)
+
+### Redis
+
+* [Redis 总结](database/Redis/Redis.md)
+* [Redlock分布式锁](database/Redis/Redlock分布式锁.md)
+* [如何做可靠的分布式锁,Redlock真的可行么](database/Redis/如何做可靠的分布式锁,Redlock真的可行么.md)
+
+## 系统设计
+
+### 设计模式
+
+- [设计模式系列文章](system-design/设计模式.md)
+
+### 常用框架
+
+#### Spring
+
+- [Spring 学习与面试](system-design/framework/Spring学习与面试.md)
+- [Spring中bean的作用域与生命周期](system-design/framework/SpringBean.md)
+- [SpringMVC 工作原理详解](system-design/framework/SpringMVC%20%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E8%AF%A6%E8%A7%A3.md)
+
+#### ZooKeeper
+
+- [可能是把 ZooKeeper 概念讲的最清楚的一篇文章](system-design/framework/ZooKeeper.md)
+- [ZooKeeper 数据模型和常见命令了解一下,速度收藏!](system-design/framework/ZooKeeper数据模型和常见命令.md)
+
+### 数据通信
+
+- [数据通信(RESTful、RPC、消息队列)相关知识点总结](system-design/data-communication/数据通信(RESTful、RPC、消息队列).md)
+- [Dubbo 总结:关于 Dubbo 的重要知识点](system-design/data-communication/dubbo.md)
+- [消息队列总结:新手也能看懂,消息队列其实很简单](system-design/data-communication/message-queue.md)
+- [一文搞懂 RabbitMQ 的重要概念以及安装](system-design/data-communication/rabbitmq.md)
+
+### 网站架构
+
+- [一文读懂分布式应该学什么](system-design/website-architecture/分布式.md)
+- [8 张图读懂大型网站技术架构](system-design/website-architecture/8%20张图读懂大型网站技术架构.md)
+- [【面试精选】关于大型网站系统架构你不得不懂的10个问题](system-design/website-architecture/【面试精选】关于大型网站系统架构你不得不懂的10个问题.md)
+
+## 面试指南
+
+### 备战面试
+
+* [【备战面试1】程序员的简历就该这样写](essential-content-for-interview/PreparingForInterview/程序员的简历之道.md)
+* [【备战面试2】初出茅庐的程序员该如何准备面试?](essential-content-for-interview/PreparingForInterview/interviewPrepare.md)
+* [【备战面试3】7个大部分程序员在面试前很关心的问题](essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md)
+* [【备战面试4】Github上开源的Java面试/学习相关的仓库推荐](essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md)
+* [【备战面试5】如果面试官问你“你有什么问题问我吗?”时,你该如何回答](essential-content-for-interview/PreparingForInterview/如果面试官问你“你有什么问题问我吗?”时,你该如何回答.md)
+* [【备战面试6】美团面试常见问题总结(附详解答案)](essential-content-for-interview/PreparingForInterview/美团面试常见问题总结.md)
+
+### 常见面试题总结
+
+* [第一周(2018-8-7)](essential-content-for-interview/MostCommonJavaInterviewQuestions/第一周(2018-8-7).md) (为什么 Java 中只有值传递、==与equals、 hashCode与equals)
+* [第二周(2018-8-13)](essential-content-for-interview/MostCommonJavaInterviewQuestions/第二周(2018-8-13).md)(String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?、什么是反射机制?反射机制的应用场景有哪些?......)
+* [第三周(2018-08-22)](java/这几道Java集合框架面试题几乎必问.md) (Arraylist 与 LinkedList 异同、ArrayList 与 Vector 区别、HashMap的底层实现、HashMap 和 Hashtable 的区别、HashMap 的长度为什么是2的幂次方、HashSet 和 HashMap 区别、ConcurrentHashMap 和 Hashtable 的区别、ConcurrentHashMap线程安全的具体实现方式/底层具体实现、集合框架底层数据结构总结)
+* [第四周(2018-8-30).md](essential-content-for-interview/MostCommonJavaInterviewQuestions/第四周(2018-8-30).md) (主要内容是几道面试常问的多线程基础题。)
+
+### 面经
+
+- [5面阿里,终获offer(2018年秋招)](essential-content-for-interview/BATJrealInterviewExperience/5面阿里,终获offer.md)
+- [蚂蚁金服2019实习生面经总结(已拿口头offer)](essential-content-for-interview/BATJrealInterviewExperience/蚂蚁金服实习生面经总结(已拿口头offer).md)
+- [2019年蚂蚁金服、头条、拼多多的面试总结](essential-content-for-interview/BATJrealInterviewExperience/2019alipay-pinduoduo-toutiao.md)
+
+## 工具
+
+### Git
+
+* [Git入门](tools/Git.md)
+
+### Docker
+
+* [Docker 入门](tools/Docker.md)
+* [一文搞懂 Docker 镜像的常用操作!](tools/Docker-Image.md)
+
+## 资料
+
+### 书单
+
+- [Java程序员必备书单](data/java-recommended-books.md)
+
+### Github榜单
+
+- [Java 项目月榜单](github-trending/JavaGithubTrending.md)
+
+***
+
+## 待办
+
+- [x] [Java 8 新特性总结](./java/What's%20New%20in%20JDK8/Java8Tutorial.md)
+- [x] [Java 8 新特性详解](./java/What's%20New%20in%20JDK8/Java8教程推荐.md)
+- [ ] Java 多线程类别知识重构(---正在进行中---)
+- [x] [BIO,NIO,AIO 总结 ](./java/BIO-NIO-AIO.md)
+- [ ] Netty 总结(---正在进行中---)
+- [ ] 数据结构总结重构(---正在进行中---)
+
+## 联系我
+
+添加我的微信备注“Github”,回复关键字 **“加群”** 即可入群。
+
+
+
+## 公众号
+
+- 如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+- 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本公众号后台回复 **"Java面试突击"** 即可免费领取!
+- 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
+
+
+
+
diff --git a/docs/_coverpage.md b/docs/_coverpage.md
new file mode 100644
index 00000000000..612cd2160ec
--- /dev/null
+++ b/docs/_coverpage.md
@@ -0,0 +1,10 @@
+
+
+
+
+Java 学习/面试指南
+
+[常用资源](https://shimo.im/docs/MuiACIg1HlYfVxrj/)
+[GitHub]()
+[开始阅读](#java)
+
diff --git a/docs/data/java-recommended-books.md b/docs/data/java-recommended-books.md
new file mode 100644
index 00000000000..7f387ce46ae
--- /dev/null
+++ b/docs/data/java-recommended-books.md
@@ -0,0 +1,115 @@
+
+
+
+- [Java](#java)
+ - [基础](#基础)
+ - [并发](#并发)
+ - [JVM](#jvm)
+ - [Java8 新特性](#java8-新特性)
+ - [代码优化](#代码优化)
+- [网络](#网络)
+- [操作系统](#操作系统)
+- [数据结构与算法](#数据结构与算法)
+- [数据库](#数据库)
+- [系统设计](#系统设计)
+ - [设计模式](#设计模式)
+ - [常用框架](#常用框架)
+ - [网站架构](#网站架构)
+ - [软件底层](#软件底层)
+- [其他](#其他)
+
+
+## Java
+
+### 基础
+
+- [《Head First Java》](https://book.douban.com/subject/2000732/)(推荐,豆瓣评分 8.7,1.0K+人评价): 可以说是我的 Java 启蒙书籍了,特别适合新手读当然也适合我们用来温故 Java 知识点。
+- [《Java 核心技术卷 1+卷 2》](https://book.douban.com/subject/25762168/)(推荐): 很棒的两本书,建议有点 Java 基础之后再读,介绍的还是比较深入的,非常推荐。这两本书我一般也会用来巩固知识点,是两本适合放在自己身边的好书。
+- [《JAVA 网络编程 第 4 版》](https://book.douban.com/subject/26259017/): 可以系统的学习一下网络的一些概念以及网络编程在 Java 中的使用。
+- [《Java 编程思想 (第 4 版)》](https://book.douban.com/subject/2130190/)(推荐,豆瓣评分 9.1,3.2K+人评价):大部分人称之为Java领域的圣经,但我不推荐初学者阅读,有点劝退的味道。稍微有点基础后阅读更好。
+
+### 并发
+
+- [《Java 并发编程之美》]() (推荐):2018 年 10 月出版的一本书,个人感觉非常不错,对每个知识点的讲解都很棒。
+- [《Java 并发编程的艺术》](https://book.douban.com/subject/26591326/)(推荐,豆瓣评分 7.2,0.2K+人评价): 这本书不是很适合作为 Java 并发入门书籍,需要具备一定的 JVM 基础。我感觉有些东西讲的还是挺深入的,推荐阅读。
+- [《实战 Java 高并发程序设计》](https://book.douban.com/subject/26663605/)(推荐,豆瓣评分 8.3): 书的质量没的说,推荐大家好好看一下。
+- [《Java 高并发编程详解》](https://book.douban.com/subject/30255689/)(豆瓣评分 7.6): 2018 年 6 月出版的一本书,内容很详细,但可能又有点过于啰嗦,不过这只是我的感觉。
+
+### JVM
+
+- [《深入理解 Java 虚拟机(第 2 版)周志明》](https://book.douban.com/subject/24722612/)(推荐,豆瓣评分 8.9,1.0K+人评价):建议多刷几遍,书中的所有知识点可以通过 JAVA 运行时区域和 JAVA 的内存模型与线程两个大模块罗列完全。
+- [《实战 JAVA 虚拟机》](https://book.douban.com/subject/26354292/)(推荐,豆瓣评分 8.0,1.0K+人评价):作为入门的了解 Java 虚拟机的知识还是不错的。
+
+### Java8 新特性
+
+- [《Java 8 实战》](https://book.douban.com/subject/26772632/) (推荐,豆瓣评分 9.2 ):面向 Java 8 的技能升级,包括 Lambdas、流和函数式编程特性。实战系列的一贯风格让自己快速上手应用起来。Java 8 支持的 Lambda 是精简表达在语法上提供的支持。Java 8 提供了 Stream,学习和使用可以建立流式编程的认知。
+- [《Java 8 编程参考官方教程》](https://book.douban.com/subject/26556574/) (推荐,豆瓣评分 9.2):也还不错吧。
+
+### 代码优化
+
+- [《重构_改善既有代码的设计》](https://book.douban.com/subject/4262627/)(推荐):豆瓣 9.1 分,重构书籍的开山鼻祖。
+- [《Effective java 》](https://book.douban.com/subject/3360807/)(推荐,豆瓣评分 9.0,1.4K+人评价):本书介绍了在 Java 编程中 78 条极具实用价值的经验规则,这些经验规则涵盖了大多数开发人员每天所面临的问题的解决方案。通过对 Java 平台设计专家所使用的技术的全面描述,揭示了应该做什么,不应该做什么才能产生清晰、健壮和高效的代码。本书中的每条规则都以简短、独立的小文章形式出现,并通过例子代码加以进一步说明。本书内容全面,结构清晰,讲解详细。可作为技术人员的参考用书。
+- [《代码整洁之道》](https://book.douban.com/subject/5442024/)(推荐,豆瓣评分 9.1):虽然是用 Java 语言作为例子,全篇都是在阐述 Java 面向对象的思想,但是其中大部分内容其它语言也能应用到。
+- **阿里巴巴 Java 开发手册(详尽版)** [https://github.com/alibaba/p3c/blob/master/阿里巴巴 Java 开发手册(详尽版).pdf](https://github.com/alibaba/p3c/blob/master/%E9%98%BF%E9%87%8C%E5%B7%B4%E5%B7%B4Java%E5%BC%80%E5%8F%91%E6%89%8B%E5%86%8C%EF%BC%88%E8%AF%A6%E5%B0%BD%E7%89%88%EF%BC%89.pdf)
+- **Google Java 编程风格指南:**
+
+
+## 网络
+
+- [《图解 HTTP》](https://book.douban.com/subject/25863515/)(推荐,豆瓣评分 8.1 , 1.6K+人评价): 讲漫画一样的讲 HTTP,很有意思,不会觉得枯燥,大概也涵盖也 HTTP 常见的知识点。因为篇幅问题,内容可能不太全面。不过,如果不是专门做网络方向研究的小伙伴想研究 HTTP 相关知识的话,读这本书的话应该来说就差不多了。
+- [《HTTP 权威指南》](https://book.douban.com/subject/10746113/) (推荐,豆瓣评分 8.6):如果要全面了解 HTTP 非此书不可!
+
+## 操作系统
+
+- [《鸟哥的 Linux 私房菜》](https://book.douban.com/subject/4889838/)(推荐,,豆瓣评分 9.1,0.3K+人评价):本书是最具知名度的 Linux 入门书《鸟哥的 Linux 私房菜基础学习篇》的最新版,全面而详细地介绍了 Linux 操作系统。全书分为 5 个部分:第一部分着重说明 Linux 的起源及功能,如何规划和安装 Linux 主机;第二部分介绍 Linux 的文件系统、文件、目录与磁盘的管理;第三部分介绍文字模式接口 shell 和管理系统的好帮手 shell 脚本,另外还介绍了文字编辑器 vi 和 vim 的使用方法;第四部分介绍了对于系统安全非常重要的 Linux 账号的管理,以及主机系统与程序的管理,如查看进程、任务分配和作业管理;第五部分介绍了系统管理员 (root) 的管理事项,如了解系统运行状况、系统服务,针对登录文件进行解析,对系统进行备份以及核心的管理等。
+
+## 数据结构与算法
+
+- [《大话数据结构》](https://book.douban.com/subject/6424904/)(推荐,豆瓣评分 7.9 , 1K+人评价):入门类型的书籍,读起来比较浅显易懂,适合没有数据结构基础或者说数据结构没学好的小伙伴用来入门数据结构。
+- [《数据结构与算法分析: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 余所大学用作教材。
+- [《算法图解》](https://book.douban.com/subject/26979890/)(推荐,豆瓣评分 8.4,0.6K+人评价):入门类型的书籍,读起来比较浅显易懂,适合没有算法基础或者说算法没学好的小伙伴用来入门。示例丰富,图文并茂,以让人容易理解的方式阐释了算法.读起来比较快,内容不枯燥!
+- [《算法 第四版》](https://book.douban.com/subject/10432347/)(推荐,豆瓣评分 9.3,0.4K+人评价):Java 语言描述,算法领域经典的参考书,全面介绍了关于算法和数据结构的必备知识,并特别针对排序、搜索、图处理和字符串处理进行了论述。书的内容非常多,可以说是 Java 程序员的必备书籍之一了。
+
+## 数据库
+
+- [《高性能 MySQL》](https://book.douban.com/subject/23008813/)(推荐,豆瓣评分 9.3,0.4K+人评价):mysql 领域的经典之作,拥有广泛的影响力。不但适合数据库管理员(dba)阅读,也适合开发人员参考学习。不管是数据库新手还是专家,相信都能从本书有所收获。
+- [《Redis 实战》](https://book.douban.com/subject/26612779/):如果你想了解 Redis 的一些概念性知识的话,这本书真的非常不错。
+- [《Redis 设计与实现》](https://book.douban.com/subject/25900156/)(推荐,豆瓣评分 8.5,0.5K+人评价):也还行吧!
+- [《MySQL 技术内幕-InnoDB 存储引擎》]()(推荐,豆瓣评分 8.7):了解 InnoDB 存储引擎底层原理必备的一本书,比较深入。
+
+## 系统设计
+
+### 设计模式
+
+- [《设计模式 : 可复用面向对象软件的基础》 ](https://book.douban.com/subject/1052241/) (推荐,豆瓣评分 9.1):设计模式的经典!
+- [《Head First 设计模式(中文版)》](https://book.douban.com/subject/2243615/) (推荐,豆瓣评分 9.2):相当赞的一本设计模式入门书籍。用实际的编程案例讲解算法设计中会遇到的各种问题和需求变更(对的,连需求变更都考虑到了!),并以此逐步推导出良好的设计模式解决办法。
+
+### 常用框架
+
+- [《深入分析 Java Web 技术内幕》](https://book.douban.com/subject/25953851/): 感觉还行,涉及的东西也蛮多。
+- [《Netty 实战》](https://book.douban.com/subject/27038538/)(推荐,豆瓣评分 7.8,92 人评价):内容很细,如果想学 Netty 的话,推荐阅读这本书!
+- [《从 Paxos 到 Zookeeper》](https://book.douban.com/subject/26292004/)(推荐,豆瓣评分 7.8,0.3K 人评价):简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了 Paxos 和 ZAB 协议。同时,本书深入介绍了分布式一致性问题的工业解决方案——ZooKeeper,并着重向读者展示这一分布式协调框架的使用方法、内部实现及运维技巧,旨在帮助读者全面了解 ZooKeeper,并更好地使用和运维 ZooKeeper。
+- [《Spring 实战(第 4 版)》](https://book.douban.com/subject/26767354/)(推荐,豆瓣评分 8.3,0.3K+人评价):不建议当做入门书籍读,入门的话可以找点国人的书或者视频看。这本定位就相当于是关于 Spring 的新华字典,只有一些基本概念的介绍和示例,涵盖了 Spring 的各个方面,但都不够深入。就像作者在最后一页写的那样:“学习 Spring,这才刚刚开始”。
+- [《RabbitMQ 实战指南》](https://book.douban.com/subject/27591386/):《RabbitMQ 实战指南》从消息中间件的概念和 RabbitMQ 的历史切入,主要阐述 RabbitMQ 的安装、使用、配置、管理、运维、原理、扩展等方面的细节。如果你想浅尝 RabbitMQ 的使用,这本书是你最好的选择;如果你想深入 RabbitMQ 的原理,这本书也是你最好的选择;总之,如果你想玩转 RabbitMQ,这本书一定是最值得看的书之一
+- [《Spring Cloud 微服务实战》](https://book.douban.com/subject/27025912/):从时下流行的微服务架构概念出发,详细介绍了 Spring Cloud 针对微服务架构中几大核心要素的解决方案和基础组件。对于各个组件的介绍,《Spring Cloud 微服务实战》主要以示例与源码结合的方式来帮助读者更好地理解这些组件的使用方法以及运行原理。同时,在介绍的过程中,还包含了作者在实践中所遇到的一些问题和解决思路,可供读者在实践中作为参考。
+- [《第一本 Docker 书》](https://book.douban.com/subject/26780404/):Docker 入门书籍!
+
+### 网站架构
+
+- [《大型网站技术架构:核心原理与案例分析+李智慧》](https://book.douban.com/subject/25723064/)(推荐):这本书我读过,基本不需要你有什么基础啊~读起来特别轻松,但是却可以学到很多东西,非常推荐了。另外我写过这本书的思维导图,关注我的微信公众号:“Java 面试通关手册”回复“大型网站技术架构”即可领取思维导图。
+- [《亿级流量网站架构核心技术》](https://book.douban.com/subject/26999243/)(推荐):一书总结并梳理了亿级流量网站高可用和高并发原则,通过实例详细介绍了如何落地这些原则。本书分为四部分:概述、高可用原则、高并发原则、案例实战。从负载均衡、限流、降级、隔离、超时与重试、回滚机制、压测与预案、缓存、池化、异步化、扩容、队列等多方面详细介绍了亿级流量网站的架构核心技术,让读者看后能快速运用到实践项目中。
+
+### 软件底层
+
+- [《深入剖析 Tomcat》](https://book.douban.com/subject/10426640/)(推荐,豆瓣评分 8.4,0.2K+人评价):本书深入剖析 Tomcat 4 和 Tomcat 5 中的每个组件,并揭示其内部工作原理。通过学习本书,你将可以自行开发 Tomcat 组件,或者扩展已有的组件。 读完这本书,基本可以摆脱背诵面试题的尴尬。
+- [《深入理解 Nginx(第 2 版)》](https://book.douban.com/subject/26745255/):作者讲的非常细致,注释都写的都很工整,对于 Nginx 的开发人员非常有帮助。优点是细致,缺点是过于细致,到处都是代码片段,缺少一些抽象。
+
+## 其他
+
+- [《黑客与画家》](https://read.douban.com/ebook/387525/?dcs=subject-rec&dcm=douban&dct=2243615):这本书是硅谷创业之父,Y Combinator 创始人 Paul Graham 的文集。之所以叫这个名字,是因为作者认为黑客(并非负面的那个意思)与画家有着极大的相似性,他们都是在创造,而不是完成某个任务。
+
+
+
+
+
+
diff --git a/docs/dataStructures-algorithms/Backtracking-NQueens.md b/docs/dataStructures-algorithms/Backtracking-NQueens.md
new file mode 100644
index 00000000000..bac262d0fbb
--- /dev/null
+++ b/docs/dataStructures-algorithms/Backtracking-NQueens.md
@@ -0,0 +1,145 @@
+# N皇后
+[51. N皇后](https://leetcode-cn.com/problems/n-queens/)
+### 题目描述
+> n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
+>
+
+>
+上图为 8 皇后问题的一种解法。
+>
+给定一个整数 n,返回所有不同的 n 皇后问题的解决方案。
+>
+每一种解法包含一个明确的 n 皇后问题的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
+
+示例:
+
+```
+输入: 4
+输出: [
+ [".Q..", // 解法 1
+ "...Q",
+ "Q...",
+ "..Q."],
+
+ ["..Q.", // 解法 2
+ "Q...",
+ "...Q",
+ ".Q.."]
+]
+解释: 4 皇后问题存在两个不同的解法。
+```
+
+### 问题分析
+约束条件为每个棋子所在的行、列、对角线都不能有另一个棋子。
+
+使用一维数组表示一种解法,下标(index)表示行,值(value)表示该行的Q(皇后)在哪一列。
+每行只存储一个元素,然后递归到下一行,这样就不用判断行了,只需要判断列和对角线。
+### Solution1
+当result[row] = column时,即row行的棋子在column列。
+
+对于[0, row-1]的任意一行(i 行),若 row 行的棋子和 i 行的棋子在同一列,则有result[i] == column;
+若 row 行的棋子和 i 行的棋子在同一对角线,等腰直角三角形两直角边相等,即 row - i == Math.abs(result[i] - column)
+
+布尔类型变量 isValid 的作用是剪枝,减少不必要的递归。
+```
+public List> solveNQueens(int n) {
+ // 下标代表行,值代表列。如result[0] = 3 表示第1行的Q在第3列
+ int[] result = new int[n];
+ List> resultList = new LinkedList<>();
+ dfs(resultList, result, 0, n);
+ return resultList;
+}
+
+void dfs(List> resultList, int[] result, int row, int n) {
+ // 递归终止条件
+ if (row == n) {
+ List list = new LinkedList<>();
+ for (int x = 0; x < n; ++x) {
+ StringBuilder sb = new StringBuilder();
+ for (int y = 0; y < n; ++y)
+ sb.append(result[x] == y ? "Q" : ".");
+ list.add(sb.toString());
+ }
+ resultList.add(list);
+ return;
+ }
+ for (int column = 0; column < n; ++column) {
+ boolean isValid = true;
+ result[row] = column;
+ /*
+ * 逐行往下考察每一行。同列,result[i] == column
+ * 同对角线,row - i == Math.abs(result[i] - column)
+ */
+ for (int i = row - 1; i >= 0; --i) {
+ if (result[i] == column || row - i == Math.abs(result[i] - column)) {
+ isValid = false;
+ break;
+ }
+ }
+ if (isValid) dfs(resultList, result, row + 1, n);
+ }
+}
+```
+### Solution2
+使用LinkedList表示一种解法,下标(index)表示行,值(value)表示该行的Q(皇后)在哪一列。
+
+解法二和解法一的不同在于,相同列以及相同对角线的校验。
+将对角线抽象成【一次函数】这个简单的数学模型,根据一次函数的截距是常量这一特性进行校验。
+
+这里,我将右上-左下对角线,简称为“\”对角线;左上-右下对角线简称为“/”对角线。
+
+“/”对角线斜率为1,对应方程为y = x + b,其中b为截距。
+对于线上任意一点,均有y - x = b,即row - i = b;
+定义一个布尔类型数组anti_diag,将b作为下标,当anti_diag[b] = true时,表示相应对角线上已经放置棋子。
+但row - i有可能为负数,负数不能作为数组下标,row - i 的最小值为-n(当row = 0,i = n时),可以加上n作为数组下标,即将row -i + n 作为数组下标。
+row - i + n 的最大值为 2n(当row = n,i = 0时),故anti_diag的容量设置为 2n 即可。
+
+
+
+“\”对角线斜率为-1,对应方程为y = -x + b,其中b为截距。
+对于线上任意一点,均有y + x = b,即row + i = b;
+同理,定义数组main_diag,将b作为下标,当main_diag[row + i] = true时,表示相应对角线上已经放置棋子。
+
+有了两个校验对角线的数组,再来定义一个用于校验列的数组cols,这个太简单啦,不解释。
+
+**解法二时间复杂度为O(n!),在校验相同列和相同对角线时,引入三个布尔类型数组进行判断。相比解法一,少了一层循环,用空间换时间。**
+
+```
+List> resultList = new LinkedList<>();
+
+public List> solveNQueens(int n) {
+ boolean[] cols = new boolean[n];
+ boolean[] main_diag = new boolean[2 * n];
+ boolean[] anti_diag = new boolean[2 * n];
+ LinkedList result = new LinkedList<>();
+ dfs(result, 0, cols, main_diag, anti_diag, n);
+ return resultList;
+}
+
+void dfs(LinkedList result, int row, boolean[] cols, boolean[] main_diag, boolean[] anti_diag, int n) {
+ if (row == n) {
+ List list = new LinkedList<>();
+ for (int x = 0; x < n; ++x) {
+ StringBuilder sb = new StringBuilder();
+ for (int y = 0; y < n; ++y)
+ sb.append(result.get(x) == y ? "Q" : ".");
+ list.add(sb.toString());
+ }
+ resultList.add(list);
+ return;
+ }
+ for (int i = 0; i < n; ++i) {
+ if (cols[i] || main_diag[row + i] || anti_diag[row - i + n])
+ continue;
+ result.add(i);
+ cols[i] = true;
+ main_diag[row + i] = true;
+ anti_diag[row - i + n] = true;
+ dfs(result, row + 1, cols, main_diag, anti_diag, n);
+ result.removeLast();
+ cols[i] = false;
+ main_diag[row + i] = false;
+ anti_diag[row - i + n] = false;
+ }
+}
+```
\ No newline at end of file
diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md" "b/docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md"
similarity index 93%
rename from "\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md"
rename to "docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md"
index d929d20046c..c78ed8f3e5a 100644
--- "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225\351\242\230\350\247\243\346\236\220/\345\205\254\345\217\270\347\234\237\351\242\230/\347\275\221\346\230\2232018\346\240\241\346\213\233\347\274\226\347\250\213\351\242\2301-3.md"
+++ "b/docs/dataStructures-algorithms/\345\205\254\345\217\270\347\234\237\351\242\230.md"
@@ -1,9 +1,10 @@
+# 网易 2018
+
下面三道编程题来自网易2018校招编程题,这三道应该来说是非常简单的编程题了,这些题目大家稍微有点编程和数学基础的话应该没什么问题。看答案之前一定要自己先想一下如果是自己做的话会怎么去做,然后再对照这我的答案看看,和你自己想的有什么区别?那一种方法更好?
-
-> # 问题
+## 问题
-## 一 获得特定数量硬币问题
+### 一 获得特定数量硬币问题
小易准备去魔法王国采购魔法神器,购买魔法神器需要使用魔法币,但是小易现在一枚魔法币都没有,但是小易有两台魔法机器可以通过投入x(x可以为0)个魔法币产生更多的魔法币。
@@ -15,33 +16,30 @@
**输入描述:** 输入包括一行,包括一个正整数n(1 ≤ n ≤ 10^9),表示小易需要的魔法币数量。
-
**输出描述:** 输出一个字符串,每个字符表示该次小易选取投入的魔法机器。其中只包含字符'1'和'2'。
**输入例子1:** 10
**输出例子1:** 122
-## 二 求“相反数”问题
+### 二 求“相反数”问题
为了得到一个数的"相反数",我们将这个数的数字顺序颠倒,然后再加上原先的数得到"相反数"。例如,为了得到1325的"相反数",首先我们将该数的数字顺序颠倒,我们得到5231,之后再加上原先的数,我们得到5231+1325=6556.如果颠倒之后的数字有前缀零,前缀零将会被忽略。例如n = 100, 颠倒之后是1.
**输入描述:** 输入包括一个整数n,(1 ≤ n ≤ 10^5)
-
**输出描述:** 输出一个整数,表示n的相反数
**输入例子1:** 1325
**输出例子1:** 6556
-## 三 字符串碎片的平均长度
+### 三 字符串碎片的平均长度
一个由小写字母组成的字符串可以看成一些同一字母的最大碎片组成的。例如,"aaabbaaac"是由下面碎片组成的:'aaa','bb','c'。牛牛现在给定一个字符串,请你帮助计算这个字符串的所有碎片的平均长度是多少。
**输入描述:** 输入包括一个字符串s,字符串s的长度length(1 ≤ length ≤ 50),s只含小写字母('a'-'z')
-
**输出描述:** 输出一个整数,表示所有碎片的平均长度,四舍五入保留两位小数。
**如样例所示:** s = "aaabbaaac"
@@ -51,19 +49,18 @@
**输出例子1:** 2.25
-
-
-> # 答案
+## 答案
-## 一 获得特定数量硬币问题
+### 一 获得特定数量硬币问题
-### 分析:
+#### 分析:
作为该试卷的第一题,这道题应该只要思路正确就很简单了。
解题关键:明确魔法机器1只能产生奇数,魔法机器2只能产生偶数即可。我们从后往前一步一步推回去即可。
-### 示例代码
+#### 示例代码
+
注意:由于用户的输入不确定性,一般是为了程序高可用性使需要将捕获用户输入异常然后友好提示用户输入类型错误并重新输入的。所以下面我给了两个版本,这两个版本都是正确的。这里只是给大家演示如何捕获输入类型异常,后面的题目中我给的代码没有异常处理的部分,参照下面两个示例代码,应该很容易添加。(PS:企业面试中没有明确就不用添加异常处理,当然你有的话也更好)
**不带输入异常处理判断的版本:**
@@ -141,32 +138,33 @@ public class Main {
```
+### 二 求“相反数”问题
-## 二 求“相反数”问题
-
-### 分析:
+#### 分析:
解决本道题有几种不同的方法,但是最快速的方法就是利用reverse()方法反转字符串然后再将字符串转换成int类型的整数,这个方法是快速解决本题关键。我们先来回顾一下下面两个知识点:
**1)String转int;**
在 Java 中要将 String 类型转化为 int 类型时,需要使用 Integer 类中的 parseInt() 方法或者 valueOf() 方法进行转换.
+
```java
String str = "123";
int a = Integer.parseInt(str);
```
+
或
+
```java
String str = "123";
int a = Integer.valueOf(str).intValue();
```
-
**2)next()和nextLine()的区别**
在Java中输入字符串有两种方法,就是next()和nextLine().两者的区别就是:nextLine()的输入是碰到回车就终止输入,而next()方法是碰到空格,回车,Tab键都会被视为终止符。所以next()不会得到带空格的字符串,而nextLine()可以得到带空格的字符串。
-### 示例代码:
+#### 示例代码:
```java
import java.util.Scanner;
@@ -192,15 +190,15 @@ public class Main {
}
```
-## 三 字符串碎片的平均长度
+### 三 字符串碎片的平均长度
-### 分析:
+#### 分析:
这道题的意思也就是要求:(字符串的总长度)/(相同字母团构成的字符串的个数)。
这样就很简单了,就变成了字符串的字符之间的比较。如果需要比较字符串的字符的话,我们可以利用charAt(i)方法:取出特定位置的字符与后一个字符比较,或者利用toCharArray()方法将字符串转换成字符数组采用同样的方法做比较。
-### 示例代码
+#### 示例代码
**利用charAt(i)方法:**
diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" "b/docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
similarity index 91%
rename from "\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
rename to "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
index b7b1c3145c8..938f4a48f1a 100644
--- "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\220\236\345\256\232BAT\351\235\242\350\257\225\342\200\224\342\200\224\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
+++ "b/docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\220\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
@@ -108,38 +108,57 @@ public class Solution {
思路很简单!先利用Arrays.sort(strs)为数组排序,再将数组第一个元素和最后一个元素的字符从前往后对比即可!
```java
-//https://leetcode-cn.com/problems/longest-common-prefix/description/
public class Main {
- public static String replaceSpace(String[] strs) {
-
- // 数组长度
- int len = strs.length;
- // 用于保存结果
- StringBuffer res = new StringBuffer();
- // 注意:=是赋值,==是判断
- if (strs == null || strs.length == 0) {
- return "";
- }
- // 给字符串数组的元素按照升序排序(包含数字的话,数字会排在前面)
- Arrays.sort(strs);
- int m = strs[0].length();
- int n = strs[len - 1].length();
- int num = Math.min(m, n);
- for (int i = 0; i < num; i++) {
- if (strs[0].charAt(i) == strs[len - 1].charAt(i)) {
- res.append(strs[0].charAt(i));
- } else
- break;
-
- }
- return res.toString();
-
- }
- //测试
- public static void main(String[] args) {
- String[] strs = { "customer", "car", "cat" };
- System.out.println(Main.replaceSpace(strs));//c
- }
+ public static String replaceSpace(String[] strs) {
+
+ // 如果检查值不合法及就返回空串
+ if (!chechStrs(strs)) {
+ return "";
+ }
+ // 数组长度
+ int len = strs.length;
+ // 用于保存结果
+ StringBuilder res = new StringBuilder();
+ // 给字符串数组的元素按照升序排序(包含数字的话,数字会排在前面)
+ Arrays.sort(strs);
+ int m = strs[0].length();
+ int n = strs[len - 1].length();
+ int num = Math.min(m, n);
+ for (int i = 0; i < num; i++) {
+ if (strs[0].charAt(i) == strs[len - 1].charAt(i)) {
+ res.append(strs[0].charAt(i));
+ } else
+ break;
+
+ }
+ return res.toString();
+
+ }
+
+ private static boolean chechStrs(String[] strs) {
+ boolean flag = false;
+ // 注意:=是赋值,==是判断
+ if (strs != null) {
+ // 遍历strs检查元素值
+ for (int i = 0; i < strs.length; i++) {
+ if (strs[i] != null && strs[i].length() != 0) {
+ flag = true;
+ } else {
+ flag = false;
+ }
+ }
+ }
+ return flag;
+ }
+
+ // 测试
+ public static void main(String[] args) {
+ String[] strs = { "customer", "car", "cat" };
+ // String[] strs = { "customer", "car", null };//空串
+ // String[] strs = {};//空串
+ // String[] strs = null;//空串
+ System.out.println(Main.replaceSpace(strs));// c
+ }
}
```
diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/Leetcode-LinkList1.md" "b/docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\351\223\276\350\241\250\347\256\227\346\263\225\351\242\230.md"
similarity index 100%
rename from "\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/Leetcode-LinkList1.md"
rename to "docs/dataStructures-algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\351\223\276\350\241\250\347\256\227\346\263\225\351\242\230.md"
diff --git "a/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md" "b/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md"
new file mode 100644
index 00000000000..51de35eac44
--- /dev/null
+++ "b/docs/dataStructures-algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md"
@@ -0,0 +1,686 @@
+### 一 斐波那契数列
+
+#### **题目描述:**
+
+大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
+n<=39
+
+#### **问题分析:**
+
+可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有一个很大的问题,那就是递归大量的重复计算会导致内存溢出。另外可以使用迭代法,用fn1和fn2保存计算过程中的结果,并复用起来。下面我会把两个方法示例代码都给出来并给出两个方法的运行时间对比。
+
+#### **示例代码:**
+
+**采用迭代法:**
+
+```java
+ int Fibonacci(int number) {
+ if (number <= 0) {
+ return 0;
+ }
+ if (number == 1 || number == 2) {
+ return 1;
+ }
+ int first = 1, second = 1, third = 0;
+ for (int i = 3; i <= number; i++) {
+ third = first + second;
+ first = second;
+ second = third;
+ }
+ return third;
+ }
+```
+
+**采用递归:**
+
+```java
+ public int Fibonacci(int n) {
+
+ if (n <= 0) {
+ return 0;
+ }
+ if (n == 1||n==2) {
+ return 1;
+ }
+
+ return Fibonacci(n - 2) + Fibonacci(n - 1);
+
+ }
+```
+
+#### **运行时间对比:**
+
+假设n为40我们分别使用迭代法和递归法计算,计算结果如下:
+
+1. 迭代法
+ 
+2. 递归法
+ 
+
+### 二 跳台阶问题
+
+#### **题目描述:**
+
+一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
+
+#### **问题分析:**
+
+**正常分析法:**
+a.如果两种跳法,1阶或者2阶,那么假定第一次跳的是一阶,那么剩下的是n-1个台阶,跳法是f(n-1);
+b.假定第一次跳的是2阶,那么剩下的是n-2个台阶,跳法是f(n-2)
+c.由a,b假设可以得出总跳法为: f(n) = f(n-1) + f(n-2)
+d.然后通过实际的情况可以得出:只有一阶的时候 f(1) = 1 ,只有两阶的时候可以有 f(2) = 2
+**找规律分析法:**
+f(1) = 1, f(2) = 2, f(3) = 3, f(4) = 5, 可以总结出f(n) = f(n-1) + f(n-2)的规律。
+但是为什么会出现这样的规律呢?假设现在6个台阶,我们可以从第5跳一步到6,这样的话有多少种方案跳到5就有多少种方案跳到6,另外我们也可以从4跳两步跳到6,跳到4有多少种方案的话,就有多少种方案跳到6,其他的不能从3跳到6什么的啦,所以最后就是f(6) = f(5) + f(4);这样子也很好理解变态跳台阶的问题了。
+
+**所以这道题其实就是斐波那契数列的问题。**
+代码只需要在上一题的代码稍做修改即可。和上一题唯一不同的就是这一题的初始元素变为 1 2 3 5 8.....而上一题为1 1 2 3 5 .......。另外这一题也可以用递归做,但是递归效率太低,所以我这里只给出了迭代方式的代码。
+
+#### **示例代码:**
+
+```java
+ int jumpFloor(int number) {
+ if (number <= 0) {
+ return 0;
+ }
+ if (number == 1) {
+ return 1;
+ }
+ if (number == 2) {
+ return 2;
+ }
+ int first = 1, second = 2, third = 0;
+ for (int i = 3; i <= number; i++) {
+ third = first + second;
+ first = second;
+ second = third;
+ }
+ return third;
+ }
+```
+
+### 三 变态跳台阶问题
+
+#### **题目描述:**
+
+一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
+
+#### **问题分析:**
+
+假设n>=2,第一步有n种跳法:跳1级、跳2级、到跳n级
+跳1级,剩下n-1级,则剩下跳法是f(n-1)
+跳2级,剩下n-2级,则剩下跳法是f(n-2)
+......
+跳n-1级,剩下1级,则剩下跳法是f(1)
+跳n级,剩下0级,则剩下跳法是f(0)
+所以在n>=2的情况下:
+f(n)=f(n-1)+f(n-2)+...+f(1)
+因为f(n-1)=f(n-2)+f(n-3)+...+f(1)
+所以f(n)=2*f(n-1) 又f(1)=1,所以可得**f(n)=2^(number-1)**
+
+#### **示例代码:**
+
+```java
+ int JumpFloorII(int number) {
+ return 1 << --number;//2^(number-1)用位移操作进行,更快
+ }
+```
+
+#### **补充:**
+
+**java中有三种移位运算符:**
+
+1. “<<” : **左移运算符**,等同于乘2的n次方
+2. “>>”: **右移运算符**,等同于除2的n次方
+3. “>>>” **无符号右移运算符**,不管移动前最高位是0还是1,右移后左侧产生的空位部分都以0来填充。与>>类似。
+ 例:
+ int a = 16;
+ int b = a << 2;//左移2,等同于16 * 2的2次方,也就是16 * 4
+ int c = a >> 2;//右移2,等同于16 / 2的2次方,也就是16 / 4
+
+### 四 二维数组查找
+
+#### **题目描述:**
+
+在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
+
+#### **问题解析:**
+
+这一道题还是比较简单的,我们需要考虑的是如何做,效率最快。这里有一种很好理解的思路:
+
+> 矩阵是有序的,从左下角来看,向上数字递减,向右数字递增,
+> 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
+> 要查找数字比左下角数字小时,上移。这样找的速度最快。
+
+#### **示例代码:**
+
+```java
+ public boolean Find(int target, int [][] array) {
+ //基本思路从左下角开始找,这样速度最快
+ int row = array.length-1;//行
+ int column = 0;//列
+ //当行数大于0,当前列数小于总列数时循环条件成立
+ while((row >= 0)&& (column< array[0].length)){
+ if(array[row][column] > target){
+ row--;
+ }else if(array[row][column] < target){
+ column++;
+ }else{
+ return true;
+ }
+ }
+ return false;
+ }
+```
+
+### 五 替换空格
+
+#### **题目描述:**
+
+请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
+
+#### **问题分析:**
+
+这道题不难,我们可以通过循环判断字符串的字符是否为空格,是的话就利用append()方法添加追加“%20”,否则还是追加原字符。
+
+或者最简单的方法就是利用: replaceAll(String regex,String replacement)方法了,一行代码就可以解决。
+
+#### **示例代码:**
+
+**常规做法:**
+
+```java
+ public String replaceSpace(StringBuffer str) {
+ StringBuffer out=new StringBuffer();
+ for (int i = 0; i < str.toString().length(); i++) {
+ char b=str.charAt(i);
+ if(String.valueOf(b).equals(" ")){
+ out.append("%20");
+ }else{
+ out.append(b);
+ }
+ }
+ return out.toString();
+ }
+```
+
+**一行代码解决:**
+
+```java
+ public String replaceSpace(StringBuffer str) {
+ //return str.toString().replaceAll(" ", "%20");
+ //public String replaceAll(String regex,String replacement)
+ //用给定的替换替换与给定的regular expression匹配的此字符串的每个子字符串。
+ //\ 转义字符. 如果你要使用 "\" 本身, 则应该使用 "\\". String类型中的空格用“\s”表示,所以我这里猜测"\\s"就是代表空格的意思
+ return str.toString().replaceAll("\\s", "%20");
+ }
+
+```
+
+### 六 数值的整数次方
+
+#### **题目描述:**
+
+给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
+
+#### **问题解析:**
+
+这道题算是比较麻烦和难一点的一个了。我这里采用的是**二分幂**思想,当然也可以采用**快速幂**。
+更具剑指offer书中细节,该题的解题思路如下:
+1.当底数为0且指数<0时,会出现对0求倒数的情况,需进行错误处理,设置一个全局变量;
+2.判断底数是否等于0,由于base为double型,所以不能直接用==判断
+3.优化求幂函数(二分幂)。
+当n为偶数,a^n =(a^n/2)*(a^n/2);
+当n为奇数,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a。时间复杂度O(logn)
+
+**时间复杂度**:O(logn)
+
+#### **示例代码:**
+
+```java
+public class Solution {
+ boolean invalidInput=false;
+ public double Power(double base, int exponent) {
+ //如果底数等于0并且指数小于0
+ //由于base为double型,不能直接用==判断
+ if(equal(base,0.0)&&exponent<0){
+ invalidInput=true;
+ return 0.0;
+ }
+ int absexponent=exponent;
+ //如果指数小于0,将指数转正
+ if(exponent<0)
+ absexponent=-exponent;
+ //getPower方法求出base的exponent次方。
+ double res=getPower(base,absexponent);
+ //如果指数小于0,所得结果为上面求的结果的倒数
+ if(exponent<0)
+ res=1.0/res;
+ return res;
+ }
+ //比较两个double型变量是否相等的方法
+ boolean equal(double num1,double num2){
+ if(num1-num2>-0.000001&&num1-num2<0.000001)
+ return true;
+ else
+ return false;
+ }
+ //求出b的e次方的方法
+ double getPower(double b,int e){
+ //如果指数为0,返回1
+ if(e==0)
+ return 1.0;
+ //如果指数为1,返回b
+ if(e==1)
+ return b;
+ //e>>1相等于e/2,这里就是求a^n =(a^n/2)*(a^n/2)
+ double result=getPower(b,e>>1);
+ result*=result;
+ //如果指数n为奇数,则要再乘一次底数base
+ if((e&1)==1)
+ result*=b;
+ return result;
+ }
+}
+```
+
+当然这一题也可以采用笨方法:累乘。不过这种方法的时间复杂度为O(n),这样没有前一种方法效率高。
+
+```java
+ // 使用累乘
+ public double powerAnother(double base, int exponent) {
+ double result = 1.0;
+ for (int i = 0; i < Math.abs(exponent); i++) {
+ result *= base;
+ }
+ if (exponent >= 0)
+ return result;
+ else
+ return 1 / result;
+ }
+```
+
+### 七 调整数组顺序使奇数位于偶数前面
+
+#### **题目描述:**
+
+输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
+
+#### **问题解析:**
+
+这道题有挺多种解法的,给大家介绍一种我觉得挺好理解的方法:
+我们首先统计奇数的个数假设为n,然后新建一个等长数组,然后通过循环判断原数组中的元素为偶数还是奇数。如果是则从数组下标0的元素开始,把该奇数添加到新数组;如果是偶数则从数组下标为n的元素开始把该偶数添加到新数组中。
+
+#### **示例代码:**
+
+时间复杂度为O(n),空间复杂度为O(n)的算法
+
+```java
+public class Solution {
+ public void reOrderArray(int [] array) {
+ //如果数组长度等于0或者等于1,什么都不做直接返回
+ if(array.length==0||array.length==1)
+ return;
+ //oddCount:保存奇数个数
+ //oddBegin:奇数从数组头部开始添加
+ int oddCount=0,oddBegin=0;
+ //新建一个数组
+ int[] newArray=new int[array.length];
+ //计算出(数组中的奇数个数)开始添加元素
+ for(int i=0;i<1){
+ pre=pre.next;
+ }
+ k--;
+ }
+ //如果节点个数小于所求的倒数第k个节点,则返回空
+ if(count<= list2.val){
+ if(mergeHead == null){
+ mergeHead = current = list1;
+ }else{
+ current.next = list1;
+ //current节点保存list1节点的值因为下一次还要用
+ current = list1;
+ }
+ //list1指向下一个节点
+ list1 = list1.next;
+ }else{
+ if(mergeHead == null){
+ mergeHead = current = list2;
+ }else{
+ current.next = list2;
+ //current节点保存list2节点的值因为下一次还要用
+ current = list2;
+ }
+ //list2指向下一个节点
+ list2 = list2.next;
+ }
+ }
+ if(list1 == null){
+ current.next = list2;
+ }else{
+ current.next = list1;
+ }
+ return mergeHead;
+ }
+}
+```
+
+**递归版本:**
+
+```java
+public ListNode Merge(ListNode list1,ListNode list2) {
+ if(list1 == null){
+ return list2;
+ }
+ if(list2 == null){
+ return list1;
+ }
+ if(list1.val <= list2.val){
+ list1.next = Merge(list1.next, list2);
+ return list1;
+ }else{
+ list2.next = Merge(list1, list2.next);
+ return list2;
+ }
+ }
+```
+
+### 十一 用两个栈实现队列
+
+#### **题目描述:**
+
+用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
+
+#### 问题分析:
+
+先来回顾一下栈和队列的基本特点:
+**栈:**后进先出(LIFO)
+**队列:** 先进先出
+很明显我们需要根据JDK给我们提供的栈的一些基本方法来实现。先来看一下Stack类的一些基本方法:
+
+
+既然题目给了我们两个栈,我们可以这样考虑当push的时候将元素push进stack1,pop的时候我们先把stack1的元素pop到stack2,然后再对stack2执行pop操作,这样就可以保证是先进先出的。(负[pop]负[pop]得正[先进先出])
+
+#### 考察内容:
+
+队列+栈
+
+#### 示例代码:
+
+```java
+//左程云的《程序员代码面试指南》的答案
+import java.util.Stack;
+
+public class Solution {
+ Stack stack1 = new Stack();
+ Stack stack2 = new Stack();
+
+ //当执行push操作时,将元素添加到stack1
+ public void push(int node) {
+ stack1.push(node);
+ }
+
+ public int pop() {
+ //如果两个队列都为空则抛出异常,说明用户没有push进任何元素
+ if(stack1.empty()&&stack2.empty()){
+ throw new RuntimeException("Queue is empty!");
+ }
+ //如果stack2不为空直接对stack2执行pop操作,
+ if(stack2.empty()){
+ while(!stack1.empty()){
+ //将stack1的元素按后进先出push进stack2里面
+ stack2.push(stack1.pop());
+ }
+ }
+ return stack2.pop();
+ }
+}
+```
+
+### 十二 栈的压入,弹出序列
+
+#### **题目描述:**
+
+输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
+
+#### **题目分析:**
+
+这道题想了半天没有思路,参考了Alias的答案,他的思路写的也很详细应该很容易看懂。
+作者:Alias
+https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
+来源:牛客网
+
+【思路】借用一个辅助的栈,遍历压栈顺序,先讲第一个放入栈中,这里是1,然后判断栈顶元素是不是出栈顺序的第一个元素,这里是4,很显然1≠4,所以我们继续压栈,直到相等以后开始出栈,出栈一个元素,则将出栈顺序向后移动一位,直到不相等,这样循环等压栈顺序遍历完成,如果辅助栈还不为空,说明弹出序列不是该栈的弹出顺序。
+
+举例:
+
+入栈1,2,3,4,5
+
+出栈4,5,3,2,1
+
+首先1入辅助栈,此时栈顶1≠4,继续入栈2
+
+此时栈顶2≠4,继续入栈3
+
+此时栈顶3≠4,继续入栈4
+
+此时栈顶4=4,出栈4,弹出序列向后一位,此时为5,,辅助栈里面是1,2,3
+
+此时栈顶3≠5,继续入栈5
+
+此时栈顶5=5,出栈5,弹出序列向后一位,此时为3,,辅助栈里面是1,2,3
+
+….
+依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
+
+
+
+#### **考察内容:**
+
+栈
+
+#### **示例代码:**
+
+```java
+import java.util.ArrayList;
+import java.util.Stack;
+//这道题没想出来,参考了Alias同学的答案:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
+public class Solution {
+ public boolean IsPopOrder(int [] pushA,int [] popA) {
+ if(pushA.length == 0 || popA.length == 0)
+ return false;
+ Stack s = new Stack();
+ //用于标识弹出序列的位置
+ int popIndex = 0;
+ for(int i = 0; i< pushA.length;i++){
+ s.push(pushA[i]);
+ //如果栈不为空,且栈顶元素等于弹出序列
+ while(!s.empty() &&s.peek() == popA[popIndex]){
+ //出栈
+ s.pop();
+ //弹出序列向后一位
+ popIndex++;
+ }
+ }
+ return s.empty();
+ }
+}
+```
\ No newline at end of file
diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/docs/dataStructures-algorithms/\346\225\260\346\215\256\347\273\223\346\236\204.md"
similarity index 90%
rename from "\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204.md"
rename to "docs/dataStructures-algorithms/\346\225\260\346\215\256\347\273\223\346\236\204.md"
index 8b8207f7f82..6bb19abaaa1 100644
--- "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204.md"
+++ "b/docs/dataStructures-algorithms/\346\225\260\346\215\256\347\273\223\346\236\204.md"
@@ -1,3 +1,4 @@
+下面只是简单地总结,给了一些参考文章,后面会对这部分内容进行重构。
- [Queue](#queue)
@@ -81,8 +82,9 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
**Stack** 是栈,它继承于Vector。它的特性是:先进后出(FILO, First In Last Out)。相关阅读:[java数据结构与算法之栈(Stack)设计与实现](https://blog.csdn.net/javazejian/article/details/53362993)
### ArrayList 和 LinkedList 源码学习
-- [ArrayList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/ArrayList.md)
-- [LinkedList 源码学习](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/LinkedList.md)
+
+- [ArrayList 源码学习](https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/ArrayList.md)
+- [LinkedList 源码学习](https://github.com/Snailclimb/JavaGuide/blob/master/docs/java/LinkedList.md)
### 推荐阅读
@@ -110,9 +112,9 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
[完全二叉树](https://baike.baidu.com/item/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科)
- 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树
+ 完全二叉树:叶节点只能出现在最下层和次下层,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。
* ### 3 满二叉树
-
+
[满二叉树](https://baike.baidu.com/item/%E6%BB%A1%E4%BA%8C%E5%8F%89%E6%A0%91)(百度百科,国内外的定义不同)
国内教程定义:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。
@@ -120,7 +122,7 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
[数据结构之堆的定义](https://blog.csdn.net/qq_33186366/article/details/51876191)
- 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆
+ 堆是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆。
* ### 4 二叉查找树(BST)
[浅谈算法和数据结构: 七 二叉查找树](http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html)
@@ -129,7 +131,7 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
1. 若任意节点的左子树不空,则左子树上所有结点的 值均小于它的根结点的值;
2. 若任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 3. 任意节点的左、右子树也分别为二叉查找树。
+ 3. 任意节点的左、右子树也分别为二叉查找树;
4. 没有键值相等的节点(no duplicate nodes)。
* ### 5 平衡二叉树(Self-balancing binary search tree)
@@ -142,16 +144,16 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
2. 根节点总是黑色的;
3. 每个叶子节点都是黑色的空节点(NIL节点);
4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
- 5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)
+ 5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。
- 红黑树的应用:
-
+
TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。
- 为什么要用红黑树
-
+
简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。详细了解可以查看 [漫画:什么是红黑树?](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
-
+
- 推荐文章:
- [漫画:什么是红黑树?](https://juejin.im/post/5a27c6946fb9a04509096248#comment)(也介绍到了二叉查找树,非常推荐)
- [寻找红黑树的操作手册](http://dandanlove.com/2018/03/18/red-black-tree/)(文章排版以及思路真的不错)
@@ -163,20 +165,28 @@ Set 继承于 Collection 接口,是一个不允许出现重复元素,并且
[《B-树,B+树,B*树详解》](https://blog.csdn.net/aqzwss/article/details/53074186)
[《B-树,B+树与B*树的优缺点比较》](https://blog.csdn.net/bigtree_3721/article/details/73632405)
-
- B-树(或B树)是一种平衡的多路查找(又称排序)树,在文件系统中有所应用。主要用作文件的索引。其中的B就表示平衡(Balance)
+
+ B-树(或B树)是一种平衡的多路查找(又称排序)树,在文件系统中有所应用。主要用作文件的索引。其中的B就表示平衡(Balance)
1. B+ 树的叶子节点链表结构相比于 B- 树便于扫库,和范围检索。
- 2. B+树支持range-query(区间查询)非常方便,而B树不支持。这是数据库选用B+树的最主要原因。
- 3. B*树 是B+树的变体,B*树分配新结点的概率比B+树要低,空间使用率更高;
+ 2. B+树支持range-query(区间查询)非常方便,而B树不支持。这是数据库选用B+树的最主要原因。
+ 3. B\*树 是B+树的变体,B\*树分配新结点的概率比B+树要低,空间使用率更高;
* ### 8 LSM 树
[[HBase] LSM树 VS B+树](https://blog.csdn.net/dbanote/article/details/8897599)
-
+
B+树最大的性能问题是会产生大量的随机IO
为了克服B+树的弱点,HBase引入了LSM树的概念,即Log-Structured Merge-Trees。
-
+
[LSM树由来、设计思想以及应用到HBase的索引](http://www.cnblogs.com/yanghuahui/p/3483754.html)
+## 图
+
+
+
+
+## BFS及DFS
+
+- [《使用BFS及DFS遍历树和图的思路及实现》](https://blog.csdn.net/Gene1994/article/details/85097507)
diff --git "a/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md" "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md"
new file mode 100644
index 00000000000..4c5df56a862
--- /dev/null
+++ "b/docs/dataStructures-algorithms/\347\256\227\346\263\225\345\255\246\344\271\240\350\265\204\346\272\220\346\216\250\350\215\220.md"
@@ -0,0 +1,52 @@
+我比较推荐大家可以刷一下 Leetcode ,我自己平时没事也会刷一下,我觉得刷 Leetcode 不仅是为了能让你更从容地面对面试中的手撕算法问题,更可以提高你的编程思维能力、解决问题的能力以及你对某门编程语言 API 的熟练度。当然牛客网也有一些算法题,我下面也整理了一些。
+
+## LeetCode
+
+- [LeetCode(中国)官网](https://leetcode-cn.com/)
+
+- [如何高效地使用 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/)
+
+
+## 牛客网
+
+- [牛客网官网](https://www.nowcoder.com)
+- [剑指offer编程题](https://www.nowcoder.com/ta/coding-interviews)
+
+- [2017校招真题](https://www.nowcoder.com/ta/2017test)
+- [华为机试题](https://www.nowcoder.com/ta/huawei)
+
+
+## 公司真题
+
+- [ 网易2018校园招聘编程题真题集合](https://www.nowcoder.com/test/6910869/summary)
+- [ 网易2018校招内推编程题集合](https://www.nowcoder.com/test/6291726/summary)
+- [2017年校招全国统一模拟笔试(第五场)编程题集合](https://www.nowcoder.com/test/5986669/summary)
+- [2017年校招全国统一模拟笔试(第四场)编程题集合](https://www.nowcoder.com/test/5507925/summary)
+- [2017年校招全国统一模拟笔试(第三场)编程题集合](https://www.nowcoder.com/test/5217106/summary)
+- [2017年校招全国统一模拟笔试(第二场)编程题集合](https://www.nowcoder.com/test/4546329/summary)
+- [ 2017年校招全国统一模拟笔试(第一场)编程题集合](https://www.nowcoder.com/test/4236887/summary)
+- [百度2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4998655/summary)
+- [网易2017春招笔试真题编程题集合](https://www.nowcoder.com/test/4575457/summary)
+- [网易2017秋招编程题集合](https://www.nowcoder.com/test/2811407/summary)
+- [网易有道2017内推编程题](https://www.nowcoder.com/test/2385858/summary)
+- [ 滴滴出行2017秋招笔试真题-编程题汇总](https://www.nowcoder.com/test/3701760/summary)
+- [腾讯2017暑期实习生编程题](https://www.nowcoder.com/test/1725829/summary)
+- [今日头条2017客户端工程师实习生笔试题](https://www.nowcoder.com/test/1649301/summary)
+- [今日头条2017后端工程师实习生笔试题](https://www.nowcoder.com/test/1649268/summary)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/MySQL Index.md" b/docs/database/MySQL Index.md
similarity index 85%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/MySQL Index.md"
rename to docs/database/MySQL Index.md
index dda0ba8bb62..e2e9dc534db 100644
--- "a/\346\225\260\346\215\256\345\255\230\345\202\250/MySQL Index.md"
+++ b/docs/database/MySQL Index.md
@@ -28,8 +28,8 @@ MySQL的基本存储结构是页(记录都存在页里边):
所以说,如果我们写select * from user where indexname = 'xxx'这样没有进行任何优化的sql语句,默认会这样做:
-1. **定位到记录所在的页:需要遍历双向链表,找到所在的页**
-2. **从所在的页内中查找相应的记录:由于不是根据主键查询,只能遍历所在页的单链表了**
+1. **定位到记录所在的页:需要遍历双向链表,找到所在的页**
+2. **从所在的页内中查找相应的记录:由于不是根据主键查询,只能遍历所在页的单链表了**
很明显,在数据量很大的情况下这样查找会很慢!这样的时间复杂度为O(n)。
@@ -55,22 +55,22 @@ MySQL的基本存储结构是页(记录都存在页里边):
### 最左前缀原则
-MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。如User表的name和city加联合索引就是(name,city)o而最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如下:
+MySQL中的索引可以以一定顺序引用多列,这种索引叫作联合索引。如User表的name和city加联合索引就是(name,city),而最左前缀原则指的是,如果查询的时候查询条件精确匹配索引的左边连续一列或几列,则此列就可以被用到。如下:
```
select * from user where name=xx and city=xx ; //可以命中索引
select * from user where name=xx ; // 可以命中索引
-select * from user where city=xx; // 法命中索引
+select * from user where city=xx ; // 无法命中索引
```
-这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 `city= xx and name =xx`,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的.
+这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 `city= xx and name =xx`,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
-由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDERBY子句也遵循此规则。
+由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDER BY子句也遵循此规则。
### 注意避免冗余索引
冗余索引指的是索引的功能相同,能够命中 就肯定能命中 ,那么 就是冗余索引如(name,city )和(name )这两个索引就是冗余索引,能够命中后者的查询肯定是能够命中前者的 在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。
-MySQLS.7 版本后,可以通过查询 sys 库的 `schemal_r dundant_indexes` 表来查看冗余索引
+MySQLS.7 版本后,可以通过查询 sys 库的 `schema_redundant_indexes` 表来查看冗余索引
### Mysql如何为表字段添加索引???
@@ -109,4 +109,4 @@ ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3`
- 《Java工程师修炼之道》
- 《MySQL高性能书籍_第3版》
- https://juejin.im/post/5b55b842f265da0f9e589e79
-
\ No newline at end of file
+
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/MySQL.md" b/docs/database/MySQL.md
similarity index 84%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/MySQL.md"
rename to docs/database/MySQL.md
index 6d7a484d658..7fed73726d3 100644
--- "a/\346\225\260\346\215\256\345\255\230\345\202\250/MySQL.md"
+++ b/docs/database/MySQL.md
@@ -1,19 +1,24 @@
+
+- [书籍推荐](#书籍推荐)
+- [文字教程推荐](#文字教程推荐)
+- [视频教程推荐](#视频教程推荐)
+- [常见问题总结](#常见问题总结)
-Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去,欢迎建议和指导):[https://github.com/Snailclimb/Java_Guide](https://github.com/Snailclimb/Java_Guide)
+
-> ## 书籍推荐
+## 书籍推荐
-**《高性能MySQL : 第3版》**
+- 《SQL基础教程(第2版)》 (入门级)
+- 《高性能MySQL : 第3版》 (进阶)
-> ## 文字教程推荐
+## 文字教程推荐
[MySQL 教程(菜鸟教程)](http://www.runoob.com/mysql/mysql-tutorial.html)
[MySQL教程(易百教程)](https://www.yiibai.com/mysql/)
-> ## 视频教程推荐
-
+## 视频教程推荐
**基础入门:** [与MySQL的零距离接触-慕课网](https://www.imooc.com/learn/122)
@@ -23,9 +28,7 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去
[MySQL集群(PXC)入门](https://www.imooc.com/learn/993) [MyCAT入门及应用](https://www.imooc.com/learn/951)
-
-
-> ## 常见问题总结
+## 常见问题总结
- ### ①存储引擎
@@ -47,7 +50,7 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去
**MyISAM:** B+Tree叶节点的data域存放的是数据记录的地址。在索引检索的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引”。
- **InnoDB:** 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。**在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,在走一遍主索引。** **因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。** PS:整理自《Java工程师修炼之道》
+ **InnoDB:** 其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分离的,其表数据文件本身就是按B+Tree组织的一个索引结构,树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。这被称为“聚簇索引(或聚集索引)”。而其余的索引都作为辅助索引,辅助索引的data域存储相应记录主键的值而不是地址,这也是和MyISAM不同的地方。**在根据主索引搜索时,直接找到key所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。** **因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。** PS:整理自《Java工程师修炼之道》
详细内容可以参考:
@@ -87,20 +90,20 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去

1. **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 2. **一致性:** 执行事务前后,数据保持一致;
- 3. **隔离性:** 并发访问数据库时,一个用户的事物不被其他事物所干扰,各并发事务之间数据库是独立的;
- 4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库 发生故障也不应该对其有任何影响。
+ 2. **一致性:** 执行事务前后,数据库从一个一致性状态转换到另一个一致性状态。
+ 3. **隔离性:** 并发访问数据库时,一个用户的事物不被其他事务所干扰,各并发事务之间数据库是独立的;
+ 4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库 发生故障也不应该对其有任何影响。
**为了达到上述事务特性,数据库定义了几种不同的事务隔离级别:**
-- **READ_UNCOMMITTED(未授权读取):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**
-- **READ_COMMITTED(授权读取):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**
-- **REPEATABLE_READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生。**
+- **READ_UNCOMMITTED(未提交读):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**
+- **READ_COMMITTED(提交读):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**
+- **REPEATABLE_READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生。**
- **SERIALIZABLE(串行):** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
这里需要注意的是:**Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.**
- 事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVVC(多版本并发控制),通过保存修改的旧版本信息来支持并发一致性读和回滚等特性。
+ 事务隔离机制的实现基于锁机制和并发调度。其中并发调度使用的是MVCC(多版本并发控制),通过行的创建时间和行的过期时间来支持并发一致性读和回滚等特性。
详细内容可以参考: [可能是最漂亮的Spring事务管理详解](https://blog.csdn.net/qq_34337272/article/details/80394121)
@@ -134,21 +137,20 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去
当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
- 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
+ 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
2. **读/写分离:** 经典的数据库拆分方案,主库负责写,从库负责读;
- 3. **缓存:** 使用MySQL的缓存,另外对重量级、更新少的数据可以考虑使用应用级别的缓存;
- 4. **垂直分区:**
+ 3 . **垂直分区:**
**根据数据库里面数据表的相关性进行拆分。** 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。
**简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。

- **垂直拆分的优点:** 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
+ **垂直拆分的优点:** 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
**垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
- 5. **水平分区:**
+ 4. **水平分区:**
**保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。**
@@ -157,9 +159,9 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去

- 水品拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水品拆分最好分库** 。
+ 水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水平拆分最好分库** 。
- 水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨界点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
+ 水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨节点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
**下面补充一下数据库分片的两种常见方案:**
- **客户端代理:** **分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。** 当当网的 **Sharding-JDBC** 、阿里的TDDL是两种比较常用的实现。
diff --git "a/docs/database/MySQL\351\253\230\346\200\247\350\203\275\344\274\230\345\214\226\350\247\204\350\214\203\345\273\272\350\256\256.md" "b/docs/database/MySQL\351\253\230\346\200\247\350\203\275\344\274\230\345\214\226\350\247\204\350\214\203\345\273\272\350\256\256.md"
new file mode 100644
index 00000000000..dcfc2edd210
--- /dev/null
+++ "b/docs/database/MySQL\351\253\230\346\200\247\350\203\275\344\274\230\345\214\226\350\247\204\350\214\203\345\273\272\350\256\256.md"
@@ -0,0 +1,441 @@
+> 作者: 听风,原文地址: 。JavaGuide 已获得作者授权。
+
+
+
+- [数据库命令规范](#数据库命令规范)
+- [数据库基本设计规范](#数据库基本设计规范)
+ - [1. 所有表必须使用 Innodb 存储引擎](#1-所有表必须使用-innodb-存储引擎)
+ - [2. 数据库和表的字符集统一使用 UTF8](#2-数据库和表的字符集统一使用-utf8)
+ - [3. 所有表和字段都需要添加注释](#3-所有表和字段都需要添加注释)
+ - [4. 尽量控制单表数据量的大小,建议控制在 500 万以内。](#4-尽量控制单表数据量的大小建议控制在-500-万以内)
+ - [5. 谨慎使用 MySQL 分区表](#5-谨慎使用-mysql-分区表)
+ - [6.尽量做到冷热数据分离,减小表的宽度](#6尽量做到冷热数据分离减小表的宽度)
+ - [7. 禁止在表中建立预留字段](#7-禁止在表中建立预留字段)
+ - [8. 禁止在数据库中存储图片,文件等大的二进制数据](#8-禁止在数据库中存储图片文件等大的二进制数据)
+ - [9. 禁止在线上做数据库压力测试](#9-禁止在线上做数据库压力测试)
+ - [10. 禁止从开发环境,测试环境直接连接生成环境数据库](#10-禁止从开发环境测试环境直接连接生成环境数据库)
+- [数据库字段设计规范](#数据库字段设计规范)
+ - [1. 优先选择符合存储需要的最小的数据类型](#1-优先选择符合存储需要的最小的数据类型)
+ - [2. 避免使用 TEXT,BLOB 数据类型,最常见的 TEXT 类型可以存储 64k 的数据](#2-避免使用-textblob-数据类型最常见的-text-类型可以存储-64k-的数据)
+ - [3. 避免使用 ENUM 类型](#3-避免使用-enum-类型)
+ - [4. 尽可能把所有列定义为 NOT NULL](#4-尽可能把所有列定义为-not-null)
+ - [5. 使用 TIMESTAMP(4 个字节) 或 DATETIME 类型 (8 个字节) 存储时间](#5-使用-timestamp4-个字节-或-datetime-类型-8-个字节-存储时间)
+ - [6. 同财务相关的金额类数据必须使用 decimal 类型](#6-同财务相关的金额类数据必须使用-decimal-类型)
+- [索引设计规范](#索引设计规范)
+ - [1. 限制每张表上的索引数量,建议单张表索引不超过 5 个](#1-限制每张表上的索引数量建议单张表索引不超过-5-个)
+ - [2. 禁止给表中的每一列都建立单独的索引](#2-禁止给表中的每一列都建立单独的索引)
+ - [3. 每个 Innodb 表必须有个主键](#3-每个-innodb-表必须有个主键)
+ - [4. 常见索引列建议](#4-常见索引列建议)
+ - [5.如何选择索引列的顺序](#5如何选择索引列的顺序)
+ - [6. 避免建立冗余索引和重复索引(增加了查询优化器生成执行计划的时间)](#6-避免建立冗余索引和重复索引增加了查询优化器生成执行计划的时间)
+ - [7. 对于频繁的查询优先考虑使用覆盖索引](#7-对于频繁的查询优先考虑使用覆盖索引)
+ - [8.索引 SET 规范](#8索引-set-规范)
+- [数据库 SQL 开发规范](#数据库-sql-开发规范)
+ - [1. 建议使用预编译语句进行数据库操作](#1-建议使用预编译语句进行数据库操作)
+ - [2. 避免数据类型的隐式转换](#2-避免数据类型的隐式转换)
+ - [3. 充分利用表上已经存在的索引](#3-充分利用表上已经存在的索引)
+ - [4. 数据库设计时,应该要对以后扩展进行考虑](#4-数据库设计时应该要对以后扩展进行考虑)
+ - [5. 程序连接不同的数据库使用不同的账号,进制跨库查询](#5-程序连接不同的数据库使用不同的账号进制跨库查询)
+ - [6. 禁止使用 SELECT * 必须使用 SELECT <字段列表> 查询](#6-禁止使用-select--必须使用-select-字段列表-查询)
+ - [7. 禁止使用不含字段列表的 INSERT 语句](#7-禁止使用不含字段列表的-insert-语句)
+ - [8. 避免使用子查询,可以把子查询优化为 join 操作](#8-避免使用子查询可以把子查询优化为-join-操作)
+ - [9. 避免使用 JOIN 关联太多的表](#9-避免使用-join-关联太多的表)
+ - [10. 减少同数据库的交互次数](#10-减少同数据库的交互次数)
+ - [11. 对应同一列进行 or 判断时,使用 in 代替 or](#11-对应同一列进行-or-判断时使用-in-代替-or)
+ - [12. 禁止使用 order by rand() 进行随机排序](#12-禁止使用-order-by-rand-进行随机排序)
+ - [13. WHERE 从句中禁止对列进行函数转换和计算](#13-where-从句中禁止对列进行函数转换和计算)
+ - [14. 在明显不会有重复值时使用 UNION ALL 而不是 UNION](#14-在明显不会有重复值时使用-union-all-而不是-union)
+ - [15. 拆分复杂的大 SQL 为多个小 SQL](#15-拆分复杂的大-sql-为多个小-sql)
+- [数据库操作行为规范](#数据库操作行为规范)
+ - [1. 超 100 万行的批量写 (UPDATE,DELETE,INSERT) 操作,要分批多次进行操作](#1-超-100-万行的批量写-updatedeleteinsert-操作要分批多次进行操作)
+ - [2. 对于大表使用 pt-online-schema-change 修改表结构](#2-对于大表使用-pt-online-schema-change-修改表结构)
+ - [3. 禁止为程序使用的账号赋予 super 权限](#3-禁止为程序使用的账号赋予-super-权限)
+ - [4. 对于程序连接数据库账号,遵循权限最小原则](#4-对于程序连接数据库账号遵循权限最小原则)
+
+
+
+## 数据库命令规范
+
+- 所有数据库对象名称必须使用小写字母并用下划线分割
+- 所有数据库对象名称禁止使用 MySQL 保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来)
+- 数据库对象的命名要能做到见名识意,并且最后不要超过 32 个字符
+- 临时库表必须以 tmp_为前缀并以日期为后缀,备份表必须以 bak_为前缀并以日期 (时间戳) 为后缀
+- 所有存储相同数据的列名和列类型必须一致(一般作为关联列,如果查询时关联列类型不一致会自动进行数据类型隐式转换,会造成列上的索引失效,导致查询效率降低)
+
+------
+
+## 数据库基本设计规范
+
+### 1. 所有表必须使用 Innodb 存储引擎
+
+没有特殊要求(即 Innodb 无法满足的功能如:列存储,存储空间数据等)的情况下,所有表必须使用 Innodb 存储引擎(MySQL5.5 之前默认使用 Myisam,5.6 以后默认的为 Innodb)。
+
+Innodb 支持事务,支持行级锁,更好的恢复性,高并发下性能更好。
+
+### 2. 数据库和表的字符集统一使用 UTF8
+
+兼容性更好,统一字符集可以避免由于字符集转换产生的乱码,不同的字符集进行比较前需要进行转换会造成索引失效,如果数据库中有存储 emoji 表情的需要,字符集需要采用 utf8mb4 字符集。
+
+### 3. 所有表和字段都需要添加注释
+
+使用 comment 从句添加表和列的备注,从一开始就进行数据字典的维护
+
+### 4. 尽量控制单表数据量的大小,建议控制在 500 万以内。
+
+500 万并不是 MySQL 数据库的限制,过大会造成修改表结构,备份,恢复都会有很大的问题。
+
+可以用历史数据归档(应用于日志数据),分库分表(应用于业务数据)等手段来控制数据量大小
+
+### 5. 谨慎使用 MySQL 分区表
+
+分区表在物理上表现为多个文件,在逻辑上表现为一个表;
+
+谨慎选择分区键,跨分区查询效率可能更低;
+
+建议采用物理分表的方式管理大数据。
+
+### 6.尽量做到冷热数据分离,减小表的宽度
+
+> MySQL 限制每个表最多存储 4096 列,并且每一行数据的大小不能超过 65535 字节。
+
+减少磁盘 IO,保证热数据的内存缓存命中率(表越宽,把表装载进内存缓冲池时所占用的内存也就越大,也会消耗更多的 IO);
+
+更有效的利用缓存,避免读入无用的冷数据;
+
+经常一起使用的列放到一个表中(避免更多的关联操作)。
+
+### 7. 禁止在表中建立预留字段
+
+预留字段的命名很难做到见名识义。
+
+预留字段无法确认存储的数据类型,所以无法选择合适的类型。
+
+对预留字段类型的修改,会对表进行锁定。
+
+### 8. 禁止在数据库中存储图片,文件等大的二进制数据
+
+通常文件很大,会短时间内造成数据量快速增长,数据库进行数据库读取时,通常会进行大量的随机 IO 操作,文件很大时,IO 操作很耗时。
+
+通常存储于文件服务器,数据库只存储文件地址信息
+
+### 9. 禁止在线上做数据库压力测试
+
+### 10. 禁止从开发环境,测试环境直接连接生产环境数据库
+
+------
+
+## 数据库字段设计规范
+
+### 1. 优先选择符合存储需要的最小的数据类型
+
+**原因:**
+
+列的字段越大,建立索引时所需要的空间也就越大,这样一页中所能存储的索引节点的数量也就越少也越少,在遍历时所需要的 IO 次数也就越多,索引的性能也就越差。
+
+**方法:**
+
+**a.将字符串转换成数字类型存储,如:将 IP 地址转换成整形数据**
+
+MySQL 提供了两个方法来处理 ip 地址
+
+- inet_aton 把 ip 转为无符号整型 (4-8 位)
+- inet_ntoa 把整型的 ip 转为地址
+
+插入数据前,先用 inet_aton 把 ip 地址转为整型,可以节省空间,显示数据时,使用 inet_ntoa 把整型的 ip 地址转为地址显示即可。
+
+**b.对于非负型的数据 (如自增 ID,整型 IP) 来说,要优先使用无符号整型来存储**
+
+**原因:**
+
+无符号相对于有符号可以多出一倍的存储空间
+
+```
+SIGNED INT -2147483648~2147483647
+UNSIGNED INT 0~4294967295
+```
+
+VARCHAR(N) 中的 N 代表的是字符数,而不是字节数,使用 UTF8 存储 255 个汉字 Varchar(255)=765 个字节。**过大的长度会消耗更多的内存。**
+
+### 2. 避免使用 TEXT,BLOB 数据类型,最常见的 TEXT 类型可以存储 64k 的数据
+
+**a. 建议把 BLOB 或是 TEXT 列分离到单独的扩展表中**
+
+MySQL 内存临时表不支持 TEXT、BLOB 这样的大数据类型,如果查询中包含这样的数据,在排序等操作时,就不能使用内存临时表,必须使用磁盘临时表进行。而且对于这种数据,MySQL 还是要进行二次查询,会使 sql 性能变得很差,但是不是说一定不能使用这样的数据类型。
+
+如果一定要使用,建议把 BLOB 或是 TEXT 列分离到单独的扩展表中,查询时一定不要使用 select * 而只需要取出必要的列,不需要 TEXT 列的数据时不要对该列进行查询。
+
+**2、TEXT 或 BLOB 类型只能使用前缀索引**
+
+因为[MySQL](http://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247487885&idx=1&sn=65b1bf5f7d4505502620179669a9c2df&chksm=ebd62ea1dca1a7b7bf884bcd9d538d78ba064ee03c09436ca8e57873b1d98a55afd6d7884cfc&scene=21#wechat_redirect) 对索引字段长度是有限制的,所以 TEXT 类型只能使用前缀索引,并且 TEXT 列上是不能有默认值的
+
+### 3. 避免使用 ENUM 类型
+
+修改 ENUM 值需要使用 ALTER 语句
+
+ENUM 类型的 ORDER BY 操作效率低,需要额外操作
+
+禁止使用数值作为 ENUM 的枚举值
+
+### 4. 尽可能把所有列定义为 NOT NULL
+
+**原因:**
+
+索引 NULL 列需要额外的空间来保存,所以要占用更多的空间
+
+进行比较和计算时要对 NULL 值做特别的处理
+
+### 5. 使用 TIMESTAMP(4 个字节) 或 DATETIME 类型 (8 个字节) 存储时间
+
+TIMESTAMP 存储的时间范围 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07
+
+TIMESTAMP 占用 4 字节和 INT 相同,但比 INT 可读性高
+
+超出 TIMESTAMP 取值范围的使用 DATETIME 类型存储
+
+**经常会有人用字符串存储日期型的数据(不正确的做法)**
+
+- 缺点 1:无法用日期函数进行计算和比较
+- 缺点 2:用字符串存储日期要占用更多的空间
+
+### 6. 同财务相关的金额类数据必须使用 decimal 类型
+
+- 非精准浮点:float,double
+- 精准浮点:decimal
+
+Decimal 类型为精准浮点数,在计算时不会丢失精度
+
+占用空间由定义的宽度决定,每 4 个字节可以存储 9 位数字,并且小数点要占用一个字节
+
+可用于存储比 bigint 更大的整型数据
+
+------
+
+## 索引设计规范
+
+### 1. 限制每张表上的索引数量,建议单张表索引不超过 5 个
+
+索引并不是越多越好!索引可以提高效率同样可以降低效率。
+
+索引可以增加查询效率,但同样也会降低插入和更新的效率,甚至有些情况下会降低查询效率。
+
+因为 MySQL 优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,就会增加 MySQL 优化器生成执行计划的时间,同样会降低查询性能。
+
+### 2. 禁止给表中的每一列都建立单独的索引
+
+5.6 版本之前,一个 sql 只能使用到一个表中的一个索引,5.6 以后,虽然有了合并索引的优化方式,但是还是远远没有使用一个联合索引的查询方式好。
+
+### 3. 每个 Innodb 表必须有个主键
+
+Innodb 是一种索引组织表:数据的存储的逻辑顺序和索引的顺序是相同的。每个表都可以有多个索引,但是表的存储顺序只能有一种。
+
+Innodb 是按照主键索引的顺序来组织表的
+
+- 不要使用更新频繁的列作为主键,不适用多列主键(相当于联合索引)
+- 不要使用 UUID,MD5,HASH,字符串列作为主键(无法保证数据的顺序增长)
+- 主键建议使用自增 ID 值
+
+------
+
+### 4. 常见索引列建议
+
+- 出现在 SELECT、UPDATE、DELETE 语句的 WHERE 从句中的列
+- 包含在 ORDER BY、GROUP BY、DISTINCT 中的字段
+- 并不要将符合 1 和 2 中的字段的列都建立一个索引, 通常将 1、2 中的字段建立联合索引效果更好
+- 多表 join 的关联列
+
+------
+
+### 5.如何选择索引列的顺序
+
+建立索引的目的是:希望通过索引进行数据查找,减少随机 IO,增加查询性能 ,索引能过滤出越少的数据,则从磁盘中读入的数据也就越少。
+
+- 区分度最高的放在联合索引的最左侧(区分度=列中不同值的数量/列的总行数)
+- 尽量把字段长度小的列放在联合索引的最左侧(因为字段长度越小,一页能存储的数据量越大,IO 性能也就越好)
+- 使用最频繁的列放到联合索引的左侧(这样可以比较少的建立一些索引)
+
+------
+
+### 6. 避免建立冗余索引和重复索引(增加了查询优化器生成执行计划的时间)
+
+- 重复索引示例:primary key(id)、index(id)、unique index(id)
+- 冗余索引示例:index(a,b,c)、index(a,b)、index(a)
+
+------
+
+### 7. 对于频繁的查询优先考虑使用覆盖索引
+
+> 覆盖索引:就是包含了所有查询字段 (where,select,ordery by,group by 包含的字段) 的索引
+
+**覆盖索引的好处:**
+
+- **避免 Innodb 表进行索引的二次查询:** Innodb 是以聚集索引的顺序来存储的,对于 Innodb 来说,二级索引在叶子节点中所保存的是行的主键信息,如果是用二级索引查询数据的话,在查找到相应的键值后,还要通过主键进行二次查询才能获取我们真实所需要的数据。而在覆盖索引中,二级索引的键值中可以获取所有的数据,避免了对主键的二次查询 ,减少了 IO 操作,提升了查询效率。
+- **可以把随机 IO 变成顺序 IO 加快查询效率:** 由于覆盖索引是按键值的顺序存储的,对于 IO 密集型的范围查找来说,对比随机从磁盘读取每一行的数据 IO 要少的多,因此利用覆盖索引在访问时也可以把磁盘的随机读取的 IO 转变成索引查找的顺序 IO。
+
+------
+
+### 8.索引 SET 规范
+
+**尽量避免使用外键约束**
+
+- 不建议使用外键约束(foreign key),但一定要在表与表之间的关联键上建立索引
+- 外键可用于保证数据的参照完整性,但建议在业务端实现
+- 外键会影响父表和子表的写操作从而降低性能
+
+------
+
+## 数据库 SQL 开发规范
+
+### 1. 建议使用预编译语句进行数据库操作
+
+预编译语句可以重复使用这些计划,减少 SQL 编译所需要的时间,还可以解决动态 SQL 所带来的 SQL 注入的问题。
+
+只传参数,比传递 SQL 语句更高效。
+
+相同语句可以一次解析,多次使用,提高处理效率。
+
+### 2. 避免数据类型的隐式转换
+
+隐式转换会导致索引失效如:
+
+```
+select name,phone from customer where id = '111';
+```
+
+### 3. 充分利用表上已经存在的索引
+
+避免使用双%号的查询条件。如:`a like '%123%'`,(如果无前置%,只有后置%,是可以用到列上的索引的)
+
+一个 SQL 只能利用到复合索引中的一列进行范围查询。如:有 a,b,c 列的联合索引,在查询条件中有 a 列的范围查询,则在 b,c 列上的索引将不会被用到。
+
+在定义联合索引时,如果 a 列要用到范围查找的话,就要把 a 列放到联合索引的右侧,使用 left join 或 not exists 来优化 not in 操作,因为 not in 也通常会使用索引失效。
+
+### 4. 数据库设计时,应该要对以后扩展进行考虑
+
+### 5. 程序连接不同的数据库使用不同的账号,进制跨库查询
+
+- 为数据库迁移和分库分表留出余地
+- 降低业务耦合度
+- 避免权限过大而产生的安全风险
+
+### 6. 禁止使用 SELECT * 必须使用 SELECT <字段列表> 查询
+
+**原因:**
+
+- 消耗更多的 CPU 和 IO 以网络带宽资源
+- 无法使用覆盖索引
+- 可减少表结构变更带来的影响
+
+### 7. 禁止使用不含字段列表的 INSERT 语句
+
+如:
+
+```
+insert into values ('a','b','c');
+```
+
+应使用:
+
+```
+insert into t(c1,c2,c3) values ('a','b','c');
+```
+
+### 8. 避免使用子查询,可以把子查询优化为 join 操作
+
+通常子查询在 in 子句中,且子查询中为简单 SQL(不包含 union、group by、order by、limit 从句) 时,才可以把子查询转化为关联查询进行优化。
+
+**子查询性能差的原因:**
+
+子查询的结果集无法使用索引,通常子查询的结果集会被存储到临时表中,不论是内存临时表还是磁盘临时表都不会存在索引,所以查询性能会受到一定的影响。特别是对于返回结果集比较大的子查询,其对查询性能的影响也就越大。
+
+由于子查询会产生大量的临时表也没有索引,所以会消耗过多的 CPU 和 IO 资源,产生大量的慢查询。
+
+### 9. 避免使用 JOIN 关联太多的表
+
+对于 MySQL 来说,是存在关联缓存的,缓存的大小可以由 join_buffer_size 参数进行设置。
+
+在 MySQL 中,对于同一个 SQL 多关联(join)一个表,就会多分配一个关联缓存,如果在一个 SQL 中关联的表越多,所占用的内存也就越大。
+
+如果程序中大量的使用了多表关联的操作,同时 join_buffer_size 设置的也不合理的情况下,就容易造成服务器内存溢出的情况,就会影响到服务器数据库性能的稳定性。
+
+同时对于关联操作来说,会产生临时表操作,影响查询效率,MySQL 最多允许关联 61 个表,建议不超过 5 个。
+
+### 10. 减少同数据库的交互次数
+
+数据库更适合处理批量操作,合并多个相同的操作到一起,可以提高处理效率。
+
+### 11. 对应同一列进行 or 判断时,使用 in 代替 or
+
+in 的值不要超过 500 个,in 操作可以更有效的利用索引,or 大多数情况下很少能利用到索引。
+
+### 12. 禁止使用 order by rand() 进行随机排序
+
+order by rand() 会把表中所有符合条件的数据装载到内存中,然后在内存中对所有数据根据随机生成的值进行排序,并且可能会对每一行都生成一个随机值,如果满足条件的数据集非常大,就会消耗大量的 CPU 和 IO 及内存资源。
+
+推荐在程序中获取一个随机值,然后从数据库中获取数据的方式。
+
+### 13. WHERE 从句中禁止对列进行函数转换和计算
+
+对列进行函数转换或计算时会导致无法使用索引
+
+**不推荐:**
+
+```
+where date(create_time)='20190101'
+```
+
+**推荐:**
+
+```
+where create_time >= '20190101' and create_time < '20190102'
+```
+
+### 14. 在明显不会有重复值时使用 UNION ALL 而不是 UNION
+
+- UNION 会把两个结果集的所有数据放到临时表中后再进行去重操作
+- UNION ALL 不会再对结果集进行去重操作
+
+### 15. 拆分复杂的大 SQL 为多个小 SQL
+
+- 大 SQL 逻辑上比较复杂,需要占用大量 CPU 进行计算的 SQL
+- MySQL 中,一个 SQL 只能使用一个 CPU 进行计算
+- SQL 拆分后可以通过并行执行来提高处理效率
+
+------
+
+## 数据库操作行为规范
+
+### 1. 超 100 万行的批量写 (UPDATE,DELETE,INSERT) 操作,要分批多次进行操作
+
+**大批量操作可能会造成严重的主从延迟**
+
+主从环境中,大批量操作可能会造成严重的主从延迟,大批量的写操作一般都需要执行一定长的时间,
+而只有当主库上执行完成后,才会在其他从库上执行,所以会造成主库与从库长时间的延迟情况
+
+**binlog 日志为 row 格式时会产生大量的日志**
+
+大批量写操作会产生大量日志,特别是对于 row 格式二进制数据而言,由于在 row 格式中会记录每一行数据的修改,我们一次修改的数据越多,产生的日志量也就会越多,日志的传输和恢复所需要的时间也就越长,这也是造成主从延迟的一个原因
+
+**避免产生大事务操作**
+
+大批量修改数据,一定是在一个事务中进行的,这就会造成表中大批量数据进行锁定,从而导致大量的阻塞,阻塞会对 MySQL 的性能产生非常大的影响。
+
+特别是长时间的阻塞会占满所有数据库的可用连接,这会使生产环境中的其他应用无法连接到数据库,因此一定要注意大批量写操作要进行分批
+
+### 2. 对于大表使用 pt-online-schema-change 修改表结构
+
+- 避免大表修改产生的主从延迟
+- 避免在对表字段进行修改时进行锁表
+
+对大表数据结构的修改一定要谨慎,会造成严重的锁表操作,尤其是生产环境,是不能容忍的。
+
+pt-online-schema-change 它会首先建立一个与原表结构相同的新表,并且在新表上进行表结构的修改,然后再把原表中的数据复制到新表中,并在原表中增加一些触发器。把原表中新增的数据也复制到新表中,在行所有数据复制完成之后,把新表命名成原表,并把原来的表删除掉。把原来一个 DDL 操作,分解成多个小的批次进行。
+
+### 3. 禁止为程序使用的账号赋予 super 权限
+
+- 当达到最大连接数限制时,还运行 1 个有 super 权限的用户连接
+- super 权限只能留给 DBA 处理问题的账号使用
+
+### 4. 对于程序连接数据库账号,遵循权限最小原则
+
+- 程序使用数据库账号只能在一个 DB 下使用,不准跨库
+- 程序使用的账号原则上不准有 drop 权限
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redis.md" b/docs/database/Redis/Redis.md
similarity index 84%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redis.md"
rename to docs/database/Redis/Redis.md
index 41234cf55ac..2c44dd1cbdc 100644
--- "a/\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redis.md"
+++ b/docs/database/Redis/Redis.md
@@ -1,32 +1,32 @@
-
+
+
- [redis 简介](#redis-简介)
-- [为什么要用 redis /为什么要用缓存](#为什么要用-redis-为什么要用缓存)
+- [为什么要用 redis/为什么要用缓存](#为什么要用-redis为什么要用缓存)
- [为什么要用 redis 而不用 map/guava 做缓存?](#为什么要用-redis-而不用-mapguava-做缓存)
- [redis 和 memcached 的区别](#redis-和-memcached-的区别)
- [redis 常见数据结构以及使用场景分析](#redis-常见数据结构以及使用场景分析)
- - [1. String](#1-string)
- - [2.Hash](#2hash)
- - [3.List](#3list)
- - [4.Set](#4set)
- - [5.Sorted Set](#5sorted-set)
+ - [1.String](#1string)
+ - [2.Hash](#2hash)
+ - [3.List](#3list)
+ - [4.Set](#4set)
+ - [5.Sorted Set](#5sorted-set)
- [redis 设置过期时间](#redis-设置过期时间)
-- [redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)](#redis-内存淘汰机制(mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?))
-- [redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)](#redis-持久化机制(怎么保证-redis-挂掉之后再重启数据可以进行恢复))
+- [redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)](#redis-内存淘汰机制mysql里有2000w数据redis中只存20w的数据如何保证redis中的数据都是热点数据)
+- [redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)](#redis-持久化机制怎么保证-redis-挂掉之后再重启数据可以进行恢复)
- [redis 事务](#redis-事务)
- [缓存雪崩和缓存穿透问题解决方案](#缓存雪崩和缓存穿透问题解决方案)
- [如何解决 Redis 的并发竞争 Key 问题](#如何解决-redis-的并发竞争-key-问题)
-- [如何保证缓存与数据库双写时的数据一致性?](#如何保证缓存与数据库双写时的数据一致性?)
-- [参考:](#参考:)
-
-
+- [如何保证缓存与数据库双写时的数据一致性?](#如何保证缓存与数据库双写时的数据一致性)
+- [参考:](#参考)
+
### redis 简介
-简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以存写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
+简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。redis 提供了多种数据类型来支持不同的业务场景。除此之外,redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。
-### 为什么要用 redis /为什么要用缓存
+### 为什么要用 redis/为什么要用缓存
主要从“高性能”和“高并发”这两点来看待这个问题。
@@ -72,7 +72,7 @@
### redis 常见数据结构以及使用场景分析
-#### 1. String
+#### 1.String
> **常用命令:** set,get,decr,incr,mget 等。
@@ -84,7 +84,7 @@ String数据结构是简单的key-value类型,value其实不仅可以是String
#### 2.Hash
> **常用命令:** hget,hset,hgetall 等。
-Hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以Hash数据结构来存储用户信息,商品信息等等。比如下面我就用 hash 类型存放了我本人的一些信息:
+hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以 hash 数据结构来存储用户信息,商品信息等等。比如下面我就用 hash 类型存放了我本人的一些信息:
```
key=JavaUser293847
@@ -128,7 +128,7 @@ sinterstore key1 key2 key3 将交集存在key1内
和set相比,sorted set增加了一个权重参数score,使得集合中的元素能够按score进行有序排列。
-**举例:** 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 SortedSet 结构进行存储。
+**举例:** 在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息,适合使用 Redis 中的 Sorted Set 结构进行存储。
### redis 设置过期时间
@@ -151,7 +151,7 @@ Redis中有个设置时间过期的功能,即对存储在 redis 数据库中
**redis 内存淘汰机制。**
-### redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)
+### redis 内存淘汰机制(MySQL里有2000w数据,Redis中只存20w的数据,如何保证Redis中的数据都是热点数据?)
redis 配置文件 redis.conf 中有相关注释,我这里就不贴了,大家可以自行查阅或者通过这个网址查看: [http://download.redis.io/redis-stable/redis.conf](http://download.redis.io/redis-stable/redis.conf)
@@ -160,19 +160,19 @@ redis 配置文件 redis.conf 中有相关注释,我这里就不贴了,大
1. **volatile-lru**:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2. **volatile-ttl**:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3. **volatile-random**:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
-4. **allkeys-lru**:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的).
+4. **allkeys-lru**:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
5. **allkeys-random**:从数据集(server.db[i].dict)中任意选择数据淘汰
-6. **no-enviction**:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
+6. **no-eviction**:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
**备注: 关于 redis 设置过期时间以及内存淘汰机制,我这里只是简单的总结一下,后面会专门写一篇文章来总结!**
-### redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)
+### redis 持久化机制(怎么保证 redis 挂掉之后再重启数据可以进行恢复)
-很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后回复数据),或者是为了防止系统故障而将数据备份到一个远程位置。
+很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后恢复数据),或者是为了防止系统故障而将数据备份到一个远程位置。
-Redis不同于Memcached的很重一点就是,Redis支持持久化,而且支持两种不同的持久化操作。**Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)**.这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法。
+Redis不同于Memcached的很重一点就是,Redis支持持久化,而且支持两种不同的持久化操作。**Redis的一种持久化方式叫快照(snapshotting,RDB),另一种方式是只追加文件(append-only file,AOF)**。这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法。
**快照(snapshotting)持久化(RDB)**
@@ -182,14 +182,13 @@ Redis可以通过创建快照来获得存储在内存里面的数据在某个时
```conf
-save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
+save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
-save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
+save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
```
-
**AOF(append-only file)持久化**
与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
@@ -203,41 +202,37 @@ appendonly yes
在Redis的配置文件中存在三种不同的 AOF 持久化方式,它们分别是:
```conf
-appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
+appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
-appendfsync no #让操作系统决定何时进行同步
+appendfsync no #让操作系统决定何时进行同步
```
为了兼顾数据和写入性能,用户可以考虑 appendfsync everysec选项 ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。
-
**Redis 4.0 对于持久化机制的优化**
Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 `aof-use-rdb-preamble` 开启)。
如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分是压缩格式不再是 AOF 格式,可读性较差。
-
-
**补充内容:AOF 重写**
AOF重写可以产生一个新的AOF文件,这个新的AOF文件和原有的AOF文件所保存的数据库状态一样,但体积更小。
-AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有AOF文件进行任伺读入、分析或者写入操作。
+AOF重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有AOF文件进行任何读入、分析或者写入操作。
在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新AOF文件期间,记录服务器执行的所有写命令。当子进程完成创建新AOF文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新AOF文件的末尾,使得新旧两个AOF文件所保存的数据库状态一致。最后,服务器用新的AOF文件替换旧的AOF文件,以此来完成AOF文件重写操作
-
**更多内容可以查看我的这篇文章:**
-- [https://github.com/Snailclimb/JavaGuide/blob/master/数据存储/Redis/Redis持久化.md](https://github.com/Snailclimb/JavaGuide/blob/master/数据存储/Redis/Redis持久化.md)
+- [Redis持久化](Redis持久化.md)
### redis 事务
Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。事务提供了一种将多个命令请求打包,然后一次性、按顺序地执行多个命令的机制,并且在事务执行期间,服务器不会中断事务而改去执行其他客户端的命令请求,它会将事务中的所有命令都执行完毕,然后才去处理其他客户端的命令请求。
-在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)。
+在传统的关系式数据库中,常常用 ACID 性质来检验事务功能的可靠性和安全性。在 Redis 中,事务总是具有原子性(Atomicity)、一致性(Consistency)和隔离性(Isolation),并且当 Redis 运行在某种特定的持久化模式下时,事务也具有持久性(Durability)。
### 缓存雪崩和缓存穿透问题解决方案
@@ -262,7 +257,7 @@ Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。
参考:
-- https://blog.csdn.net/zeb_perfect/article/details/54135506[enter link description here](https://blog.csdn.net/zeb_perfect/article/details/54135506)
+- [https://blog.csdn.net/zeb_perfect/article/details/54135506](https://blog.csdn.net/zeb_perfect/article/details/54135506)
### 如何解决 Redis 的并发竞争 Key 问题
@@ -278,9 +273,7 @@ Redis 通过 MULTI、EXEC、WATCH 等命令来实现事务(transaction)功能。
- https://www.jianshu.com/p/8bddd381de06
-
-### 如何保证缓存与数据库双写时的数据一致性?
-
+### 如何保证缓存与数据库双写时的数据一致性?
你只要用缓存,就可能会涉及到缓存与数据库双存储双写,你只要是双写,就一定会有数据一致性的问题,那么你如何解决一致性问题?
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redis\346\214\201\344\271\205\345\214\226.md" "b/docs/database/Redis/Redis\346\214\201\344\271\205\345\214\226.md"
similarity index 100%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redis\346\214\201\344\271\205\345\214\226.md"
rename to "docs/database/Redis/Redis\346\214\201\344\271\205\345\214\226.md"
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redlock\345\210\206\345\270\203\345\274\217\351\224\201.md" "b/docs/database/Redis/Redlock\345\210\206\345\270\203\345\274\217\351\224\201.md"
similarity index 100%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/Redis/Redlock\345\210\206\345\270\203\345\274\217\351\224\201.md"
rename to "docs/database/Redis/Redlock\345\210\206\345\270\203\345\274\217\351\224\201.md"
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/Redis/\345\246\202\344\275\225\345\201\232\345\217\257\351\235\240\347\232\204\345\210\206\345\270\203\345\274\217\351\224\201\357\274\214Redlock\347\234\237\347\232\204\345\217\257\350\241\214\344\271\210.md" "b/docs/database/Redis/\345\246\202\344\275\225\345\201\232\345\217\257\351\235\240\347\232\204\345\210\206\345\270\203\345\274\217\351\224\201\357\274\214Redlock\347\234\237\347\232\204\345\217\257\350\241\214\344\271\210.md"
similarity index 100%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/Redis/\345\246\202\344\275\225\345\201\232\345\217\257\351\235\240\347\232\204\345\210\206\345\270\203\345\274\217\351\224\201\357\274\214Redlock\347\234\237\347\232\204\345\217\257\350\241\214\344\271\210.md"
rename to "docs/database/Redis/\345\246\202\344\275\225\345\201\232\345\217\257\351\235\240\347\232\204\345\210\206\345\270\203\345\274\217\351\224\201\357\274\214Redlock\347\234\237\347\232\204\345\217\257\350\241\214\344\271\210.md"
diff --git "a/docs/database/\344\270\200\345\215\203\350\241\214MySQL\345\221\275\344\273\244.md" "b/docs/database/\344\270\200\345\215\203\350\241\214MySQL\345\221\275\344\273\244.md"
new file mode 100644
index 00000000000..acbfda3d7ac
--- /dev/null
+++ "b/docs/database/\344\270\200\345\215\203\350\241\214MySQL\345\221\275\344\273\244.md"
@@ -0,0 +1,973 @@
+> 原文地址:https://shockerli.net/post/1000-line-mysql-note/ ,JavaGuide 对本文进行了简答排版,新增了目录。
+> 作者:格物
+
+非常不错的总结,强烈建议保存下来,需要的时候看一看。
+
+
+- [基本操作](#基本操作)
+- [数据库操作](#数据库操作)
+- [表的操作](#表的操作)
+- [数据操作](#数据操作)
+- [字符集编码](#字符集编码)
+- [数据类型(列类型)](#数据类型列类型)
+- [列属性(列约束)](#列属性列约束)
+- [建表规范](#建表规范)
+- [SELECT](#select)
+- [UNION](#union)
+- [子查询](#子查询)
+- [连接查询(join)](#连接查询join)
+- [TRUNCATE](#truncate)
+- [备份与还原](#备份与还原)
+- [视图](#视图)
+- [事务(transaction)](#事务transaction)
+- [锁表](#锁表)
+- [触发器](#触发器)
+- [SQL编程](#sql编程)
+- [存储过程](#存储过程)
+- [用户和权限管理](#用户和权限管理)
+- [表维护](#表维护)
+- [杂项](#杂项)
+
+
+
+### 基本操作
+
+```mysql
+/* Windows服务 */
+-- 启动MySQL
+ net start mysql
+-- 创建Windows服务
+ sc create mysql binPath= mysqld_bin_path(注意:等号与值之间有空格)
+/* 连接与断开服务器 */
+mysql -h 地址 -P 端口 -u 用户名 -p 密码
+SHOW PROCESSLIST -- 显示哪些线程正在运行
+SHOW VARIABLES -- 显示系统变量信息
+```
+
+### 数据库操作
+
+```mysql
+/* 数据库操作 */ ------------------
+-- 查看当前数据库
+ SELECT DATABASE();
+-- 显示当前时间、用户名、数据库版本
+ SELECT now(), user(), version();
+-- 创建库
+ CREATE DATABASE[ IF NOT EXISTS] 数据库名 数据库选项
+ 数据库选项:
+ CHARACTER SET charset_name
+ COLLATE collation_name
+-- 查看已有库
+ SHOW DATABASES[ LIKE 'PATTERN']
+-- 查看当前库信息
+ SHOW CREATE DATABASE 数据库名
+-- 修改库的选项信息
+ ALTER DATABASE 库名 选项信息
+-- 删除库
+ DROP DATABASE[ IF EXISTS] 数据库名
+ 同时删除该数据库相关的目录及其目录内容
+```
+
+### 表的操作
+
+```mysql
+-- 创建表
+ CREATE [TEMPORARY] TABLE[ IF NOT EXISTS] [库名.]表名 ( 表的结构定义 )[ 表选项]
+ 每个字段必须有数据类型
+ 最后一个字段后不能有逗号
+ TEMPORARY 临时表,会话结束时表自动消失
+ 对于字段的定义:
+ 字段名 数据类型 [NOT NULL | NULL] [DEFAULT default_value] [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY] [COMMENT 'string']
+-- 表选项
+ -- 字符集
+ CHARSET = charset_name
+ 如果表没有设定,则使用数据库字符集
+ -- 存储引擎
+ ENGINE = engine_name
+ 表在管理数据时采用的不同的数据结构,结构不同会导致处理方式、提供的特性操作等不同
+ 常见的引擎:InnoDB MyISAM Memory/Heap BDB Merge Example CSV MaxDB Archive
+ 不同的引擎在保存表的结构和数据时采用不同的方式
+ MyISAM表文件含义:.frm表定义,.MYD表数据,.MYI表索引
+ InnoDB表文件含义:.frm表定义,表空间数据和日志文件
+ SHOW ENGINES -- 显示存储引擎的状态信息
+ SHOW ENGINE 引擎名 {LOGS|STATUS} -- 显示存储引擎的日志或状态信息
+ -- 自增起始数
+ AUTO_INCREMENT = 行数
+ -- 数据文件目录
+ DATA DIRECTORY = '目录'
+ -- 索引文件目录
+ INDEX DIRECTORY = '目录'
+ -- 表注释
+ COMMENT = 'string'
+ -- 分区选项
+ PARTITION BY ... (详细见手册)
+-- 查看所有表
+ SHOW TABLES[ LIKE 'pattern']
+ SHOW TABLES FROM 库名
+-- 查看表机构
+ SHOW CREATE TABLE 表名 (信息更详细)
+ DESC 表名 / DESCRIBE 表名 / EXPLAIN 表名 / SHOW COLUMNS FROM 表名 [LIKE 'PATTERN']
+ SHOW TABLE STATUS [FROM db_name] [LIKE 'pattern']
+-- 修改表
+ -- 修改表本身的选项
+ ALTER TABLE 表名 表的选项
+ eg: ALTER TABLE 表名 ENGINE=MYISAM;
+ -- 对表进行重命名
+ RENAME TABLE 原表名 TO 新表名
+ RENAME TABLE 原表名 TO 库名.表名 (可将表移动到另一个数据库)
+ -- RENAME可以交换两个表名
+ -- 修改表的字段机构(13.1.2. ALTER TABLE语法)
+ ALTER TABLE 表名 操作名
+ -- 操作名
+ ADD[ COLUMN] 字段定义 -- 增加字段
+ AFTER 字段名 -- 表示增加在该字段名后面
+ FIRST -- 表示增加在第一个
+ ADD PRIMARY KEY(字段名) -- 创建主键
+ ADD UNIQUE [索引名] (字段名)-- 创建唯一索引
+ ADD INDEX [索引名] (字段名) -- 创建普通索引
+ DROP[ COLUMN] 字段名 -- 删除字段
+ MODIFY[ COLUMN] 字段名 字段属性 -- 支持对字段属性进行修改,不能修改字段名(所有原有属性也需写上)
+ CHANGE[ COLUMN] 原字段名 新字段名 字段属性 -- 支持对字段名修改
+ DROP PRIMARY KEY -- 删除主键(删除主键前需删除其AUTO_INCREMENT属性)
+ DROP INDEX 索引名 -- 删除索引
+ DROP FOREIGN KEY 外键 -- 删除外键
+-- 删除表
+ DROP TABLE[ IF EXISTS] 表名 ...
+-- 清空表数据
+ TRUNCATE [TABLE] 表名
+-- 复制表结构
+ CREATE TABLE 表名 LIKE 要复制的表名
+-- 复制表结构和数据
+ CREATE TABLE 表名 [AS] SELECT * FROM 要复制的表名
+-- 检查表是否有错误
+ CHECK TABLE tbl_name [, tbl_name] ... [option] ...
+-- 优化表
+ OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
+-- 修复表
+ REPAIR [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... [QUICK] [EXTENDED] [USE_FRM]
+-- 分析表
+ ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
+```
+
+### 数据操作
+
+```mysql
+/* 数据操作 */ ------------------
+-- 增
+ INSERT [INTO] 表名 [(字段列表)] VALUES (值列表)[, (值列表), ...]
+ -- 如果要插入的值列表包含所有字段并且顺序一致,则可以省略字段列表。
+ -- 可同时插入多条数据记录!
+ REPLACE 与 INSERT 完全一样,可互换。
+ INSERT [INTO] 表名 SET 字段名=值[, 字段名=值, ...]
+-- 查
+ SELECT 字段列表 FROM 表名[ 其他子句]
+ -- 可来自多个表的多个字段
+ -- 其他子句可以不使用
+ -- 字段列表可以用*代替,表示所有字段
+-- 删
+ DELETE FROM 表名[ 删除条件子句]
+ 没有条件子句,则会删除全部
+-- 改
+ UPDATE 表名 SET 字段名=新值[, 字段名=新值] [更新条件]
+```
+
+### 字符集编码
+
+```mysql
+/* 字符集编码 */ ------------------
+-- MySQL、数据库、表、字段均可设置编码
+-- 数据编码与客户端编码不需一致
+SHOW VARIABLES LIKE 'character_set_%' -- 查看所有字符集编码项
+ character_set_client 客户端向服务器发送数据时使用的编码
+ character_set_results 服务器端将结果返回给客户端所使用的编码
+ character_set_connection 连接层编码
+SET 变量名 = 变量值
+ SET character_set_client = gbk;
+ SET character_set_results = gbk;
+ SET character_set_connection = gbk;
+SET NAMES GBK; -- 相当于完成以上三个设置
+-- 校对集
+ 校对集用以排序
+ SHOW CHARACTER SET [LIKE 'pattern']/SHOW CHARSET [LIKE 'pattern'] 查看所有字符集
+ SHOW COLLATION [LIKE 'pattern'] 查看所有校对集
+ CHARSET 字符集编码 设置字符集编码
+ COLLATE 校对集编码 设置校对集编码
+```
+
+### 数据类型(列类型)
+
+```mysql
+/* 数据类型(列类型) */ ------------------
+1. 数值类型
+-- a. 整型 ----------
+ 类型 字节 范围(有符号位)
+ tinyint 1字节 -128 ~ 127 无符号位:0 ~ 255
+ smallint 2字节 -32768 ~ 32767
+ mediumint 3字节 -8388608 ~ 8388607
+ int 4字节
+ bigint 8字节
+ int(M) M表示总位数
+ - 默认存在符号位,unsigned 属性修改
+ - 显示宽度,如果某个数不够定义字段时设置的位数,则前面以0补填,zerofill 属性修改
+ 例:int(5) 插入一个数'123',补填后为'00123'
+ - 在满足要求的情况下,越小越好。
+ - 1表示bool值真,0表示bool值假。MySQL没有布尔类型,通过整型0和1表示。常用tinyint(1)表示布尔型。
+-- b. 浮点型 ----------
+ 类型 字节 范围
+ float(单精度) 4字节
+ double(双精度) 8字节
+ 浮点型既支持符号位 unsigned 属性,也支持显示宽度 zerofill 属性。
+ 不同于整型,前后均会补填0.
+ 定义浮点型时,需指定总位数和小数位数。
+ float(M, D) double(M, D)
+ M表示总位数,D表示小数位数。
+ M和D的大小会决定浮点数的范围。不同于整型的固定范围。
+ M既表示总位数(不包括小数点和正负号),也表示显示宽度(所有显示符号均包括)。
+ 支持科学计数法表示。
+ 浮点数表示近似值。
+-- c. 定点数 ----------
+ decimal -- 可变长度
+ decimal(M, D) M也表示总位数,D表示小数位数。
+ 保存一个精确的数值,不会发生数据的改变,不同于浮点数的四舍五入。
+ 将浮点数转换为字符串来保存,每9位数字保存为4个字节。
+2. 字符串类型
+-- a. char, varchar ----------
+ char 定长字符串,速度快,但浪费空间
+ varchar 变长字符串,速度慢,但节省空间
+ M表示能存储的最大长度,此长度是字符数,非字节数。
+ 不同的编码,所占用的空间不同。
+ char,最多255个字符,与编码无关。
+ varchar,最多65535字符,与编码有关。
+ 一条有效记录最大不能超过65535个字节。
+ utf8 最大为21844个字符,gbk 最大为32766个字符,latin1 最大为65532个字符
+ varchar 是变长的,需要利用存储空间保存 varchar 的长度,如果数据小于255个字节,则采用一个字节来保存长度,反之需要两个字节来保存。
+ varchar 的最大有效长度由最大行大小和使用的字符集确定。
+ 最大有效长度是65532字节,因为在varchar存字符串时,第一个字节是空的,不存在任何数据,然后还需两个字节来存放字符串的长度,所以有效长度是64432-1-2=65532字节。
+ 例:若一个表定义为 CREATE TABLE tb(c1 int, c2 char(30), c3 varchar(N)) charset=utf8; 问N的最大值是多少? 答:(65535-1-2-4-30*3)/3
+-- b. blob, text ----------
+ blob 二进制字符串(字节字符串)
+ tinyblob, blob, mediumblob, longblob
+ text 非二进制字符串(字符字符串)
+ tinytext, text, mediumtext, longtext
+ text 在定义时,不需要定义长度,也不会计算总长度。
+ text 类型在定义时,不可给default值
+-- c. binary, varbinary ----------
+ 类似于char和varchar,用于保存二进制字符串,也就是保存字节字符串而非字符字符串。
+ char, varchar, text 对应 binary, varbinary, blob.
+3. 日期时间类型
+ 一般用整型保存时间戳,因为PHP可以很方便的将时间戳进行格式化。
+ datetime 8字节 日期及时间 1000-01-01 00:00:00 到 9999-12-31 23:59:59
+ date 3字节 日期 1000-01-01 到 9999-12-31
+ timestamp 4字节 时间戳 19700101000000 到 2038-01-19 03:14:07
+ time 3字节 时间 -838:59:59 到 838:59:59
+ year 1字节 年份 1901 - 2155
+datetime YYYY-MM-DD hh:mm:ss
+timestamp YY-MM-DD hh:mm:ss
+ YYYYMMDDhhmmss
+ YYMMDDhhmmss
+ YYYYMMDDhhmmss
+ YYMMDDhhmmss
+date YYYY-MM-DD
+ YY-MM-DD
+ YYYYMMDD
+ YYMMDD
+ YYYYMMDD
+ YYMMDD
+time hh:mm:ss
+ hhmmss
+ hhmmss
+year YYYY
+ YY
+ YYYY
+ YY
+4. 枚举和集合
+-- 枚举(enum) ----------
+enum(val1, val2, val3...)
+ 在已知的值中进行单选。最大数量为65535.
+ 枚举值在保存时,以2个字节的整型(smallint)保存。每个枚举值,按保存的位置顺序,从1开始逐一递增。
+ 表现为字符串类型,存储却是整型。
+ NULL值的索引是NULL。
+ 空字符串错误值的索引值是0。
+-- 集合(set) ----------
+set(val1, val2, val3...)
+ create table tab ( gender set('男', '女', '无') );
+ insert into tab values ('男, 女');
+ 最多可以有64个不同的成员。以bigint存储,共8个字节。采取位运算的形式。
+ 当创建表时,SET成员值的尾部空格将自动被删除。
+```
+
+### 列属性(列约束)
+
+```mysql
+/* 列属性(列约束) */ ------------------
+1. PRIMARY 主键
+ - 能唯一标识记录的字段,可以作为主键。
+ - 一个表只能有一个主键。
+ - 主键具有唯一性。
+ - 声明字段时,用 primary key 标识。
+ 也可以在字段列表之后声明
+ 例:create table tab ( id int, stu varchar(10), primary key (id));
+ - 主键字段的值不能为null。
+ - 主键可以由多个字段共同组成。此时需要在字段列表后声明的方法。
+ 例:create table tab ( id int, stu varchar(10), age int, primary key (stu, age));
+2. UNIQUE 唯一索引(唯一约束)
+ 使得某字段的值也不能重复。
+3. NULL 约束
+ null不是数据类型,是列的一个属性。
+ 表示当前列是否可以为null,表示什么都没有。
+ null, 允许为空。默认。
+ not null, 不允许为空。
+ insert into tab values (null, 'val');
+ -- 此时表示将第一个字段的值设为null, 取决于该字段是否允许为null
+4. DEFAULT 默认值属性
+ 当前字段的默认值。
+ insert into tab values (default, 'val'); -- 此时表示强制使用默认值。
+ create table tab ( add_time timestamp default current_timestamp );
+ -- 表示将当前时间的时间戳设为默认值。
+ current_date, current_time
+5. AUTO_INCREMENT 自动增长约束
+ 自动增长必须为索引(主键或unique)
+ 只能存在一个字段为自动增长。
+ 默认为1开始自动增长。可以通过表属性 auto_increment = x进行设置,或 alter table tbl auto_increment = x;
+6. COMMENT 注释
+ 例:create table tab ( id int ) comment '注释内容';
+7. FOREIGN KEY 外键约束
+ 用于限制主表与从表数据完整性。
+ alter table t1 add constraint `t1_t2_fk` foreign key (t1_id) references t2(id);
+ -- 将表t1的t1_id外键关联到表t2的id字段。
+ -- 每个外键都有一个名字,可以通过 constraint 指定
+ 存在外键的表,称之为从表(子表),外键指向的表,称之为主表(父表)。
+ 作用:保持数据一致性,完整性,主要目的是控制存储在外键表(从表)中的数据。
+ MySQL中,可以对InnoDB引擎使用外键约束:
+ 语法:
+ foreign key (外键字段) references 主表名 (关联字段) [主表记录删除时的动作] [主表记录更新时的动作]
+ 此时需要检测一个从表的外键需要约束为主表的已存在的值。外键在没有关联的情况下,可以设置为null.前提是该外键列,没有not null。
+ 可以不指定主表记录更改或更新时的动作,那么此时主表的操作被拒绝。
+ 如果指定了 on update 或 on delete:在删除或更新时,有如下几个操作可以选择:
+ 1. cascade,级联操作。主表数据被更新(主键值更新),从表也被更新(外键值更新)。主表记录被删除,从表相关记录也被删除。
+ 2. set null,设置为null。主表数据被更新(主键值更新),从表的外键被设置为null。主表记录被删除,从表相关记录外键被设置成null。但注意,要求该外键列,没有not null属性约束。
+ 3. restrict,拒绝父表删除和更新。
+ 注意,外键只被InnoDB存储引擎所支持。其他引擎是不支持的。
+
+```
+
+### 建表规范
+
+```mysql
+/* 建表规范 */ ------------------
+ -- Normal Format, NF
+ - 每个表保存一个实体信息
+ - 每个具有一个ID字段作为主键
+ - ID主键 + 原子表
+ -- 1NF, 第一范式
+ 字段不能再分,就满足第一范式。
+ -- 2NF, 第二范式
+ 满足第一范式的前提下,不能出现部分依赖。
+ 消除符合主键就可以避免部分依赖。增加单列关键字。
+ -- 3NF, 第三范式
+ 满足第二范式的前提下,不能出现传递依赖。
+ 某个字段依赖于主键,而有其他字段依赖于该字段。这就是传递依赖。
+ 将一个实体信息的数据放在一个表内实现。
+```
+
+### SELECT
+
+```mysql
+/* SELECT */ ------------------
+SELECT [ALL|DISTINCT] select_expr FROM -> WHERE -> GROUP BY [合计函数] -> HAVING -> ORDER BY -> LIMIT
+a. select_expr
+ -- 可以用 * 表示所有字段。
+ select * from tb;
+ -- 可以使用表达式(计算公式、函数调用、字段也是个表达式)
+ select stu, 29+25, now() from tb;
+ -- 可以为每个列使用别名。适用于简化列标识,避免多个列标识符重复。
+ - 使用 as 关键字,也可省略 as.
+ select stu+10 as add10 from tb;
+b. FROM 子句
+ 用于标识查询来源。
+ -- 可以为表起别名。使用as关键字。
+ SELECT * FROM tb1 AS tt, tb2 AS bb;
+ -- from子句后,可以同时出现多个表。
+ -- 多个表会横向叠加到一起,而数据会形成一个笛卡尔积。
+ SELECT * FROM tb1, tb2;
+ -- 向优化符提示如何选择索引
+ USE INDEX、IGNORE INDEX、FORCE INDEX
+ SELECT * FROM table1 USE INDEX (key1,key2) WHERE key1=1 AND key2=2 AND key3=3;
+ SELECT * FROM table1 IGNORE INDEX (key3) WHERE key1=1 AND key2=2 AND key3=3;
+c. WHERE 子句
+ -- 从from获得的数据源中进行筛选。
+ -- 整型1表示真,0表示假。
+ -- 表达式由运算符和运算数组成。
+ -- 运算数:变量(字段)、值、函数返回值
+ -- 运算符:
+ =, <=>, <>, !=, <=, <, >=, >, !, &&, ||,
+ in (not) null, (not) like, (not) in, (not) between and, is (not), and, or, not, xor
+ is/is not 加上ture/false/unknown,检验某个值的真假
+ <=>与<>功能相同,<=>可用于null比较
+d. GROUP BY 子句, 分组子句
+ GROUP BY 字段/别名 [排序方式]
+ 分组后会进行排序。升序:ASC,降序:DESC
+ 以下[合计函数]需配合 GROUP BY 使用:
+ count 返回不同的非NULL值数目 count(*)、count(字段)
+ sum 求和
+ max 求最大值
+ min 求最小值
+ avg 求平均值
+ group_concat 返回带有来自一个组的连接的非NULL值的字符串结果。组内字符串连接。
+e. HAVING 子句,条件子句
+ 与 where 功能、用法相同,执行时机不同。
+ where 在开始时执行检测数据,对原数据进行过滤。
+ having 对筛选出的结果再次进行过滤。
+ having 字段必须是查询出来的,where 字段必须是数据表存在的。
+ where 不可以使用字段的别名,having 可以。因为执行WHERE代码时,可能尚未确定列值。
+ where 不可以使用合计函数。一般需用合计函数才会用 having
+ SQL标准要求HAVING必须引用GROUP BY子句中的列或用于合计函数中的列。
+f. ORDER BY 子句,排序子句
+ order by 排序字段/别名 排序方式 [,排序字段/别名 排序方式]...
+ 升序:ASC,降序:DESC
+ 支持多个字段的排序。
+g. LIMIT 子句,限制结果数量子句
+ 仅对处理好的结果进行数量限制。将处理好的结果的看作是一个集合,按照记录出现的顺序,索引从0开始。
+ limit 起始位置, 获取条数
+ 省略第一个参数,表示从索引0开始。limit 获取条数
+h. DISTINCT, ALL 选项
+ distinct 去除重复记录
+ 默认为 all, 全部记录
+```
+
+### UNION
+
+```mysql
+/* UNION */ ------------------
+ 将多个select查询的结果组合成一个结果集合。
+ SELECT ... UNION [ALL|DISTINCT] SELECT ...
+ 默认 DISTINCT 方式,即所有返回的行都是唯一的
+ 建议,对每个SELECT查询加上小括号包裹。
+ ORDER BY 排序时,需加上 LIMIT 进行结合。
+ 需要各select查询的字段数量一样。
+ 每个select查询的字段列表(数量、类型)应一致,因为结果中的字段名以第一条select语句为准。
+```
+
+### 子查询
+
+```mysql
+/* 子查询 */ ------------------
+ - 子查询需用括号包裹。
+-- from型
+ from后要求是一个表,必须给子查询结果取个别名。
+ - 简化每个查询内的条件。
+ - from型需将结果生成一个临时表格,可用以原表的锁定的释放。
+ - 子查询返回一个表,表型子查询。
+ select * from (select * from tb where id>0) as subfrom where id>1;
+-- where型
+ - 子查询返回一个值,标量子查询。
+ - 不需要给子查询取别名。
+ - where子查询内的表,不能直接用以更新。
+ select * from tb where money = (select max(money) from tb);
+ -- 列子查询
+ 如果子查询结果返回的是一列。
+ 使用 in 或 not in 完成查询
+ exists 和 not exists 条件
+ 如果子查询返回数据,则返回1或0。常用于判断条件。
+ select column1 from t1 where exists (select * from t2);
+ -- 行子查询
+ 查询条件是一个行。
+ select * from t1 where (id, gender) in (select id, gender from t2);
+ 行构造符:(col1, col2, ...) 或 ROW(col1, col2, ...)
+ 行构造符通常用于与对能返回两个或两个以上列的子查询进行比较。
+ -- 特殊运算符
+ != all() 相当于 not in
+ = some() 相当于 in。any 是 some 的别名
+ != some() 不等同于 not in,不等于其中某一个。
+ all, some 可以配合其他运算符一起使用。
+```
+
+### 连接查询(join)
+
+```mysql
+/* 连接查询(join) */ ------------------
+ 将多个表的字段进行连接,可以指定连接条件。
+-- 内连接(inner join)
+ - 默认就是内连接,可省略inner。
+ - 只有数据存在时才能发送连接。即连接结果不能出现空行。
+ on 表示连接条件。其条件表达式与where类似。也可以省略条件(表示条件永远为真)
+ 也可用where表示连接条件。
+ 还有 using, 但需字段名相同。 using(字段名)
+ -- 交叉连接 cross join
+ 即,没有条件的内连接。
+ select * from tb1 cross join tb2;
+-- 外连接(outer join)
+ - 如果数据不存在,也会出现在连接结果中。
+ -- 左外连接 left join
+ 如果数据不存在,左表记录会出现,而右表为null填充
+ -- 右外连接 right join
+ 如果数据不存在,右表记录会出现,而左表为null填充
+-- 自然连接(natural join)
+ 自动判断连接条件完成连接。
+ 相当于省略了using,会自动查找相同字段名。
+ natural join
+ natural left join
+ natural right join
+select info.id, info.name, info.stu_num, extra_info.hobby, extra_info.sex from info, extra_info where info.stu_num = extra_info.stu_id;
+```
+
+### TRUNCATE
+
+```mysql
+/* TRUNCATE */ ------------------
+TRUNCATE [TABLE] tbl_name
+清空数据
+删除重建表
+区别:
+1,truncate 是删除表再创建,delete 是逐条删除
+2,truncate 重置auto_increment的值。而delete不会
+3,truncate 不知道删除了几条,而delete知道。
+4,当被用于带分区的表时,truncate 会保留分区
+```
+
+### 备份与还原
+
+```mysql
+/* 备份与还原 */ ------------------
+备份,将数据的结构与表内数据保存起来。
+利用 mysqldump 指令完成。
+-- 导出
+mysqldump [options] db_name [tables]
+mysqldump [options] ---database DB1 [DB2 DB3...]
+mysqldump [options] --all--database
+1. 导出一张表
+ mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)
+2. 导出多张表
+ mysqldump -u用户名 -p密码 库名 表1 表2 表3 > 文件名(D:/a.sql)
+3. 导出所有表
+ mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)
+4. 导出一个库
+ mysqldump -u用户名 -p密码 --lock-all-tables --database 库名 > 文件名(D:/a.sql)
+可以-w携带WHERE条件
+-- 导入
+1. 在登录mysql的情况下:
+ source 备份文件
+2. 在不登录的情况下
+ mysql -u用户名 -p密码 库名 < 备份文件
+```
+
+### 视图
+
+```mysql
+什么是视图:
+ 视图是一个虚拟表,其内容由查询定义。同真实的表一样,视图包含一系列带有名称的列和行数据。但是,视图并不在数据库中以存储的数据值集形式存在。行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。
+ 视图具有表结构文件,但不存在数据文件。
+ 对其中所引用的基础表来说,视图的作用类似于筛选。定义视图的筛选可以来自当前或其它数据库的一个或多个表,或者其它视图。通过视图进行查询没有任何限制,通过它们进行数据修改时的限制也很少。
+ 视图是存储在数据库中的查询的sql语句,它主要出于两种原因:安全原因,视图可以隐藏一些数据,如:社会保险基金表,可以用视图只显示姓名,地址,而不显示社会保险号和工资数等,另一原因是可使复杂的查询易于理解和使用。
+-- 创建视图
+CREATE [OR REPLACE] [ALGORITHM = {UNDEFINED | MERGE | TEMPTABLE}] VIEW view_name [(column_list)] AS select_statement
+ - 视图名必须唯一,同时不能与表重名。
+ - 视图可以使用select语句查询到的列名,也可以自己指定相应的列名。
+ - 可以指定视图执行的算法,通过ALGORITHM指定。
+ - column_list如果存在,则数目必须等于SELECT语句检索的列数
+-- 查看结构
+ SHOW CREATE VIEW view_name
+-- 删除视图
+ - 删除视图后,数据依然存在。
+ - 可同时删除多个视图。
+ DROP VIEW [IF EXISTS] view_name ...
+-- 修改视图结构
+ - 一般不修改视图,因为不是所有的更新视图都会映射到表上。
+ ALTER VIEW view_name [(column_list)] AS select_statement
+-- 视图作用
+ 1. 简化业务逻辑
+ 2. 对客户端隐藏真实的表结构
+-- 视图算法(ALGORITHM)
+ MERGE 合并
+ 将视图的查询语句,与外部查询需要先合并再执行!
+ TEMPTABLE 临时表
+ 将视图执行完毕后,形成临时表,再做外层查询!
+ UNDEFINED 未定义(默认),指的是MySQL自主去选择相应的算法。
+```
+
+### 事务(transaction)
+
+```mysql
+事务是指逻辑上的一组操作,组成这组操作的各个单元,要不全成功要不全失败。
+ - 支持连续SQL的集体成功或集体撤销。
+ - 事务是数据库在数据晚自习方面的一个功能。
+ - 需要利用 InnoDB 或 BDB 存储引擎,对自动提交的特性支持完成。
+ - InnoDB被称为事务安全型引擎。
+-- 事务开启
+ START TRANSACTION; 或者 BEGIN;
+ 开启事务后,所有被执行的SQL语句均被认作当前事务内的SQL语句。
+-- 事务提交
+ COMMIT;
+-- 事务回滚
+ ROLLBACK;
+ 如果部分操作发生问题,映射到事务开启前。
+-- 事务的特性
+ 1. 原子性(Atomicity)
+ 事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
+ 2. 一致性(Consistency)
+ 事务前后数据的完整性必须保持一致。
+ - 事务开始和结束时,外部数据一致
+ - 在整个事务过程中,操作是连续的
+ 3. 隔离性(Isolation)
+ 多个用户并发访问数据库时,一个用户的事务不能被其它用户的事物所干扰,多个并发事务之间的数据要相互隔离。
+ 4. 持久性(Durability)
+ 一个事务一旦被提交,它对数据库中的数据改变就是永久性的。
+-- 事务的实现
+ 1. 要求是事务支持的表类型
+ 2. 执行一组相关的操作前开启事务
+ 3. 整组操作完成后,都成功,则提交;如果存在失败,选择回滚,则会回到事务开始的备份点。
+-- 事务的原理
+ 利用InnoDB的自动提交(autocommit)特性完成。
+ 普通的MySQL执行语句后,当前的数据提交操作均可被其他客户端可见。
+ 而事务是暂时关闭“自动提交”机制,需要commit提交持久化数据操作。
+-- 注意
+ 1. 数据定义语言(DDL)语句不能被回滚,比如创建或取消数据库的语句,和创建、取消或更改表或存储的子程序的语句。
+ 2. 事务不能被嵌套
+-- 保存点
+ SAVEPOINT 保存点名称 -- 设置一个事务保存点
+ ROLLBACK TO SAVEPOINT 保存点名称 -- 回滚到保存点
+ RELEASE SAVEPOINT 保存点名称 -- 删除保存点
+-- InnoDB自动提交特性设置
+ SET autocommit = 0|1; 0表示关闭自动提交,1表示开启自动提交。
+ - 如果关闭了,那普通操作的结果对其他客户端也不可见,需要commit提交后才能持久化数据操作。
+ - 也可以关闭自动提交来开启事务。但与START TRANSACTION不同的是,
+ SET autocommit是永久改变服务器的设置,直到下次再次修改该设置。(针对当前连接)
+ 而START TRANSACTION记录开启前的状态,而一旦事务提交或回滚后就需要再次开启事务。(针对当前事务)
+
+```
+
+### 锁表
+
+```mysql
+/* 锁表 */
+表锁定只用于防止其它客户端进行不正当地读取和写入
+MyISAM 支持表锁,InnoDB 支持行锁
+-- 锁定
+ LOCK TABLES tbl_name [AS alias]
+-- 解锁
+ UNLOCK TABLES
+```
+
+### 触发器
+
+```mysql
+/* 触发器 */ ------------------
+ 触发程序是与表有关的命名数据库对象,当该表出现特定事件时,将激活该对象
+ 监听:记录的增加、修改、删除。
+-- 创建触发器
+CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW trigger_stmt
+ 参数:
+ trigger_time是触发程序的动作时间。它可以是 before 或 after,以指明触发程序是在激活它的语句之前或之后触发。
+ trigger_event指明了激活触发程序的语句的类型
+ INSERT:将新行插入表时激活触发程序
+ UPDATE:更改某一行时激活触发程序
+ DELETE:从表中删除某一行时激活触发程序
+ tbl_name:监听的表,必须是永久性的表,不能将触发程序与TEMPORARY表或视图关联起来。
+ trigger_stmt:当触发程序激活时执行的语句。执行多个语句,可使用BEGIN...END复合语句结构
+-- 删除
+DROP TRIGGER [schema_name.]trigger_name
+可以使用old和new代替旧的和新的数据
+ 更新操作,更新前是old,更新后是new.
+ 删除操作,只有old.
+ 增加操作,只有new.
+-- 注意
+ 1. 对于具有相同触发程序动作时间和事件的给定表,不能有两个触发程序。
+-- 字符连接函数
+concat(str1,str2,...])
+concat_ws(separator,str1,str2,...)
+-- 分支语句
+if 条件 then
+ 执行语句
+elseif 条件 then
+ 执行语句
+else
+ 执行语句
+end if;
+-- 修改最外层语句结束符
+delimiter 自定义结束符号
+ SQL语句
+自定义结束符号
+delimiter ; -- 修改回原来的分号
+-- 语句块包裹
+begin
+ 语句块
+end
+-- 特殊的执行
+1. 只要添加记录,就会触发程序。
+2. Insert into on duplicate key update 语法会触发:
+ 如果没有重复记录,会触发 before insert, after insert;
+ 如果有重复记录并更新,会触发 before insert, before update, after update;
+ 如果有重复记录但是没有发生更新,则触发 before insert, before update
+3. Replace 语法 如果有记录,则执行 before insert, before delete, after delete, after insert
+```
+
+### SQL编程
+
+```mysql
+/* SQL编程 */ ------------------
+--// 局部变量 ----------
+-- 变量声明
+ declare var_name[,...] type [default value]
+ 这个语句被用来声明局部变量。要给变量提供一个默认值,请包含一个default子句。值可以被指定为一个表达式,不需要为一个常数。如果没有default子句,初始值为null。
+-- 赋值
+ 使用 set 和 select into 语句为变量赋值。
+ - 注意:在函数内是可以使用全局变量(用户自定义的变量)
+--// 全局变量 ----------
+-- 定义、赋值
+set 语句可以定义并为变量赋值。
+set @var = value;
+也可以使用select into语句为变量初始化并赋值。这样要求select语句只能返回一行,但是可以是多个字段,就意味着同时为多个变量进行赋值,变量的数量需要与查询的列数一致。
+还可以把赋值语句看作一个表达式,通过select执行完成。此时为了避免=被当作关系运算符看待,使用:=代替。(set语句可以使用= 和 :=)。
+select @var:=20;
+select @v1:=id, @v2=name from t1 limit 1;
+select * from tbl_name where @var:=30;
+select into 可以将表中查询获得的数据赋给变量。
+ -| select max(height) into @max_height from tb;
+-- 自定义变量名
+为了避免select语句中,用户自定义的变量与系统标识符(通常是字段名)冲突,用户自定义变量在变量名前使用@作为开始符号。
+@var=10;
+ - 变量被定义后,在整个会话周期都有效(登录到退出)
+--// 控制结构 ----------
+-- if语句
+if search_condition then
+ statement_list
+[elseif search_condition then
+ statement_list]
+...
+[else
+ statement_list]
+end if;
+-- case语句
+CASE value WHEN [compare-value] THEN result
+[WHEN [compare-value] THEN result ...]
+[ELSE result]
+END
+-- while循环
+[begin_label:] while search_condition do
+ statement_list
+end while [end_label];
+- 如果需要在循环内提前终止 while循环,则需要使用标签;标签需要成对出现。
+ -- 退出循环
+ 退出整个循环 leave
+ 退出当前循环 iterate
+ 通过退出的标签决定退出哪个循环
+--// 内置函数 ----------
+-- 数值函数
+abs(x) -- 绝对值 abs(-10.9) = 10
+format(x, d) -- 格式化千分位数值 format(1234567.456, 2) = 1,234,567.46
+ceil(x) -- 向上取整 ceil(10.1) = 11
+floor(x) -- 向下取整 floor (10.1) = 10
+round(x) -- 四舍五入去整
+mod(m, n) -- m%n m mod n 求余 10%3=1
+pi() -- 获得圆周率
+pow(m, n) -- m^n
+sqrt(x) -- 算术平方根
+rand() -- 随机数
+truncate(x, d) -- 截取d位小数
+-- 时间日期函数
+now(), current_timestamp(); -- 当前日期时间
+current_date(); -- 当前日期
+current_time(); -- 当前时间
+date('yyyy-mm-dd hh:ii:ss'); -- 获取日期部分
+time('yyyy-mm-dd hh:ii:ss'); -- 获取时间部分
+date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j'); -- 格式化时间
+unix_timestamp(); -- 获得unix时间戳
+from_unixtime(); -- 从时间戳获得时间
+-- 字符串函数
+length(string) -- string长度,字节
+char_length(string) -- string的字符个数
+substring(str, position [,length]) -- 从str的position开始,取length个字符
+replace(str ,search_str ,replace_str) -- 在str中用replace_str替换search_str
+instr(string ,substring) -- 返回substring首次在string中出现的位置
+concat(string [,...]) -- 连接字串
+charset(str) -- 返回字串字符集
+lcase(string) -- 转换成小写
+left(string, length) -- 从string2中的左边起取length个字符
+load_file(file_name) -- 从文件读取内容
+locate(substring, string [,start_position]) -- 同instr,但可指定开始位置
+lpad(string, length, pad) -- 重复用pad加在string开头,直到字串长度为length
+ltrim(string) -- 去除前端空格
+repeat(string, count) -- 重复count次
+rpad(string, length, pad) --在str后用pad补充,直到长度为length
+rtrim(string) -- 去除后端空格
+strcmp(string1 ,string2) -- 逐字符比较两字串大小
+-- 流程函数
+case when [condition] then result [when [condition] then result ...] [else result] end 多分支
+if(expr1,expr2,expr3) 双分支。
+-- 聚合函数
+count()
+sum();
+max();
+min();
+avg();
+group_concat()
+-- 其他常用函数
+md5();
+default();
+--// 存储函数,自定义函数 ----------
+-- 新建
+ CREATE FUNCTION function_name (参数列表) RETURNS 返回值类型
+ 函数体
+ - 函数名,应该合法的标识符,并且不应该与已有的关键字冲突。
+ - 一个函数应该属于某个数据库,可以使用db_name.funciton_name的形式执行当前函数所属数据库,否则为当前数据库。
+ - 参数部分,由"参数名"和"参数类型"组成。多个参数用逗号隔开。
+ - 函数体由多条可用的mysql语句,流程控制,变量声明等语句构成。
+ - 多条语句应该使用 begin...end 语句块包含。
+ - 一定要有 return 返回值语句。
+-- 删除
+ DROP FUNCTION [IF EXISTS] function_name;
+-- 查看
+ SHOW FUNCTION STATUS LIKE 'partten'
+ SHOW CREATE FUNCTION function_name;
+-- 修改
+ ALTER FUNCTION function_name 函数选项
+--// 存储过程,自定义功能 ----------
+-- 定义
+存储存储过程 是一段代码(过程),存储在数据库中的sql组成。
+一个存储过程通常用于完成一段业务逻辑,例如报名,交班费,订单入库等。
+而一个函数通常专注与某个功能,视为其他程序服务的,需要在其他语句中调用函数才可以,而存储过程不能被其他调用,是自己执行 通过call执行。
+-- 创建
+CREATE PROCEDURE sp_name (参数列表)
+ 过程体
+参数列表:不同于函数的参数列表,需要指明参数类型
+IN,表示输入型
+OUT,表示输出型
+INOUT,表示混合型
+注意,没有返回值。
+```
+
+### 存储过程
+
+```mysql
+/* 存储过程 */ ------------------
+存储过程是一段可执行性代码的集合。相比函数,更偏向于业务逻辑。
+调用:CALL 过程名
+-- 注意
+- 没有返回值。
+- 只能单独调用,不可夹杂在其他语句中
+-- 参数
+IN|OUT|INOUT 参数名 数据类型
+IN 输入:在调用过程中,将数据输入到过程体内部的参数
+OUT 输出:在调用过程中,将过程体处理完的结果返回到客户端
+INOUT 输入输出:既可输入,也可输出
+-- 语法
+CREATE PROCEDURE 过程名 (参数列表)
+BEGIN
+ 过程体
+END
+```
+
+### 用户和权限管理
+
+```mysql
+/* 用户和权限管理 */ ------------------
+-- root密码重置
+1. 停止MySQL服务
+2. [Linux] /usr/local/mysql/bin/safe_mysqld --skip-grant-tables &
+ [Windows] mysqld --skip-grant-tables
+3. use mysql;
+4. UPDATE `user` SET PASSWORD=PASSWORD("密码") WHERE `user` = "root";
+5. FLUSH PRIVILEGES;
+用户信息表:mysql.user
+-- 刷新权限
+FLUSH PRIVILEGES;
+-- 增加用户
+CREATE USER 用户名 IDENTIFIED BY [PASSWORD] 密码(字符串)
+ - 必须拥有mysql数据库的全局CREATE USER权限,或拥有INSERT权限。
+ - 只能创建用户,不能赋予权限。
+ - 用户名,注意引号:如 'user_name'@'192.168.1.1'
+ - 密码也需引号,纯数字密码也要加引号
+ - 要在纯文本中指定密码,需忽略PASSWORD关键词。要把密码指定为由PASSWORD()函数返回的混编值,需包含关键字PASSWORD
+-- 重命名用户
+RENAME USER old_user TO new_user
+-- 设置密码
+SET PASSWORD = PASSWORD('密码') -- 为当前用户设置密码
+SET PASSWORD FOR 用户名 = PASSWORD('密码') -- 为指定用户设置密码
+-- 删除用户
+DROP USER 用户名
+-- 分配权限/添加用户
+GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
+ - all privileges 表示所有权限
+ - *.* 表示所有库的所有表
+ - 库名.表名 表示某库下面的某表
+ GRANT ALL PRIVILEGES ON `pms`.* TO 'pms'@'%' IDENTIFIED BY 'pms0817';
+-- 查看权限
+SHOW GRANTS FOR 用户名
+ -- 查看当前用户权限
+ SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();
+-- 撤消权限
+REVOKE 权限列表 ON 表名 FROM 用户名
+REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名 -- 撤销所有权限
+-- 权限层级
+-- 要使用GRANT或REVOKE,您必须拥有GRANT OPTION权限,并且您必须用于您正在授予或撤销的权限。
+全局层级:全局权限适用于一个给定服务器中的所有数据库,mysql.user
+ GRANT ALL ON *.*和 REVOKE ALL ON *.*只授予和撤销全局权限。
+数据库层级:数据库权限适用于一个给定数据库中的所有目标,mysql.db, mysql.host
+ GRANT ALL ON db_name.*和REVOKE ALL ON db_name.*只授予和撤销数据库权限。
+表层级:表权限适用于一个给定表中的所有列,mysql.talbes_priv
+ GRANT ALL ON db_name.tbl_name和REVOKE ALL ON db_name.tbl_name只授予和撤销表权限。
+列层级:列权限适用于一个给定表中的单一列,mysql.columns_priv
+ 当使用REVOKE时,您必须指定与被授权列相同的列。
+-- 权限列表
+ALL [PRIVILEGES] -- 设置除GRANT OPTION之外的所有简单权限
+ALTER -- 允许使用ALTER TABLE
+ALTER ROUTINE -- 更改或取消已存储的子程序
+CREATE -- 允许使用CREATE TABLE
+CREATE ROUTINE -- 创建已存储的子程序
+CREATE TEMPORARY TABLES -- 允许使用CREATE TEMPORARY TABLE
+CREATE USER -- 允许使用CREATE USER, DROP USER, RENAME USER和REVOKE ALL PRIVILEGES。
+CREATE VIEW -- 允许使用CREATE VIEW
+DELETE -- 允许使用DELETE
+DROP -- 允许使用DROP TABLE
+EXECUTE -- 允许用户运行已存储的子程序
+FILE -- 允许使用SELECT...INTO OUTFILE和LOAD DATA INFILE
+INDEX -- 允许使用CREATE INDEX和DROP INDEX
+INSERT -- 允许使用INSERT
+LOCK TABLES -- 允许对您拥有SELECT权限的表使用LOCK TABLES
+PROCESS -- 允许使用SHOW FULL PROCESSLIST
+REFERENCES -- 未被实施
+RELOAD -- 允许使用FLUSH
+REPLICATION CLIENT -- 允许用户询问从属服务器或主服务器的地址
+REPLICATION SLAVE -- 用于复制型从属服务器(从主服务器中读取二进制日志事件)
+SELECT -- 允许使用SELECT
+SHOW DATABASES -- 显示所有数据库
+SHOW VIEW -- 允许使用SHOW CREATE VIEW
+SHUTDOWN -- 允许使用mysqladmin shutdown
+SUPER -- 允许使用CHANGE MASTER, KILL, PURGE MASTER LOGS和SET GLOBAL语句,mysqladmin debug命令;允许您连接(一次),即使已达到max_connections。
+UPDATE -- 允许使用UPDATE
+USAGE -- “无权限”的同义词
+GRANT OPTION -- 允许授予权限
+```
+
+### 表维护
+
+```mysql
+/* 表维护 */
+-- 分析和存储表的关键字分布
+ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...
+-- 检查一个或多个表是否有错误
+CHECK TABLE tbl_name [, tbl_name] ... [option] ...
+option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}
+-- 整理数据文件的碎片
+OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...
+```
+
+### 杂项
+
+```mysql
+/* 杂项 */ ------------------
+1. 可用反引号(`)为标识符(库名、表名、字段名、索引、别名)包裹,以避免与关键字重名!中文也可以作为标识符!
+2. 每个库目录存在一个保存当前数据库的选项文件db.opt。
+3. 注释:
+ 单行注释 # 注释内容
+ 多行注释 /* 注释内容 */
+ 单行注释 -- 注释内容 (标准SQL注释风格,要求双破折号后加一空格符(空格、TAB、换行等))
+4. 模式通配符:
+ _ 任意单个字符
+ % 任意多个字符,甚至包括零字符
+ 单引号需要进行转义 \'
+5. CMD命令行内的语句结束符可以为 ";", "\G", "\g",仅影响显示结果。其他地方还是用分号结束。delimiter 可修改当前对话的语句结束符。
+6. SQL对大小写不敏感
+7. 清除已有语句:\c
+```
+
diff --git "a/docs/database/\344\270\200\346\235\241sql\350\257\255\345\217\245\345\234\250mysql\344\270\255\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md" "b/docs/database/\344\270\200\346\235\241sql\350\257\255\345\217\245\345\234\250mysql\344\270\255\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
new file mode 100644
index 00000000000..261a0c0b975
--- /dev/null
+++ "b/docs/database/\344\270\200\346\235\241sql\350\257\255\345\217\245\345\234\250mysql\344\270\255\345\246\202\344\275\225\346\211\247\350\241\214\347\232\204.md"
@@ -0,0 +1,149 @@
+本文来自[木木匠](https://github.com/kinglaw1204)投稿。
+
+
+
+- [一 MySQL 基础架构分析](#一-mysql-基础架构分析)
+ - [1.1 MySQL 基本架构概览](#11-mysql-基本架构概览)
+ - [1.2 Server 层基本组件介绍](#12-server-层基本组件介绍)
+ - [1) 连接器](#1-连接器)
+ - [2) 查询缓存(MySQL 8.0 版本后移除)](#2-查询缓存mysql-80-版本后移除)
+ - [3) 分析器](#3-分析器)
+ - [4) 优化器](#4-优化器)
+ - [5) 执行器](#5-执行器)
+- [二 语句分析](#二-语句分析)
+ - [2.1 查询语句](#21-查询语句)
+ - [2.2 更新语句](#22-更新语句)
+- [三 总结](#三-总结)
+- [四 参考](#四-参考)
+
+
+
+本篇文章会分析下一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的。
+
+在分析之前我会先带着你看看 MySQL 的基础架构,知道了 MySQL 由那些组件组成已经这些组件的作用是什么,可以帮助我们理解和解决这些问题。
+
+## 一 MySQL 基础架构分析
+
+### 1.1 MySQL 基本架构概览
+
+下图是 MySQL 的一个简要架构图,从下图你可以很清晰的看到用户的 SQL 语句在 MySQL 内部是如何执行的。
+
+先简单介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图,在 1.2 节中会详细介绍到这些组件的作用。
+
+- **连接器:** 身份认证和权限相关(登录 MySQL 的时候)。
+- **查询缓存:** 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
+- **分析器:** 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
+- **优化器:** 按照 MySQL 认为最优的方案去执行。
+- **执行器:** 执行语句,然后从存储引擎返回数据。
+
+
+
+简单来说 MySQL 主要分为 Server 层和存储引擎层:
+
+- **Server 层**:主要包括连接器、查询缓存、分析器、优化器、执行器等,所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图,函数等,还有一个通用的日志模块 binglog 日志模块。
+- **存储引擎**: 主要负责数据的存储和读取,采用可以替换的插件式架构,支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块。**现在最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本开始就被当做默认存储引擎了。**
+
+### 1.2 Server 层基本组件介绍
+
+#### 1) 连接器
+
+连接器主要和身份认证和权限相关的功能相关,就好比一个级别很高的门卫一样。
+
+主要负责用户登录数据库,进行用户的身份认证,包括校验账户密码,权限等操作,如果用户账户密码已通过,连接器会到权限表中查询该用户的所有权限,之后在这个连接里的权限逻辑判断都是会依赖此时读取到的权限数据,也就是说,后续只要这个连接不断开,即时管理员修改了该用户的权限,该用户也是不受影响的。
+
+#### 2) 查询缓存(MySQL 8.0 版本后移除)
+
+查询缓存主要用来缓存我们所执行的 SELECT 语句以及该语句的结果集。
+
+连接建立后,执行查询语句的时候,会先查询缓存,MySQL 会先校验这个 sql 是否执行过,以 Key-Value 的形式缓存在内存中,Key 是查询预计,Value 是结果集。如果缓存 key 被命中,就会直接返回给客户端,如果没有命中,就会执行后续的操作,完成后也会把结果缓存起来,方便下一次调用。当然在真正执行缓存查询的时候还是会校验用户的权限,是否有该表的查询条件。
+
+MySQL 查询不建议使用缓存,因为查询缓存失效在实际业务场景中可能会非常频繁,假如你对一个表更新的话,这个表上的所有的查询缓存都会被清空。对于不经常更新的数据来说,使用缓存还是可以的。
+
+所以,一般在大多数情况下我们都是不推荐去使用查询缓存的。
+
+MySQL 8.0 版本后删除了缓存的功能,官方也是认为该功能在实际的应用场景比较少,所以干脆直接删掉了。
+
+#### 3) 分析器
+
+MySQL 没有命中缓存,那么就会进入分析器,分析器主要是用来分析 SQL 语句是来干嘛的,分析器也会分为几步:
+
+**第一步,词法分析**,一条 SQL 语句有多个字符串组成,首先要提取关键字,比如 select,提出查询的表,提出字段名,提出查询条件等等。做完这些操作后,就会进入第二步。
+
+**第二步,语法分析**,主要就是判断你输入的 sql 是否正确,是否符合 MySQL 的语法。
+
+完成这 2 步之后,MySQL 就准备开始执行了,但是如何执行,怎么执行是最好的结果呢?这个时候就需要优化器上场了。
+
+#### 4) 优化器
+
+优化器的作用就是它认为的最优的执行方案去执行(有时候可能也不是最优,这篇文章涉及对这部分知识的深入讲解),比如多个索引的时候该如何选择索引,多表查询的时候如何选择关联顺序等。
+
+可以说,经过了优化器之后可以说这个语句具体该如何执行就已经定下来。
+
+#### 5) 执行器
+
+当选择了执行方案后,MySQL 就准备开始执行了,首先执行前会校验该用户有没有权限,如果没有权限,就会返回错误信息,如果有权限,就会去调用引擎的接口,返回接口执行的结果。
+
+## 二 语句分析
+
+### 2.1 查询语句
+
+说了以上这么多,那么究竟一条 sql 语句是如何执行的呢?其实我们的 sql 可以分为两种,一种是查询,一种是更新(增加,更新,删除)。我们先分析下查询语句,语句如下:
+
+```sql
+select * from tb_student A where A.age='18' and A.name=' 张三 ';
+```
+
+结合上面的说明,我们分析下这个语句的执行流程:
+
+* 先检查该语句是否有权限,如果没有权限,直接返回错误信息,如果有权限,在 MySQL8.0 版本以前,会先查询缓存,以这条 sql 语句为 key 在内存中查询是否有结果,如果有直接缓存,如果没有,执行下一步。
+* 通过分析器进行词法分析,提取 sql 语句的关键元素,比如提取上面这个语句是查询 select,提取需要查询的表名为 tb_student,需要查询所有的列,查询条件是这个表的 id='1'。然后判断这个 sql 语句是否有语法错误,比如关键词是否正确等等,如果检查没问题就执行下一步。
+* 接下来就是优化器进行确定执行方案,上面的 sql 语句,可以有两种执行方案:
+
+ a.先查询学生表中姓名为“张三”的学生,然后判断是否年龄是 18。
+ b.先找出学生中年龄 18 岁的学生,然后再查询姓名为“张三”的学生。
+ 那么优化器根据自己的优化算法进行选择执行效率最好的一个方案(优化器认为,有时候不一定最好)。那么确认了执行计划后就准备开始执行了。
+
+* 进行权限校验,如果没有权限就会返回错误信息,如果有权限就会调用数据库引擎接口,返回引擎的执行结果。
+
+### 2.2 更新语句
+
+以上就是一条查询 sql 的执行流程,那么接下来我们看看一条更新语句如何执行的呢?sql 语句如下:
+
+```
+update tb_student A set A.age='19' where A.name=' 张三 ';
+```
+我们来给张三修改下年龄,在实际数据库肯定不会设置年龄这个字段的,不然要被技术负责人打的。其实条语句也基本上会沿着上一个查询的流程走,只不过执行更新的时候肯定要记录日志啦,这就会引入日志模块了,MySQL 自带的日志模块式 **binlog(归档日志)** ,所有的存储引擎都可以使用,我们常用的 InnoDB 引擎还自带了一个日志模块 **redo log(重做日志)**,我们就以 InnoDB 模式下来探讨这个语句的执行流程。流程如下:
+
+* 先查询到张三这一条数据,如果有缓存,也是会用到缓存。
+* 然后拿到查询的语句,把 age 改为 19,然后调用引擎 API 接口,写入这一行数据,InnoDB 引擎把数据保存在内存中,同时记录 redo log,此时 redo log 进入 prepare 状态,然后告诉执行器,执行完成了,随时可以提交。
+* 执行器收到通知后记录 binlog,然后调用引擎接口,提交 redo log 为提交状态。
+* 更新完成。
+
+**这里肯定有同学会问,为什么要用两个日志模块,用一个日志模块不行吗?**
+
+这是因为最开始 MySQL 并没与 InnoDB 引擎( InnoDB 引擎是其他公司以插件形式插入 MySQL 的) ,MySQL 自带的引擎是 MyISAM,但是我们知道 redo log 是 InnoDB 引擎特有的,其他存储引擎都没有,这就导致会没有 crash-safe 的能力(crash-safe 的能力即使数据库发生异常重启,之前提交的记录都不会丢失),binlog 日志只能用来归档。
+
+并不是说只用一个日志模块不可以,只是 InnoDB 引擎就是通过 redo log 来支持事务的。那么,又会有同学问,我用两个日志模块,但是不要这么复杂行不行,为什么 redo log 要引入 prepare 预提交状态?这里我们用反证法来说明下为什么要这么做?
+
+* **先写 redo log 直接提交,然后写 binlog**,假设写完 redo log 后,机器挂了,binlog 日志没有被写入,那么机器重启后,这台机器会通过 redo log 恢复数据,但是这个时候 bingog 并没有记录该数据,后续进行机器备份的时候,就会丢失这一条数据,同时主从同步也会丢失这一条数据。
+* **先写 binlog,然后写 redo log**,假设写完了 binlog,机器异常重启了,由于没有 redo log,本机是无法恢复这一条记录的,但是 binlog 又有记录,那么和上面同样的道理,就会产生数据不一致的情况。
+
+如果采用 redo log 两阶段提交的方式就不一样了,写完 binglog 后,然后再提交 redo log 就会防止出现上述的问题,从而保证了数据的一致性。那么问题来了,有没有一个极端的情况呢?假设 redo log 处于预提交状态,binglog 也已经写完了,这个时候发生了异常重启会怎么样呢?
+这个就要依赖于 MySQL 的处理机制了,MySQL 的处理过程如下:
+
+* 判断 redo log 是否完整,如果判断是完整的,就立即提交。
+* 如果 redo log 只是预提交但不是 commit 状态,这个时候就会去判断 binlog 是否完整,如果完整就提交 redo log, 不完整就回滚事务。
+
+这样就解决了数据一致性的问题。
+
+## 三 总结
+
+* MySQL 主要分为 Server 层和引擎层,Server 层主要包括连接器、查询缓存、分析器、优化器、执行器,同时还有一个日志模块(binlog),这个日志模块所有执行引擎都可以共用,redolog 只有 InnoDB 有。
+* 引擎层是插件式的,目前主要包括,MyISAM,InnoDB,Memory 等。
+* 查询语句的执行流程如下:权限校验(如果命中缓存)---》查询缓存---》分析器---》优化器---》权限校验---》执行器---》引擎
+* 更新语句执行流程如下:分析器----》权限校验----》执行器---》引擎---redo log(prepare 状态---》binlog---》redo log(commit状态)
+
+## 四 参考
+
+* 《MySQL 实战45讲》
+* MySQL 5.6参考手册:
diff --git "a/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md" "b/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md"
new file mode 100644
index 00000000000..4cd950d5357
--- /dev/null
+++ "b/docs/database/\344\272\213\345\212\241\351\232\224\347\246\273\347\272\247\345\210\253(\345\233\276\346\226\207\350\257\246\350\247\243).md"
@@ -0,0 +1,149 @@
+> 本文由 [SnailClimb](https://github.com/Snailclimb) 和 [BugSpeak](https://github.com/BugSpeak) 共同完成。
+
+
+- [事务隔离级别(图文详解)](#事务隔离级别图文详解)
+ - [什么是事务?](#什么是事务)
+ - [事物的特性(ACID)](#事物的特性acid)
+ - [并发事务带来的问题](#并发事务带来的问题)
+ - [事务隔离级别](#事务隔离级别)
+ - [实际情况演示](#实际情况演示)
+ - [脏读(读未提交)](#脏读读未提交)
+ - [避免脏读(读已提交)](#避免脏读读已提交)
+ - [不可重复读](#不可重复读)
+ - [可重复读](#可重复读)
+ - [防止幻读(可重复读)](#防止幻读可重复读)
+ - [参考](#参考)
+
+
+
+## 事务隔离级别(图文详解)
+
+### 什么是事务?
+
+事务是逻辑上的一组操作,要么都执行,要么都不执行。
+
+事务最经典也经常被拿出来说例子就是转账了。假如小明要给小红转账1000元,这个转账会涉及到两个关键操作就是:将小明的余额减少1000元,将小红的余额增加1000元。万一在这两个操作之间突然出现错误比如银行系统崩溃,导致小明余额减少而小红的余额没有增加,这样就不对了。事务就是保证这两个关键操作要么都成功,要么都要失败。
+
+### 事物的特性(ACID)
+
+
+

+
+
+1. **原子性:** 事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
+2. **一致性:** 执行事务前后,数据保持一致,多个事务对同一个数据读取的结果是相同的;
+3. **隔离性:** 并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
+4. **持久性:** 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
+
+### 并发事务带来的问题
+
+在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对统一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
+
+- **脏读(Dirty read):** 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
+- **丢失修改(Lost to modify):** 指在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。 例如:事务1读取某表中的数据A=20,事务2也读取A=20,事务1修改A=A-1,事务2也修改A=A-1,最终结果A=19,事务1的修改被丢失。
+- **不可重复读(Unrepeatableread):** 指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
+- **幻读(Phantom read):** 幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
+
+**不可重复度和幻读区别:**
+
+不可重复读的重点是修改,幻读的重点在于新增或者删除。
+
+例1(同样的条件, 你读取过的数据, 再次读取出来发现值不一样了 ):事务1中的A先生读取自己的工资为 1000的操作还没完成,事务2中的B先生就修改了A的工资为2000,导 致A再读自己的工资时工资变为 2000;这就是不可重复读。
+
+ 例2(同样的条件, 第1次和第2次读出来的记录数不一样 ):假某工资单表中工资大于3000的有4人,事务1读取了所有工资大于3000的人,共查到4条记录,这时事务2 又插入了一条工资大于3000的记录,事务1再次读取时查到的记录就变为了5条,这样就导致了幻读。
+
+### 事务隔离级别
+
+**SQL 标准定义了四个隔离级别:**
+
+- **READ-UNCOMMITTED(读取未提交):** 最低的隔离级别,允许读取尚未提交的数据变更,**可能会导致脏读、幻读或不可重复读**。
+- **READ-COMMITTED(读取已提交):** 允许读取并发事务已经提交的数据,**可以阻止脏读,但是幻读或不可重复读仍有可能发生**。
+- **REPEATABLE-READ(可重复读):** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,**可以阻止脏读和不可重复读,但幻读仍有可能发生**。
+- **SERIALIZABLE(可串行化):** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,**该级别可以防止脏读、不可重复读以及幻读**。
+
+----
+
+| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
+| :---: | :---: | :---:| :---: |
+| READ-UNCOMMITTED | √ | √ | √ |
+| READ-COMMITTED | × | √ | √ |
+| REPEATABLE-READ | × | × | √ |
+| SERIALIZABLE | × | × | × |
+
+MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看
+
+```sql
+mysql> SELECT @@tx_isolation;
++-----------------+
+| @@tx_isolation |
++-----------------+
+| REPEATABLE-READ |
++-----------------+
+```
+
+这里需要注意的是:与 SQL 标准不同的地方在于InnoDB 存储引擎在 **REPEATABLE-READ(可重读)**事务隔离级别下使用的是Next-Key Lock 锁算法,因此可以避免幻读的产生,这与其他数据库系统(如 SQL Server)是不同的。所以说InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)** 已经可以完全保证事务的隔离性要求,即达到了 SQL标准的**SERIALIZABLE(可串行化)**隔离级别。
+
+因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是**READ-COMMITTED(读取提交内容):**,但是你要知道的是InnoDB 存储引擎默认使用 **REPEATABLE-READ(可重读)**并不会有任何性能损失。
+
+InnoDB 存储引擎在 **分布式事务** 的情况下一般会用到**SERIALIZABLE(可串行化)**隔离级别。
+
+### 实际情况演示
+
+在下面我会使用 2 个命令行mysql ,模拟多线程(多事务)对同一份数据的脏读问题。
+
+MySQL 命令行的默认配置中事务都是自动提交的,即执行SQL语句后就会马上执行 COMMIT 操作。如果要显式地开启一个事务需要使用命令:`START TARNSACTION`。
+
+我们可以通过下面的命令来设置隔离级别。
+
+```sql
+SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE]
+```
+
+我们再来看一下我们在下面实际操作中使用到的一些并发控制语句:
+
+- `START TARNSACTION` |`BEGIN`:显式地开启一个事务。
+- `COMMIT`:提交事务,使得对数据库做的所有修改成为永久性。
+- `ROLLBACK`:回滚会结束用户的事务,并撤销正在进行的所有未提交的修改。
+
+#### 脏读(读未提交)
+
+
+
实例.jpg,_ANDesc=img,)
+
+
+#### 避免脏读(读已提交)
+
+
+

+
+
+#### 不可重复读
+
+还是刚才上面的读已提交的图,虽然避免了读未提交,但是却出现了,一个事务还没有结束,就发生了 不可重复读问题。
+
+
+

+
+
+#### 可重复读
+
+
+

+
+
+#### 防止幻读(可重复读)
+
+
+
.jpg,_ANDesc=img,)
+
+
+一个事务对数据库进行操作,这种操作的范围是数据库的全部行,然后第二个事务也在对这个数据库操作,这种操作可以是插入一行记录或删除一行记录,那么第一个是事务就会觉得自己出现了幻觉,怎么还有没有处理的记录呢? 或者 怎么多处理了一行记录呢?
+
+幻读和不可重复读有些相似之处 ,但是不可重复读的重点是修改,幻读的重点在于新增或者删除。
+
+### 参考
+
+- 《MySQL技术内幕:InnoDB存储引擎》
+-
+- [Mysql 锁:灵魂七拷问](https://tech.youzan.com/seven-questions-about-the-lock-of-mysql/)
+- [Innodb 中的事务隔离级别和锁的关系](https://tech.meituan.com/2014/08/20/innodb-lock.html)
diff --git a/docs/essential-content-for-interview/BATJrealInterviewExperience/2019alipay-pinduoduo-toutiao.md b/docs/essential-content-for-interview/BATJrealInterviewExperience/2019alipay-pinduoduo-toutiao.md
new file mode 100644
index 00000000000..183a1852a90
--- /dev/null
+++ b/docs/essential-content-for-interview/BATJrealInterviewExperience/2019alipay-pinduoduo-toutiao.md
@@ -0,0 +1,294 @@
+作者: rhwayfun,原文地址:https://mp.weixin.qq.com/s/msYty4vjjC0PvrwasRH5Bw ,JavaGuide 已经获得作者授权并对原文进行了重新排版。
+
+
+- [写在2019年后的蚂蚁、头条、拼多多的面试总结](#写在2019年后的蚂蚁头条拼多多的面试总结)
+ - [准备过程](#准备过程)
+ - [蚂蚁金服](#蚂蚁金服)
+ - [一面](#一面)
+ - [二面](#二面)
+ - [三面](#三面)
+ - [四面](#四面)
+ - [五面](#五面)
+ - [小结](#小结)
+ - [拼多多](#拼多多)
+ - [面试前](#面试前)
+ - [一面](#一面-1)
+ - [二面](#二面-1)
+ - [三面](#三面-1)
+ - [小结](#小结-1)
+ - [字节跳动](#字节跳动)
+ - [面试前](#面试前-1)
+ - [一面](#一面-2)
+ - [二面](#二面-2)
+ - [小结](#小结-2)
+ - [总结](#总结)
+
+
+
+# 2019年蚂蚁金服、头条、拼多多的面试总结
+
+文章有点长,请耐心看完,绝对有收获!不想听我BB直接进入面试分享:
+
+- 准备过程
+- 蚂蚁金服面试分享
+- 拼多多面试分享
+- 字节跳动面试分享
+- 总结
+
+说起来开始进行面试是年前倒数第二周,上午9点,我还在去公司的公交上,突然收到蚂蚁的面试电话,其实算不上真正的面试。面试官只是和我聊了下他们在做的事情(主要是做双十一这里大促的稳定性保障,偏中间件吧),说的很详细,然后和我沟通了下是否有兴趣,我表示有兴趣,后面就收到正式面试的通知,最后没选择去蚂蚁表示抱歉。
+
+当时我自己也准备出去看看机会,顺便看看自己的实力。当时我其实挺纠结的,一方面现在部门也正需要我,还是可以有一番作为的,另一方面觉得近一年来进步缓慢,没有以前飞速进步的成就感了,而且业务和技术偏于稳定,加上自己也属于那种比较懒散的人,骨子里还是希望能够突破现状,持续在技术上有所精进。
+
+在开始正式的总结之前,还是希望各位同仁能否听我继续发泄一会,抱拳!
+
+我翻开自己2018年初立的flag,觉得甚是惭愧。其中就有一条是保持一周写一篇博客,奈何中间因为各种原因没能坚持下去。细细想来,主要是自己没能真正静下来心认真投入到技术的研究和学习,那么为什么会这样?说白了还是因为没有确定目标或者目标不明确,没有目标或者目标不明确都可能导致行动的失败。
+
+那么问题来了,目标是啥?就我而言,短期目标是深入研究某一项技术,比如最近在研究mysql,那么深入研究一定要动手实践并且有所产出,这就够了么?还需要我们能够举一反三,结合实际开发场景想一想日常开发要注意什么,这中间有没有什么坑?可以看出,要进步真的不是一件简单的事,这种反人类的行为需要我们克服自我的弱点,逐渐形成习惯。真正牛逼的人,从不觉得认真学习是一件多么难的事,因为这已经形成了他的习惯,就喝早上起床刷牙洗脸那么自然简单。
+
+扯了那么多,开始进入正题,先后进行了蚂蚁、拼多多和字节跳动的面试。
+
+## 准备过程
+
+先说说我自己的情况,我2016先在蚂蚁实习了将近三个月,然后去了我现在的老东家,2.5年工作经验,可以说毕业后就一直老老实实在老东家打怪升级,虽说有蚂蚁的实习经历,但是因为时间太短,还是有点虚的。所以面试官看到我简历第一个问题绝对是这样的。
+
+“哇,你在蚂蚁待过,不错啊”,面试官笑嘻嘻地问到。“是的,还好”,我说。“为啥才三个月?”,面试官脸色一沉问到。“哗啦啦解释一通。。。”,我解释道。“哦,原来如此,那我们开始面试吧”,面试官一本正经说到。
+
+尼玛,早知道不写蚂蚁的实习经历了,后面仔细一想,当初写上蚂蚁不就给简历加点料嘛。
+
+言归正传,准备过程其实很早开始了(当然这不是说我工作时老想着跳槽,因为我明白现在的老东家并不是终点,我还需要不断提升),具体可追溯到从蚂蚁离职的时候,当时出来也面了很多公司,没啥大公司,面了大概5家公司,都拿到offer了。
+
+工作之余常常会去额外研究自己感兴趣的技术以及工作用到的技术,力求把原理搞明白,并且会自己实践一把。此外,买了N多书,基本有时间就会去看,补补基础,什么操作系统、数据结构与算法、MySQL、JDK之类的源码,基本都好好温习了(文末会列一下自己看过的书和一些好的资料)。**我深知基础就像“木桶效应”的短板,决定了能装多少水。**
+
+此外,在正式决定看机会之前,我给自己列了一个提纲,主要包括Java要掌握的核心要点,有不懂的就查资料搞懂。我给自己定位还是Java工程师,所以Java体系是一定要做到心中有数的,很多东西没有常年的积累面试的时候很容易露馅,学习要对得起自己,不要骗人。
+
+剩下的就是找平台和内推了,除了蚂蚁,头条和拼多多都是找人内推的,感谢蚂蚁面试官对我的欣赏,以后说不定会去蚂蚁咯😄。
+
+平台:脉脉、GitHub、v2
+
+## 蚂蚁金服
+
+
+
+- 一面
+- 二面
+- 三面
+- 四面
+- 五面
+- 小结
+
+### 一面
+
+一面就做了一道算法题,要求两小时内完成,给了长度为N的有重复元素的数组,要求输出第10大的数。典型的TopK问题,快排算法搞定。
+
+算法题要注意的是合法性校验、边界条件以及异常的处理。另外,如果要写测试用例,一定要保证测试覆盖场景尽可能全。加上平时刷刷算法题,这种考核应该没问题的。
+
+### 二面
+
+- 自我介绍下呗
+- 开源项目贡献过代码么?(Dubbo提过一个打印accesslog的bug算么)
+- 目前在部门做什么,业务简单介绍下,内部有哪些系统,作用和交互过程说下
+- Dubbo踩过哪些坑,分别是怎么解决的?(说了异常处理时业务异常捕获的问题,自定义了一个异常拦截器)
+- 开始进入正题,说下你对线程安全的理解(多线程访问同一个对象,如果不需要考虑额外的同步,调用对象的行为就可以获得正确的结果就是线程安全)
+- 事务有哪些特性?(ACID)
+- 怎么理解原子性?(同一个事务下,多个操作要么成功要么失败,不存在部分成功或者部分失败的情况)
+- 乐观锁和悲观锁的区别?(悲观锁假定会发生冲突,访问的时候都要先获得锁,保证同一个时刻只有线程获得锁,读读也会阻塞;乐观锁假设不会发生冲突,只有在提交操作的时候检查是否有冲突)这两种锁在Java和MySQL分别是怎么实现的?(Java乐观锁通过CAS实现,悲观锁通过synchronize实现。mysql乐观锁通过MVCC,也就是版本实现,悲观锁可以通过select... for update加上排它锁)
+- HashMap为什么不是线程安全的?(多线程操作无并发控制,顺便说了在扩容的时候多线程访问时会造成死锁,会形成一个环,不过扩容时多线程操作形成环的问题再JDK1.8已经解决,但多线程下使用HashMap还会有一些其他问题比如数据丢失,所以多线程下不应该使用HashMap,而应该使用ConcurrentHashMap)怎么让HashMap变得线程安全?(Collections的synchronize方法包装一个线程安全的Map,或者直接用ConcurrentHashMap)两者的区别是什么?(前者直接在put和get方法加了synchronize同步,后者采用了分段锁以及CAS支持更高的并发)
+- jdk1.8对ConcurrentHashMap做了哪些优化?(插入的时候如果数组元素使用了红黑树,取消了分段锁设计,synchronize替代了Lock锁)为什么这样优化?(避免冲突严重时链表多长,提高查询效率,时间复杂度从O(N)提高到O(logN))
+- redis主从机制了解么?怎么实现的?
+- 有过GC调优的经历么?(有点虚,答得不是很好)
+- 有什么想问的么?
+
+### 三面
+
+- 简单自我介绍下
+- 监控系统怎么做的,分为哪些模块,模块之间怎么交互的?用的什么数据库?(MySQL)使用什么存储引擎,为什么使用InnnoDB?(支持事务、聚簇索引、MVCC)
+- 订单表有做拆分么,怎么拆的?(垂直拆分和水平拆分)
+- 水平拆分后查询过程描述下
+- 如果落到某个分片的数据很大怎么办?(按照某种规则,比如哈希取模、range,将单张表拆分为多张表)
+- 哈希取模会有什么问题么?(有的,数据分布不均,扩容缩容相对复杂 )
+- 分库分表后怎么解决读写压力?(一主多从、多主多从)
+- 拆分后主键怎么保证惟一?(UUID、Snowflake算法)
+- Snowflake生成的ID是全局递增唯一么?(不是,只是全局唯一,单机递增)
+- 怎么实现全局递增的唯一ID?(讲了TDDL的一次取一批ID,然后再本地慢慢分配的做法)
+- Mysql的索引结构说下(说了B+树,B+树可以对叶子结点顺序查找,因为叶子结点存放了数据结点且有序)
+- 主键索引和普通索引的区别(主键索引的叶子结点存放了整行记录,普通索引的叶子结点存放了主键ID,查询的时候需要做一次回表查询)一定要回表查询么?(不一定,当查询的字段刚好是索引的字段或者索引的一部分,就可以不用回表,这也是索引覆盖的原理)
+- 你们系统目前的瓶颈在哪里?
+- 你打算怎么优化?简要说下你的优化思路
+- 有什么想问我么?
+
+### 四面
+
+- 介绍下自己
+- 为什么要做逆向?
+- 怎么理解微服务?
+- 服务治理怎么实现的?(说了限流、压测、监控等模块的实现)
+- 这个不是中间件做的事么,为什么你们部门做?(当时没有单独的中间件团队,微服务刚搞不久,需要进行监控和性能优化)
+- 说说Spring的生命周期吧
+- 说说GC的过程(说了young gc和full gc的触发条件和回收过程以及对象创建的过程)
+- CMS GC有什么问题?(并发清除算法,浮动垃圾,短暂停顿)
+- 怎么避免产生浮动垃圾?(记得有个VM参数设置可以让扫描新生代之前进行一次young gc,但是因为gc是虚拟机自动调度的,所以不保证一定执行。但是还有参数可以让虚拟机强制执行一次young gc)
+- 强制young gc会有什么问题?(STW停顿时间变长)
+- 知道G1么?(了解一点 )
+- 回收过程是怎么样的?(young gc、并发阶段、混合阶段、full gc,说了Remember Set)
+- 你提到的Remember Set底层是怎么实现的?
+- 有什么想问的么?
+
+### 五面
+
+五面是HRBP面的,和我提前预约了时间,主要聊了之前在蚂蚁的实习经历、部门在做的事情、职业发展、福利待遇等。阿里面试官确实是具有一票否决权的,很看重你的价值观是否match,一般都比较喜欢皮实的候选人。HR面一定要诚实,不要说谎,只要你说谎HR都会去证实,直接cut了。
+
+- 之前蚂蚁实习三个月怎么不留下来?
+- 实习的时候主管是谁?
+- 实习做了哪些事情?(尼玛这种也问?)
+- 你对技术怎么看?平时使用什么技术栈?(阿里HR真的是既当爹又当妈,😂)
+- 最近有在研究什么东西么
+- 你对SRE怎么看
+- 对待遇有什么预期么
+
+最后HR还对我说目前稳定性保障部挺缺人的,希望我尽快回复。
+
+### 小结
+
+蚂蚁面试比较重视基础,所以Java那些基本功一定要扎实。蚂蚁的工作环境还是挺赞的,因为我面的是稳定性保障部门,还有许多单独的小组,什么三年1班,很有青春的感觉。面试官基本水平都比较高,基本都P7以上,除了基础还问了不少架构设计方面的问题,收获还是挺大的。
+
+## 拼多多
+
+
+
+- 面试前
+- 一面
+- 二面
+- 三面
+- 小结
+
+### 面试前
+
+面完蚂蚁后,早就听闻拼多多这个独角兽,决定也去面一把。首先我在脉脉找了一个拼多多的HR,加了微信聊了下,发了简历便开始我的拼多多面试之旅。这里要非常感谢拼多多HR小姐姐,从面试内推到offer确认一直都在帮我,人真的很nice。
+
+### 一面
+
+- 为啥蚂蚁只待了三个月?没转正?(转正了,解释了一通。。。)
+- Java中的HashMap、TreeMap解释下?(TreeMap红黑树,有序,HashMap无序,数组+链表)
+- TreeMap查询写入的时间复杂度多少?(O(logN))
+- HashMap多线程有什么问题?(线程安全,死锁)怎么解决?( jdk1.8用了synchronize + CAS,扩容的时候通过CAS检查是否有修改,是则重试)重试会有什么问题么?(CAS(Compare And Swap)是比较和交换,不会导致线程阻塞,但是因为重试是通过自旋实现的,所以仍然会占用CPU时间,还有ABA的问题)怎么解决?(超时,限定自旋的次数,ABA可以通过原理变量AtomicStampedReference解决,原理利用版本号进行比较)超过重试次数如果仍然失败怎么办?(synchronize互斥锁)
+- CAS和synchronize有什么区别?都用synchronize不行么?(CAS是乐观锁,不需要阻塞,硬件级别实现的原子性;synchronize会阻塞,JVM级别实现的原子性。使用场景不同,线程冲突严重时CAS会造成CPU压力过大,导致吞吐量下降,synchronize的原理是先自旋然后阻塞,线程冲突严重仍然有较高的吞吐量,因为线程都被阻塞了,不会占用CPU
+)
+- 如果要保证线程安全怎么办?(ConcurrentHashMap)
+- ConcurrentHashMap怎么实现线程安全的?(分段锁)
+- get需要加锁么,为什么?(不用,volatile关键字)
+- volatile的作用是什么?(保证内存可见性)
+- 底层怎么实现的?(说了主内存和工作内存,读写内存屏障,happen-before,并在纸上画了线程交互图)
+- 在多核CPU下,可见性怎么保证?(思考了一会,总线嗅探技术)
+- 聊项目,系统之间是怎么交互的?
+- 系统并发多少,怎么优化?
+- 给我一张纸,画了一个九方格,都填了数字,给一个M*N矩阵,从1开始逆时针打印这M*N个数,要求时间复杂度尽可能低(内心OS:之前貌似碰到过这题,最优解是怎么实现来着)思考中。。。
+- 可以先说下你的思路(想起来了,说了什么时候要变换方向的条件,向右、向下、向左、向上,依此循环)
+- 有什么想问我的?
+
+### 二面
+
+- 自我介绍下
+- 手上还有其他offer么?(拿了蚂蚁的offer)
+- 部门组织结构是怎样的?(这轮不是技术面么,不过还是老老实实说了)
+- 系统有哪些模块,每个模块用了哪些技术,数据怎么流转的?(面试官有点秃顶,一看级别就很高)给了我一张纸,我在上面简单画了下系统之间的流转情况
+- 链路追踪的信息是怎么传递的?(RpcContext的attachment,说了Span的结构:parentSpanId + curSpanId)
+- SpanId怎么保证唯一性?(UUID,说了下内部的定制改动)
+- RpcContext是在什么维度传递的?(线程)
+- Dubbo的远程调用怎么实现的?(讲了读取配置、拼装url、创建Invoker、服务导出、服务注册以及消费者通过动态代理、filter、获取Invoker列表、负载均衡等过程(哗啦啦讲了10多分钟),我可以喝口水么)
+- Spring的单例是怎么实现的?(单例注册表)
+- 为什么要单独实现一个服务治理框架?(说了下内部刚搞微服务不久,主要对服务进行一些监控和性能优化)
+- 谁主导的?内部还在使用么?
+- 逆向有想过怎么做成通用么?
+- 有什么想问的么?
+
+### 三面
+
+二面老大面完后就直接HR面了,主要问了些职业发展、是否有其他offer、以及入职意向等问题,顺便说了下公司的福利待遇等,都比较常规啦。不过要说的是手上有其他offer或者大厂经历会有一定加分。
+
+### 小结
+
+拼多多的面试流程就简单许多,毕竟是一个成立三年多的公司。面试难度中规中矩,只要基础扎实应该不是问题。但不得不说工作强度很大,开始面试前HR就提前和我确认能否接受这样强度的工作,想来的老铁还是要做好准备
+
+## 字节跳动
+
+
+
+- 面试前
+- 一面
+- 二面
+- 小结
+
+### 面试前
+
+头条的面试是三家里最专业的,每次面试前有专门的HR和你约时间,确定OK后再进行面试。每次都是通过视频面试,因为都是之前都是电话面或现场面,所以视频面试还是有点不自然。也有人觉得视频面试体验很赞,当然萝卜青菜各有所爱。最坑的二面的时候对方面试官的网络老是掉线,最后很冤枉的挂了(当然有一些点答得不好也是原因之一)。所以还是有点遗憾的。
+
+### 一面
+
+- 先自我介绍下
+- 聊项目,逆向系统是什么意思
+- 聊项目,逆向系统用了哪些技术
+- 线程池的线程数怎么确定?
+- 如果是IO操作为主怎么确定?
+- 如果计算型操作又怎么确定?
+- Redis熟悉么,了解哪些数据结构?(说了zset) zset底层怎么实现的?(跳表)
+- 跳表的查询过程是怎么样的,查询和插入的时间复杂度?(说了先从第一层查找,不满足就下沉到第二层找,因为每一层都是有序的,写入和插入的时间复杂度都是O(logN))
+- 红黑树了解么,时间复杂度?(说了是N叉平衡树,O(logN))
+- 既然两个数据结构时间复杂度都是O(logN),zset为什么不用红黑树(跳表实现简单,踩坑成本低,红黑树每次插入都要通过旋转以维持平衡,实现复杂)
+- 点了点头,说下Dubbo的原理?(说了服务注册与发布以及消费者调用的过程)踩过什么坑没有?(说了dubbo异常处理的和打印accesslog的问题)
+- CAS了解么?(说了CAS的实现)还了解其他同步机制么?(说了synchronize以及两者的区别,一个乐观锁,一个悲观锁)
+- 那我们做一道题吧,数组A,2*n个元素,n个奇数、n个偶数,设计一个算法,使得数组奇数下标位置放置的都是奇数,偶数下标位置放置的都是偶数
+- 先说下你的思路(从0下标开始遍历,如果是奇数下标判断该元素是否奇数,是则跳过,否则从该位置寻找下一个奇数)
+- 下一个奇数?怎么找?(有点懵逼,思考中。。)
+- 有思路么?(仍然是先遍历一次数组,并对下标进行判断,如果下标属性和该位置元素不匹配从当前下标的下一个遍历数组元素,然后替换)
+- 你这样时间复杂度有点高,如果要求O(N)要怎么做(思考一会,答道“定义两个指针,分别从下标0和1开始遍历,遇见奇数位是是偶数和偶数位是奇数就停下,交换内容”)
+- 时间差不多了,先到这吧。你有什么想问我的?
+
+### 二面
+
+- 面试官和蔼很多,你先介绍下自己吧
+- 你对服务治理怎么理解的?
+- 项目中的限流怎么实现的?(Guava ratelimiter,令牌桶算法)
+- 具体怎么实现的?(要点是固定速率且令牌数有限)
+- 如果突然很多线程同时请求令牌,有什么问题?(导致很多请求积压,线程阻塞)
+- 怎么解决呢?(可以把积压的请求放到消息队列,然后异步处理)
+- 如果不用消息队列怎么解决?(说了RateLimiter预消费的策略)
+- 分布式追踪的上下文是怎么存储和传递的?(ThreadLocal + spanId,当前节点的spanId作为下个节点的父spanId)
+- Dubbo的RpcContext是怎么传递的?(ThreadLocal)主线程的ThreadLocal怎么传递到线程池?(说了先在主线程通过ThreadLocal的get方法拿到上下文信息,在线程池创建新的ThreadLocal并把之前获取的上下文信息设置到ThreadLocal中。这里要注意的线程池创建的ThreadLocal要在finally中手动remove,不然会有内存泄漏的问题)
+- 你说的内存泄漏具体是怎么产生的?(说了ThreadLocal的结构,主要分两种场景:主线程仍然对ThreadLocal有引用和主线程不存在对ThreadLocal的引用。第一种场景因为主线程仍然在运行,所以还是有对ThreadLocal的引用,那么ThreadLocal变量的引用和value是不会被回收的。第二种场景虽然主线程不存在对ThreadLocal的引用,且该引用是弱引用,所以会在gc的时候被回收,但是对用的value不是弱引用,不会被内存回收,仍然会造成内存泄漏)
+- 线程池的线程是不是必须手动remove才可以回收value?(是的,因为线程池的核心线程是一直存在的,如果不清理,那么核心线程的threadLocals变量会一直持有ThreadLocal变量)
+- 那你说的内存泄漏是指主线程还是线程池?(主线程 )
+- 可是主线程不是都退出了,引用的对象不应该会主动回收么?(面试官和内存泄漏杠上了),沉默了一会。。。
+- 那你说下SpringMVC不同用户登录的信息怎么保证线程安全的?(刚才解释的有点懵逼,一下没反应过来,居然回答成锁了。大脑有点晕了,此时已经一个小时过去了,感觉情况不妙。。。)
+- 这个直接用ThreadLocal不就可以么,你见过SpringMVC有锁实现的代码么?(有点晕菜。。。)
+- 我们聊聊mysql吧,说下索引结构(说了B+树)
+- 为什么使用B+树?( 说了查询效率高,O(logN),可以充分利用磁盘预读的特性,多叉树,深度小,叶子结点有序且存储数据)
+- 什么是索引覆盖?(忘记了。。。 )
+- Java为什么要设计双亲委派模型?
+- 什么时候需要自定义类加载器?
+- 我们做一道题吧,手写一个对象池
+- 有什么想问我的么?(感觉我很多点都没答好,是不是挂了(结果真的是) )
+
+### 小结
+
+头条的面试确实很专业,每次面试官会提前给你发一个视频链接,然后准点开始面试,而且考察的点都比较全。
+
+面试官都有一个特点,会抓住一个值得深入的点或者你没说清楚的点深入下去直到你把这个点讲清楚,不然面试官会觉得你并没有真正理解。二面面试官给了我一点建议,研究技术的时候一定要去研究产生的背景,弄明白在什么场景解决什么特定的问题,其实很多技术内部都是相通的。很诚恳,还是很感谢这位面试官大大。
+
+## 总结
+
+从年前开始面试到头条面完大概一个多月的时间,真的有点身心俱疲的感觉。最后拿到了拼多多、蚂蚁的offer,还是蛮幸运的。头条的面试对我帮助很大,再次感谢面试官对我的诚恳建议,以及拼多多的HR对我的啰嗦的问题详细解答。
+
+这里要说的是面试前要做好两件事:简历和自我介绍,简历要好好回顾下自己做的一些项目,然后挑几个亮点项目。自我介绍基本每轮面试都有,所以最好提前自己练习下,想好要讲哪些东西,分别怎么讲。此外,简历提到的技术一定是自己深入研究过的,没有深入研究也最好找点资料预热下,不打无准备的仗。
+
+**这些年看过的书**:
+
+《Effective Java》、《现代操作系统》、《TCP/IP详解:卷一》、《代码整洁之道》、《重构》、《Java程序性能优化》、《Spring实战》、《Zookeeper》、《高性能MySQL》、《亿级网站架构核心技术》、《可伸缩服务架构》、《Java编程思想》
+
+说实话这些书很多只看了一部分,我通常会带着问题看书,不然看着看着就睡着了,简直是催眠良药😅。
+
+
+最后,附一张自己面试前准备的脑图:
+
+链接:https://pan.baidu.com/s/1o2l1tuRakBEP0InKEh4Hzw 密码:300d
+
+全文完。
diff --git "a/docs/essential-content-for-interview/BATJrealInterviewExperience/5\351\235\242\351\230\277\351\207\214,\347\273\210\350\216\267offer.md" "b/docs/essential-content-for-interview/BATJrealInterviewExperience/5\351\235\242\351\230\277\351\207\214,\347\273\210\350\216\267offer.md"
new file mode 100644
index 00000000000..9efac14f6d4
--- /dev/null
+++ "b/docs/essential-content-for-interview/BATJrealInterviewExperience/5\351\235\242\351\230\277\351\207\214,\347\273\210\350\216\267offer.md"
@@ -0,0 +1,96 @@
+> 作者:ppxyn。本文来自读者投稿,同时也欢迎各位投稿,**对于不错的原创文章我根据你的选择给予现金(50-200)、付费专栏或者任选书籍进行奖励!所以,快提 pr 或者邮件的方式(邮件地址在主页)给我投稿吧!** 当然,我觉得奖励是次要的,最重要的是你可以从自己整理知识点的过程中学习到很多知识。
+
+**目录**
+
+
+
+- [前言](#前言)
+- [一面\(技术面\)](#一面技术面)
+- [二面\(技术面\)](#二面技术面)
+- [三面\(技术面\)](#三面技术面)
+- [四面\(半个技术面\)](#四面半个技术面)
+- [五面\(HR面\)](#五面hr面)
+- [总结](#总结)
+
+
+
+### 前言
+
+在接触 Java 之前我接触的比较多的是硬件方面,用的比较多的语言就是C和C++。到了大三我才正式选择 Java 方向,到目前为止使用Java到现在大概有一年多的时间,所以Java算不上很好。刚开始投递的时候,实习刚辞职,也没准备笔试面试,很多东西都忘记了。所以,刚开始我并没有直接就投递阿里,毕竟心里还是有一点点小害怕的。于是,我就先投递了几个不算大的公司来练手,就是想着刷刷经验而已或者说是练练手(ps:还是挺对不起那些公司的)。面了一个月其他公司后,我找了我实验室的学长内推我,后面就有了这5次面试。
+
+下面简单的说一下我的这5次面试:4次技术面+1次HR面,希望我的经历能对你有所帮助。
+
+### 一面(技术面)
+
+1. 自我介绍(主要讲自己会的技术细节,项目经验,经历那些就一语带过,后面面试官会问你的)。
+2. 聊聊项目(就是一个很普通的分布式商城,自己做了一些改进),让我画了整个项目的架构图,然后针对项目抛了一系列的提高性能的问题,还问了我做项目的过程中遇到了那些问题,如何解决的,差不读就这些吧。
+3. 可能是我前面说了我会数据库优化,然后面试官就开始问索引、事务隔离级别、悲观锁和乐观锁、索引、ACID、MVVC这些问题。
+4. 浏览器输入URL发生了什么? TCP和UDP区别? TCP如何保证传输可靠性?
+5. 讲下跳表怎么实现的?哈夫曼编码是怎么回事?非递归且不用额外空间(不用栈),如何遍历二叉树
+6. 后面又问了很多JVM方面的问题,比如Java内存模型、常见的垃圾回收器、双亲委派模型这些
+7. 你有什么问题要问吗?
+
+### 二面(技术面)
+
+1. 自我介绍(主要讲自己会的技术细节,项目经验,经历那些就一语带过,后面面试官会问你的)。
+2. 操作系统的内存管理机制
+3. 进程和线程的区别
+4. 说下你对线程安全的理解
+5. volatile 有什么作用 ,sychronized和lock有什么区别
+6. ReentrantLock实现原理
+7. 用过CountDownLatch么?什么场景下用的?
+8. AQS底层原理。
+9. 造成死锁的原因有哪些,如何预防?
+10. 加锁会带来哪些性能问题。如何解决?
+11. HashMap、ConcurrentHashMap源码。HashMap是线程安全的吗?Hashtable呢?ConcurrentHashMap有了解吗?
+12. 是否可以实习?
+13. 你有什么问题要问吗?
+
+### 三面(技术面)
+
+1. 有没有参加过 ACM 或者他竞赛,有没有拿过什么奖?( 我说我没参加过ACM,本科参加过数学建模竞赛,名次并不好,没拿过什么奖。面试官好像有点失望,然后我又赶紧补充说我和老师一起做过一个项目,目前已经投入使用。面试官还比较感兴趣,后面又和他聊了一下这个项目。)
+2. 研究生期间,做过什么项目,发过论文吗?有什么成果吗?
+3. 你觉得你有什么优点和缺点?你觉得你相比于那些比你更优秀的人欠缺什么?
+4. 有读过什么源码吗?(我说我读过 Java 集合框架和 Netty 的,面试官说 Java 集合前几面一定问的差不多,就不问了,然后就问我 Netty的,我当时很慌啊!)
+5. 介绍一下自己对 Netty 的认识,为什么要用。说说业务中,Netty 的使用场景。什么是TCP 粘包/拆包,解决办法。Netty线程模型。Dubbo 在使用 Netty 作为网络通讯时候是如何避免粘包与半包问题?讲讲Netty的零拷贝?巴拉巴拉问了好多,我记得有好几个我都没回答上来,心里想着凉凉了啊。
+6. 用到了那些开源技术、在开源领域做过贡献吗?
+7. 常见的排序算法及其复杂度,现场写了快排。
+8. 红黑树,B树的一些问题。
+9. 讲讲算法及数据结构在实习项目中的用处。
+10. 自己的未来规划(就简单描述了一下自己未来的设想啊,说的还挺诚恳,面试官好像还挺满意的)
+11. 你有什么问题要问吗?
+
+### 四面(半个技术面)
+
+三面面完当天,晚上9点接到面试电话,感觉像是部门或者项目主管。 这个和之前的面试不大相同,感觉面试官主要考察的是你解决问题的能力、学习能力和团队协作能力。
+
+1. 让我讲一个自己觉得最不错的项目。然后就巴拉巴拉的聊,我记得主要是问了项目是如何进行协作的、遇到问题是如何解决的、与他人发生冲突是如何解决的这些。感觉聊了挺久。
+2. 出现 OOM 后你会怎么排查问题?
+3. 自己平时是如何学习新技术的?除了 Java 还回去了解其他技术吗?
+4. 上一段实习经历的收获。
+5. NginX如何做负载均衡、常见的负载均衡算法有哪些、一致性哈希的一致性是什么意思、一致性哈希是如何做哈希的
+6. 你有什么问题问我吗?
+7. 还有一些其他的,想不起来了,感觉这一面不是偏向技术来问。
+
+## 五面(HR面)
+
+1. 自我介绍(主要讲能突出自己的经历,会的编程技术一语带过)。
+2. 你觉得你有什么优点和缺点?如何克服这些缺点?
+3. 说一件大学里你自己比较有成就感的一件事情,为此付出了那些努力。
+4. 你前面跟其他面试官讲过一些你做的项目吧?可以给我讲讲吗?你要考虑到我不是一个做技术的人,怎么让我也听得懂。项目中有什么问题,你怎么解决的?你最大的收获是什么?
+5. 你目前有面试过其他公司吗?如果让你选,这些公司和阿里,你选哪个?(送分题,回答不好可能送命)
+6. 你期望的工作地点是哪里?
+7. 你有什么问题吗?
+
+### 总结
+
+1. 可以看出面试官问我的很多问题都是比较常见的问题,所以记得一定要提前准备,还要深入准备,不要回答的太皮毛。很多时候一个问题可能会牵扯出很多问题,遇到不会的问题不要慌,冷静分析,如果你真的回答不上来,也不要担心自己是不是就要挂了,很可能这个问题本身就比较难。
+2. 表达能力和沟通能力太重要了,一定要提前练一下,我自身就是一个不太会说话的人,所以,面试前我对于自我介绍、项目介绍和一些常见问题都在脑子里练了好久,确保面试的时候能够很清晰和简洁的说出来。
+3. 等待面试的过程和面试的过程真的好熬人,那段时间我压力也比较大,好在我私下找到学长聊了很多,心情也好了很多。
+4. 面试之后及时总结,面的好的话,不要得意,尽快准备下一场面试吧!
+
+我觉得我还算是比较幸运的,最后也祝大家都能获得心仪的Offer。
+
+
+
+
diff --git "a/docs/essential-content-for-interview/BATJrealInterviewExperience/\350\232\202\350\232\201\351\207\221\346\234\215\345\256\236\344\271\240\347\224\237\351\235\242\347\273\217\346\200\273\347\273\223(\345\267\262\346\213\277\345\217\243\345\244\264offer).md" "b/docs/essential-content-for-interview/BATJrealInterviewExperience/\350\232\202\350\232\201\351\207\221\346\234\215\345\256\236\344\271\240\347\224\237\351\235\242\347\273\217\346\200\273\347\273\223(\345\267\262\346\213\277\345\217\243\345\244\264offer).md"
new file mode 100644
index 00000000000..2e2df23b941
--- /dev/null
+++ "b/docs/essential-content-for-interview/BATJrealInterviewExperience/\350\232\202\350\232\201\351\207\221\346\234\215\345\256\236\344\271\240\347\224\237\351\235\242\347\273\217\346\200\273\347\273\223(\345\267\262\346\213\277\345\217\243\345\244\264offer).md"
@@ -0,0 +1,251 @@
+本文来自 Anonymous 的投稿 ,JavaGuide 对原文进行了重新排版和一点完善。
+
+
+
+- [一面 (37 分钟左右)](#一面-37-分钟左右)
+- [二面 (33 分钟左右)](#二面-33-分钟左右)
+- [三面 (46 分钟)](#三面-46-分钟)
+- [HR 面](#hr-面)
+
+
+
+### 一面 (37 分钟左右)
+
+一面是上海的小哥打来的,3.12 号中午确认的内推,下午就打来约时间了,也是唯一一个约时间的面试官。约的晚上八点。紧张的一比,人生第一次面试就献给了阿里。
+
+幸运的是一面的小哥特温柔。好像是个海归?口语中夹杂着英文。废话不多说,上干货:
+
+**面试官:** 先自我介绍下吧!
+
+**我:** 巴拉巴拉...。
+
+> 关于自我介绍:从 HR 面、技术面到高管面/部门主管面,面试官一般会让你先自我介绍一下,所以好好准备自己的自我介绍真的非常重要。网上一般建议的是准备好两份自我介绍:一份对 HR 说的,主要讲能突出自己的经历,会的编程技术一语带过;另一份对技术面试官说的,主要讲自己会的技术细节,项目经验,经历那些就一语带过。
+
+**面试官:** 我看你简历上写你做了个秒杀系统?我们就从这个项目开始吧,先介绍下你的项目。
+
+> 关于项目介绍:如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:
+>
+> 1. 对项目整体设计的一个感受(面试官可能会让你画系统的架构图)
+> 2. 在这个项目中你负责了什么、做了什么、担任了什么角色
+> 3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
+> 4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用 redis 做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+
+**我:** 我说了我是如何考虑它的需求(秒杀地址隐藏,记录订单,减库存),一开始简单的用 synchronized 锁住方法,出现了问题,后来乐观锁改进,又有瓶颈,再上缓存,出现了缓存雪崩,于是缓存预热,错开缓存失效时间。最后,发现先记录订单再减库存会减少行级锁等待时间。
+
+> 一面面试官很耐心地听,并给了我一些指导,问了我乐观锁是怎么实现的,我说是基于 sql 语句,在减库存操作的 where 条件里加剩余库存数>0,他说这应该不算是一种乐观锁,应该先查库存,在减库存的时候判断当前库存是否与读到的库存一样(可这样不是多一次查询操作吗?不是很理解,不过我没有反驳,只是说理解您的意思。事实证明千万别怼面试官,即使你觉得他说的不对)
+
+**面试官:** 我缓存雪崩什么情况下会发生?如何避免?
+
+**我:** 当多个商品缓存同时失效时会雪崩,导致大量查询数据库。还有就是秒杀刚开始的时候缓存里没有数据。解决方案:缓存预热,错开缓存失效时间
+
+**面试官:** 问我更新数据库的同时为什么不马上更新缓存,而是删除缓存?
+
+**我:** 因为考虑到更新数据库后更新缓存可能会因为多线程下导致写入脏数据(比如线程 A 先更新数据库成功,接下来要取更新缓存,接着线程 B 更新数据库,但 B 又更新了缓存,接着 B 的时间片用完了,线程 A 更新了缓存)
+
+逼逼了将近 30 分钟,面试官居然用周杰伦的语气对我说:
+
+
+
+我突然受宠若惊,连忙说谢谢,也正是因为第一次面试得到了面试官的肯定,才让我信心大增,二三面稳定发挥。
+
+**面试官又曰:** 我看你还懂数据库是吧,答:略懂略懂。。。那我问个简单的吧!
+
+**我:** 因为这个问题太简单了,所以我忘记它是什么了。
+
+**面试官:** 你还会啥数据库知识?
+
+**我:** 我一听,问的这么随意的吗。。。都让我选题了,我就说我了解索引,慢查询优化,巴拉巴拉
+
+**面试官:** 等等,你说索引是吧,那你能说下索引的存储数据结构吗?
+
+**我:** 我心想这简单啊,我就说 B+树,还说了为什么用 B+树
+
+**面试官:** 你简历上写的这个 J.U.C 包是什么啊?(他居然不知道 JUC)
+
+**我:** 就是 java 多线程的那个包啊。。。
+
+**面试官:** 那你都了解里面的哪些东西呢?
+
+**我:** 哈哈哈!这可是我的强项,从 ConcurrentHashMap,ConcurrentLinkedQueue 说到 CountDownLatch,CyclicBarrier,又说到线程池,分别说了底层实现和项目中的应用。
+
+**面试官:** 我觉得差不多了,那我再问个与技术无关的问题哈,虽然这个问题可能不应该我问,就是你是如何考虑你的项目架构的呢?
+
+**我:** 先用最简单的方式实现它,再去发掘系统的问题和瓶颈,于是查资料改进架构。。。
+
+**面试官:** 好,那我给你介绍下我这边的情况吧
+
+
+
+**总结:** 一面可能是简历面吧,问的比较简单,我在讲项目中说出了我做项目时的学习历程和思考,赢得了面试官的好感,感觉他应该给我的评价很好。
+
+### 二面 (33 分钟左右)
+
+然而开心了没一会,内推人问我面的怎么样啊?看我流程已经到大大 boss 那了。我一听二面不是主管吗???怎么直接跳了一面。于是瞬间慌了,赶紧(下床)学习准备二面。
+
+隔了一天,3.14 的早上 10:56 分,杭州的大大 boss 给我打来了电话,卧槽我当时在上毛概课,万恶的毛概课每节课都点名,我还在最后一排不敢跑出去。于是接起电话来怂怂地说不好意思我在上课,晚上可以面试吗?大大 boss 看来很忙啊,跟我说晚上没时间啊,再说吧!
+
+于是又隔了一天,3.16 中午我收到了北京的电话,当时心里小失望,我的大大 boss 呢???接起电话来,就是一番狂轰乱炸。。。
+
+第一步还是先自我介绍,这个就不多说了,提前准备好要说的重点就没问题!
+
+**面试官:** 我们还是从你的项目开始吧,说说你的秒杀系统。
+
+**我:** 一面时的套路。。。我考虑到秒杀地址在开始前不应暴露给用户。。。
+
+**面试官:** 等下啊,为什么要这样呢?暴露给用户会怎么样?
+
+**我:** 用户提前知道秒杀地址就可以写脚本来抢购了,这样不公平
+
+**面试官:** 那比如说啊,我现在是个黑客,我在秒杀开始时写好了脚本,运行一万个线程获取秒杀地址,这样是不是也不公平呢?
+
+**我:** 我考虑到了这方面,于是我自己写了个 LRU 缓存(划重点,这么多好用的缓存我为啥不用偏要自己写?就是为了让面试官上钩问我是怎么写的,这样我就可以逼逼准备好的内容了!),用这个缓存存储请求的 ip 和用户名,一个 ip 和用户名只能同时透过 3 个请求。
+
+**面试官:** 那我可不可以创建一个 ip 代理池和很多用户来抢购呢?假设我有很多手机号的账户。
+
+**我:** 这就是在为难我胖虎啊,我说这种情况跟真实用户操作太像了。。。我没法区别,不过我觉得可以通过地理位置信息或者机器学习算法来做吧。。。
+
+**面试官:** 好的这个问题就到这吧,你接着说
+
+**我:** 我把生成订单和减库存两条 sql 语句放在一个事务里,都操作成功了则认为秒杀成功。
+
+**面试官:** 等等,你这个订单表和商品库存表是在一个数据库的吧,那如果在不同的数据库中呢?
+
+**我:** 这面试官好变态啊,我只是个本科生?!?!我觉得应该要用分布式锁来实现吧。。。
+
+**面试官:** 有没有更轻量级的做法?
+
+**我:** 不知道了。后来查资料发现可以用消息队列来实现。使用消息队列主要能带来两个好处:(1) 通过异步处理提高系统性能(削峰、减少响应所需时间);(2) 降低系统耦合性。关于消息队列的更多内容可以查看这篇文章:
+
+后来发现消息队列作用好大,于是现在在学手写一个消息队列。
+
+**面试官:** 好的你接着说项目吧。
+
+**我:** 我考虑到了缓存雪崩问题,于是。。。
+
+**面试官:** 等等,你有没有考虑到一种情况,假如说你的缓存刚刚失效,大量流量就来查缓存,你的数据库会不会炸?
+
+**我:** 我不知道数据库会不会炸,反正我快炸了。当时说没考虑这么高的并发量,后来发现也是可以用消息队列来解决,对流量削峰填谷。
+
+**面试官:** 好项目聊(怼)完了,我们来说说别的,操作系统了解吧,你能说说 NIO 吗?
+
+**我:** NIO 是。。。
+
+**面试官:** 那你知道 NIO 的系统调用有哪些吗,具体是怎么实现的?
+
+**我:** 当时复习 NIO 的时候就知道是咋回事,不知道咋实现。最近在补这方面的知识,可见 NIO 还是很重要的!
+
+**面试官:** 说说进程切换时操作系统都会发生什么?
+
+**我:** 不如杀了我,我最讨厌操作系统了。简单说了下,可能不对,需要答案自行百度。
+
+**面试官:** 说说线程池?
+
+**答:** 卧槽这我熟啊,把 Java 并发编程的艺术里讲的都说出来了,说了得有十分钟,自夸一波,毕竟这本书我看了五遍😂
+
+**面试官:** 好问问计网吧如果设计一个聊天系统,应该用 TCP 还是 UDP?为什么
+
+**我:** 当然是 TCP!原因如下:
+
+
+
+**面试官:** 好的,你有什么要问我的吗?
+
+**我:** 我还有下一次面试吗?
+
+**面试官:** 应该。应该有的,一周内吧。还告诉我居然转正前要实习三个月?wtf,一个大三满课的本科生让我如何在八月底前实习三个月?
+
+**我:** 面试官再见
+
+
+
+### 三面 (46 分钟)
+
+3.18 号,三面来了,这次又是那个大大 boss!
+
+第一步还是先自我介绍,这个就不多说了,提前准备好要说的重点就没问题!
+
+**面试官:** 聊聊你的项目?
+
+**我:** 经过二面的教训,我迅速学习了一下分布式的理论知识,并应用到了我的项目(吹牛逼)中。
+
+**面试官:** 看你用到了 Spring 的事务机制,你能说下 Spring 的事务传播吗?
+
+**我:** 完了这个问题好像没准备,虽然之前刷知乎看到过。。。我就只说出来一条,面试官说其实这个有很多机制的,比如事务嵌套,内事务回滚外事务回滚都会有不同情况,你可以回去看看。
+
+**面试官:** 说说你的分布式事务解决方案?
+
+**我:** 我叭叭的照着资料查到的解决方案说了一通,面试官怎么好像没大听懂???
+
+> 阿里巴巴之前开源了一个分布式 Fescar(一种易于使用,高性能,基于 Java 的开源分布式事务解决方案),后来,Ant Financial 加入 Fescar,使其成为一个更加中立和开放的分布式交易社区,Fescar 重命名为 Seata。Github 地址:
+
+**面试官:** 好,我们聊聊其他项目,说说你这个 MapReduce 项目?MapReduce 原理了解过吗?
+
+**我:** 我叭叭地说了一通,面试官好像觉得这个项目太简单了。要不是没项目,我会把我的实验写上吗???
+
+**面试官:** 你这个手写 BP 神经网络是干了啥?
+
+**我:** 这是我选修机器学习课程时的一个作业,我又对它进行了扩展。
+
+**面试官:** 你能说说为什么调整权值时要沿着梯度下降的方向?
+
+**我:** 老大,你太厉害了,怎么什么都懂。我压根没准备这个项目。。。没想到会问,做过去好几个月了,加上当时一紧张就忘了,后来想起来大概是....。
+
+**面试官:** 好我们问问基础知识吧,说说什么叫 xisuo?
+
+**我:**???xisuo,您说什么,不好意思我没听清。(这面试官有点口音。。。)就是 xisuo 啊!xisuo 你不知道吗?。。。尴尬了十几秒后我终于意识到,他在说死锁!!!
+
+**面试官:** 假如 A 账户给 B 账户转钱,会发生 xisuo 吗?能具体说说吗?
+
+**我:** 当时答的不好,后来发现面试官又是想问分布式,具体答案参考这个:
+
+**面试官:** 为什么不考研?
+
+**我:** 不喜欢学术氛围,巴拉巴拉。
+
+**面试官:** 你有什么问题吗?
+
+**我:** 我还有下一面吗。。。面试官说让我等,一周内答复。
+
+------
+
+等了十天,一度以为我凉了,内推人说我流程到 HR 了,让我等着吧可能 HR 太忙了,3.28 号 HR 打来了电话,当时在教室,我直接飞了出去。
+
+### HR 面
+
+**面试官:** 你好啊,先自我介绍下吧
+
+**我:** 巴拉巴拉....HR 面的技术面试和技术面的还是有所区别的!
+
+面试官人特别好,一听就是很会说话的小姐姐!说我这里给你悄悄透露下,你的评级是 A 哦!
+
+
+
+接下来就是几个经典 HR 面挂人的问题,什么难给我来什么,我看别人的 HR 面怎么都是聊聊天。。。
+
+**面试官:** 你为什么选择支付宝呢,你怎么看待支付宝?
+
+**我:** 我从个人情怀,公司理念,环境氛围,市场价值,趋势导向分析了一波(说白了就是疯狂夸支付宝,不过说实话我说的那些一点都没撒谎,阿里确实做到了。比如我举了个雷军和格力打赌 5 年 2000 亿销售额,大部分企业家关注的是利益,而马云更关注的是真的为人类为世界做一些事情,利益不是第一位的。)
+
+**面试官:** 明白了解,那你的优点我们都很明了了,你能说说你的缺点吗?
+
+> 缺点肯定不能是目标岗位需要的关键能力!!!
+>
+> 总之,记住一点,面试官问你这个问题的话,你可以说一些不影响你这个职位工作需要的一些缺点。比如你面试后端工程师,面试官问你的缺点是什么的话,你可以这样说:自己比较内向,平时不太爱与人交流,但是考虑到以后可能要和客户沟通,自己正在努力改。
+
+**我:** 据说这是 HR 面最难的一个问题。。。我当时翻了好几天的知乎才找到一个合适的,也符合我的答案:我有时候会表现的不太自信,比如阿里的内推二月份就开始了,其实我当时已经复习了很久了,但是老是觉得自己还不行,不敢投简历,于是又把书看了一遍才投的,当时也是舍友怂恿一波才投的,面了之后发现其实自己也没有很差。(划重点,一定要把自己的缺点圆回来)。
+
+**面试官:** HR 好像不太满意我的答案,继续问我还有缺点吗?
+
+**我:** 我说比较容易紧张吧,举了自己大一面实验室因为紧张没进去的例子,后来不断调整心态,现在已经好很多了。
+
+接下来又是个好难的问题。
+
+**面试官:** BAT 都给你 offer 了,你怎么选?
+
+其实我当时好想说,BT 是什么?不好意思我只知道阿里。
+
+**我 :** 哈哈哈哈开玩笑,就说了阿里的文化,支付宝给我们带来很多便利,想加入支付宝为人类做贡献!
+
+最后 HR 问了我实习时间,现在大几之类的问题,说肯定会给我发 offer 的,让我等着就好了,希望过两天能收到好的结果。
+
+
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md" "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md"
similarity index 98%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md"
rename to "docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md"
index 36eaa60dff1..595a73e28b0 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md"
+++ "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\270\200\345\221\250\357\274\2102018-8-7\357\274\211.md"
@@ -139,7 +139,7 @@ Java程序设计语言对对象采用的不是引用调用,实际上,对象
下面再总结一下Java中方法参数的使用情况:
-- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
+- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
- 一个方法可以改变一个对象参数的状态。
- 一个方法不能让对象参数引用一个新的对象。
@@ -153,6 +153,7 @@ Java程序设计语言对对象采用的不是引用调用,实际上,对象
**==** : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
**equals()** : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
+
- 情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
- 情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
@@ -180,6 +181,7 @@ public class test1 {
```
**说明:**
+
- String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
- 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
@@ -245,7 +247,5 @@ hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返
[https://www.cnblogs.com/skywang12345/p/3324958.html](https://www.cnblogs.com/skywang12345/p/3324958.html)
-[https://www.cnblogs.com/skywang12345/p/3324958.html](https://www.cnblogs.com/skywang12345/p/3324958.html)
-
[https://www.cnblogs.com/Eason-S/p/5524837.html](https://www.cnblogs.com/Eason-S/p/5524837.html)
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\272\214\345\221\250(2018-8-13).md" "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\272\214\345\221\250(2018-8-13).md"
similarity index 95%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\272\214\345\221\250(2018-8-13).md"
rename to "docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\272\214\345\221\250(2018-8-13).md"
index 88aa2a6ec4a..2839aae916c 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\344\272\214\345\221\250(2018-8-13).md"
+++ "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\344\272\214\345\221\250(2018-8-13).md"
@@ -168,10 +168,12 @@ Java语言通过字节码的方式,在一定程度上解决了传统解释型
### 接口和抽象类的区别是什么?
1. 接口的方法默认是public,所有方法在接口中不能有实现,抽象类可以有非抽象的方法
-2. 接口中的实例变量默认是final类型的,而抽象类中则不一定
-3. 一个类可以实现多个接口,但最多只能实现一个抽象类
-4. 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
-5. 接口不能用new实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
+2. 接口中的实例变量默认是final类型的,而抽象类中则不一定
+3. 一个类可以实现多个接口,但最多只能实现一个抽象类
+4. 一个类实现接口的话要实现接口的所有方法,而抽象类不一定
+5. 接口不能用new实例化,但可以声明,但是必须引用一个实现该接口的对象 从设计层面来说,抽象是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
+
+注意:Java8 后接口可以有默认实现( default )。
### 成员变量与局部变量的区别有那些?
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\345\233\233\345\221\250(2018-8-30).md" "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\345\233\233\345\221\250(2018-8-30).md"
similarity index 67%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\345\233\233\345\221\250(2018-8-30).md"
rename to "docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\345\233\233\345\221\250(2018-8-30).md"
index c9a6ebf38d5..82d0a02b0b1 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\234\200\346\234\200\346\234\200\345\270\270\350\247\201\347\232\204Java\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223/\347\254\254\345\233\233\345\221\250(2018-8-30).md"
+++ "b/docs/essential-content-for-interview/MostCommonJavaInterviewQuestions/\347\254\254\345\233\233\345\221\250(2018-8-30).md"
@@ -16,39 +16,40 @@
## 2. 线程有哪些基本状态?这些状态是如何定义的?
-1. **新建(new)**:新创建了一个线程对象。
-2. **可运行(runnable)**:线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获 取cpu的使用权。
-3. **运行(running)**:可运行状态(runnable)的线程获得了cpu时间片(timeslice),执行程序代码。
-4. **阻塞(block)**:阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有 机会再次获得cpu timeslice转到运行(running)状态。阻塞的情况分三种:
- - **(一). 等待阻塞**:运行(running)的线程执行o.wait()方法,JVM会把该线程放 入等待队列(waitting queue)中。
- - **(二). 同步阻塞**:运行(running)的线程在获取对象的同步锁时,若该同步 锁 被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
- - **(三). 其他阻塞**: 运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
-5. **死亡(dead)**:线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
+Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态(图源《Java 并发编程艺术》4.1.4 节)。
-
+
-备注: 可以用早起坐地铁来比喻这个过程(下面参考自牛客网某位同学的回答):
+线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程状态变迁如下图所示(图源《Java 并发编程艺术》4.1.4 节):
-1. 还没起床:sleeping
-2. 起床收拾好了,随时可以坐地铁出发:Runnable
-3. 等地铁来:Waiting
-4. 地铁来了,但要排队上地铁:I/O阻塞
-5. 上了地铁,发现暂时没座位:synchronized阻塞
-6. 地铁上找到座位:Running
-7. 到达目的地:Dead
+
+
+由上图可以看出:线程创建之后它将处于 **NEW(新建)** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY(可运行)** 状态。可运行状态的线程获得了 CPU 时间片(timeslice)后就处于 **RUNNING(运行)** 状态。
+
+> 操作系统隐藏 Java 虚拟机(JVM)中的 RUNNABLE 和 RUNNING 状态,它只能看到 RUNNABLE 状态(图源:[HowToDoInJava](https://howtodoinjava.com/):[Java Thread Life Cycle and Thread States](https://howtodoinjava.com/java/multi-threading/java-thread-life-cycle-and-thread-states/)),所以 Java 系统一般将这两个状态统称为 **RUNNABLE(运行中)** 状态 。
+
+
+
+当线程执行 `wait()`方法之后,线程进入 **WAITING(等待)**状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而 **TIME_WAITING(超时等待)** 状态相当于在等待状态的基础上增加了超时限制,比如通过 `sleep(long millis)`方法或 `wait(long millis)`方法可以将 Java 线程置于 TIMED WAITING 状态。当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到 **BLOCKED(阻塞)** 状态。线程在执行 Runnable 的` run() `方法之后将会进入到 **TERMINATED(终止)** 状态。
+
## 3. 何为多线程?
多线程就是多个线程同时运行或交替运行。单核CPU的话是顺序执行,也就是交替运行。多核CPU的话,因为每个CPU有自己的运算器,所以在多个CPU中可以同时运行。
-## 4. 为什么多线程是必要的?
+## 4. 为什么要使用多线程?
+
+先从总体上来说:
+
+- **从计算机底层来说:**线程可以比作是轻量级的进程,是程序执行的最小单位,线程间的切换和调度的成本远远小于进程。另外,多核 CPU 时代意味着多个线程可以同时运行,这减少了线程上下文切换的开销。
+- **从当代互联网发展趋势来说:**现在的系统动不动就要求百万级甚至千万级的并发量,而多线程并发编程正是开发高并发系统的基础,利用好多线程机制可以大大提高系统整体的并发能力以及性能。
-1. 使用线程可以把占据长时间的程序中的任务放到后台去处理。
-2. 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度。
-3. 程序的运行速度可能加快。
+再深入到计算机底层来探讨:
+- **单核时代:** 在单核时代多线程主要是为了提高 CPU 和 IO 设备的综合利用率。举个例子:当只有一个线程的时候会导致 CPU 计算时,IO 设备空闲;进行 IO 操作时,CPU 空闲。我们可以简单地说这两者的利用率目前都是 50%左右。但是当有两个线程的时候就不一样了,当一个线程执行 CPU 计算时,另外一个线程可以进行 IO 操作,这样两个的利用率就可以在理想情况下达到 100%了。
+- **多核时代:** 多核时代多线程主要是为了提高 CPU 利用率。举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,CPU 只会一个 CPU 核心被利用到,而创建多个线程就可以让多个 CPU 核心被利用到,这样就提高了 CPU 的利用率。
## 5 使用多线程常见的三种方式
### ①继承Thread类
@@ -82,10 +83,10 @@ public class Run {

从上面的运行结果可以看出:线程是一个子任务,CPU以不确定的方式,或者说是以随机的时间来调用线程中的run方法。
-###②实现Runnable接口
+### ②实现Runnable接口
推荐实现Runnable接口方式开发多线程,因为Java单继承但是可以实现多个接口。
-。
+可以通过调用 Thead 类的 `setDaemon(true)` 方法设置当前的线程为守护线程。
注意事项:
@@ -178,7 +179,7 @@ Thread类中包含的成员变量代表了线程的某些优先级。如**Thread
- 两者最主要的区别在于:**sleep方法没有释放锁,而wait方法释放了锁** 。
- 两者都可以暂停线程的执行。
- Wait通常被用于线程间交互/通信,sleep通常被用于暂停执行。
-- wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者nofifyAl()方法。sleep()方法执行完成后,线程会自动苏醒。
+- wait()方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的notify()或者notifyAll()方法。sleep()方法执行完成后,线程会自动苏醒。
## 9 为什么我们调用start()方法时会执行run()方法,为什么我们不能直接调用run()方法?
@@ -186,7 +187,7 @@ Thread类中包含的成员变量代表了线程的某些优先级。如**Thread
这是另一个非常经典的java多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
new一个Thread,线程进入了新建状态;调用start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。
-start()会执行线程的相应准备工作,然后自动执行run()方法的内容,这是真正的多线程工作。 而直接执行run()方法,会把run方法当成一个mian线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
+start()会执行线程的相应准备工作,然后自动执行run()方法的内容,这是真正的多线程工作。 而直接执行run()方法,会把run方法当成一个main线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
**总结: 调用start方法方可启动线程并使线程进入就绪状态,而run方法只是thread的一个普通方法调用,还是在主线程里执行。**
diff --git a/docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md b/docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md
new file mode 100644
index 00000000000..4901f88932d
--- /dev/null
+++ b/docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md
@@ -0,0 +1,78 @@
+最近浏览 Github ,收藏了一些还算不错的 Java面试/学习相关的仓库,分享给大家,希望对你有帮助。我暂且按照目前的 Star 数量来排序。
+
+本文由 SnailClimb 整理,如需转载请联系作者。
+
+### 1. interviews
+
+- Github地址: [https://github.com/kdn251/interviews/blob/master/README-zh-cn.md](https://github.com/kdn251/interviews/blob/master/README-zh-cn.md)
+- star: 31k
+- 介绍: 软件工程技术面试个人指南。
+- 概览:
+
+ 
+
+### 2. JCSprout
+
+- Github地址:[https://github.com/crossoverJie/JCSprout](https://github.com/crossoverJie/JCSprout)
+- star: 17.7k
+- 介绍: Java Core Sprout:处于萌芽阶段的 Java 核心知识库。
+- 概览:
+
+ 
+
+### 3. JavaGuide
+
+- Github地址: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- star: 17.4k
+- 介绍: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
+- 概览:
+
+ 
+
+### 4. technology-talk
+
+- Github地址: [https://github.com/aalansehaiyang/technology-talk](https://github.com/aalansehaiyang/technology-talk)
+- star: 4.2k
+- 介绍: 汇总java生态圈常用技术框架、开源中间件,系统架构、项目管理、经典架构案例、数据库、常用三方库、线上运维等知识。
+
+### 5. fullstack-tutorial
+
+- Github地址: [https://github.com/frank-lam/fullstack-tutorial](https://github.com/frank-lam/fullstack-tutorial)
+- star: 2.8k
+- 介绍: Full Stack Developer Tutorial,后台技术栈/全栈开发/架构师之路,秋招/春招/校招/面试。 from zero to hero。
+- 概览:
+
+ 
+
+### 6. java-bible
+
+- Github地址:[https://github.com/biezhi/java-bible](https://github.com/biezhi/java-bible)
+- star: 1.9k
+- 介绍: 这里记录了一些技术摘要,部分文章来自网络,本项目的目的力求分享精品技术干货,以Java为主。
+- 概览:
+
+ 
+
+### 7. EasyJob
+
+- Github地址:[https://github.com/it-interview/EasyJob](https://github.com/it-interview/EasyJob)
+- star: 1.9k
+- 介绍: 互联网求职面试题、知识点和面经整理。
+
+### 8. advanced-java
+
+- Github地址:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- star: 1k
+- 介绍: 互联网 Java 工程师进阶知识完全扫盲
+
+### 9. 3y
+
+- Github地址:[https://github.com/ZhongFuCheng3y/3y](https://github.com/ZhongFuCheng3y/3y)
+- star: 0.4 k
+- 介绍: Java 知识整合。
+
+除了这九个仓库,再推荐几个不错的学习方向的仓库给大家。
+
+1. Star 数高达 4w+的 CS 笔记-CS-Notes:[https://github.com/CyC2018/CS-Notes](https://github.com/CyC2018/CS-Notes)
+2. 后端(尤其是Java)程序员的 Linux 学习仓库-Linux-Tutorial:[https://github.com/judasn/Linux-Tutorial](https://github.com/judasn/Linux-Tutorial)( Star:4.6k)
+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)
diff --git a/docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md b/docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md
new file mode 100644
index 00000000000..d515693722e
--- /dev/null
+++ b/docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md
@@ -0,0 +1,81 @@
+ 身边的朋友或者公众号的粉丝很多人都向我询问过:“我是双非/三本/专科学校的,我有机会进入大厂吗?”、“非计算机专业的学生能学好吗?”、“如何学习Java?”、“Java学习该学哪些东西?”、“我该如何准备Java面试?”......这些方面的问题。我会根据自己的一点经验对大部分人关心的这些问题进行答疑解惑。现在又刚好赶上考研结束,这篇文章也算是给考研结束准备往Java后端方向发展的朋友们指明一条学习之路。道理懂了如果没有实际行动,那这篇文章对你或许没有任何意义。
+
+### Question1:我是双非/三本/专科学校的,我有机会进入大厂吗?
+
+ 我自己也是非985非211学校的,结合自己的经历以及一些朋友的经历,我觉得让我回答这个问题再好不过。
+
+ 首先,我觉得学校歧视很正常,真的太正常了,如果要抱怨的话,你只能抱怨自己没有进入名校。但是,千万不要动不动说自己学校差,动不动拿自己学校当做自己进不了大厂的借口,学历只是筛选简历的很多标准中的一个而已,如果你够优秀,简历够丰富,你也一样可以和名校同学一起同台竞争。
+
+ 企业HR肯定是更喜欢高学历的人,毕竟985、211优秀人才比例肯定比普通学校高很多,HR团队肯定会优先在这些学校里选。这就好比相亲,你是愿意在很多优秀的人中选一个优秀的,还是愿意在很多普通的人中选一个优秀的呢?
+
+ 双非本科甚至是二本、三本甚至是专科的同学也有很多进入大厂的,不过比率相比于名校的低很多而已。从大厂招聘的结果上看,高学历人才的数量占据大头,那些成功进入BAT、美团,京东,网易等大厂的双非本科甚至是二本、三本甚至是专科的同学往往是因为具备丰富的项目经历或者在某个含金量比较高的竞赛比如ACM中取得了不错的成绩。**一部分学历不突出但能力出众的面试者能够进入大厂并不是说明学历不重要,而是学历的软肋能够通过其他的优势来弥补。** 所以,如果你的学校不够好而你自己又想去大厂的话,建议你可以从这几点来做:**①尽量在面试前最好有一个可以拿的出手的项目;②有实习条件的话,尽早出去实习,实习经历也会是你的简历的一个亮点(有能力在大厂实习最佳!);③参加一些含金量比较高的比赛,拿不拿得到名次没关系,重在锻炼。**
+
+
+### Question2:非计算机专业的学生能学好Java后台吗?我能进大厂吗?
+
+ 当然可以!现在非科班的程序员很多,很大一部分原因是互联网行业的工资比较高。我们学校外面的培训班里面90%都是非科班,我觉得他们很多人学的都还不错。另外,我的一个朋友本科是机械专业,大一开始自学安卓,技术贼溜,在我看来他比大部分本科是计算机的同学学的还要好。参考Question1的回答,即使你是非科班程序员,如果你想进入大厂的话,你也可以通过自己的其他优势来弥补。
+
+ 我觉得我们不应该因为自己的专业给自己划界限或者贴标签,说实话,很多科班的同学可能并不如你,你以为科班的同学就会认真听讲吗?还不是几乎全靠自己课下自学!不过如果你是非科班的话,你想要学好,那么注定就要舍弃自己本专业的一些学习时间,这是无可厚非的。
+
+ 建议非科班的同学,首先要打好计算机基础知识基础:①计算机网络、②操作系统、③数据机构与算法,我个人觉得这3个对你最重要。这些东西就像是内功,对你以后的长远发展非常有用。当然,如果你想要进大厂的话,这些知识也是一定会被问到的。另外,“一定学好数据结构与算法!一定学好数据结构与算法!一定学好数据结构与算法!”,重要的东西说3遍。
+
+
+
+### Question3: 我没有实习经历的话找工作是不是特别艰难?
+
+ 没有实习经历没关系,只要你有拿得出手的项目或者大赛经历的话,你依然有可能拿到大厂的 offer 。笔主当时找工作的时候就没有实习经历以及大赛获奖经历,单纯就是凭借自己的项目经验撑起了整个面试。
+
+ 如果你既没有实习经历,又没有拿得出手的项目或者大赛经历的话,我觉得在简历关,除非你有其他特别的亮点,不然,你应该就会被刷。
+
+### Question4: 我该如何准备面试呢?面试的注意事项有哪些呢?
+
+下面是我总结的一些准备面试的Tips以及面试必备的注意事项:
+
+1. **准备一份自己的自我介绍,面试的时候根据面试对象适当进行修改**(突出重点,突出自己的优势在哪里,切忌流水账);
+2. **注意随身带上自己的成绩单和简历复印件;** (有的公司在面试前都会让你交一份成绩单和简历当做面试中的参考。)
+3. **如果需要笔试就提前刷一些笔试题,大部分在线笔试的类型是选择题+编程题,有的还会有简答题。**(平时空闲时间多的可以刷一下笔试题目(牛客网上有很多),但是不要只刷面试题,不动手code,程序员不是为了考试而存在的。)另外,注意抓重点,因为题目太多了,但是有很多题目几乎次次遇到,像这样的题目一定要搞定。
+4. **提前准备技术面试。** 搞清楚自己面试中可能涉及哪些知识点、哪些知识点是重点。面试中哪些问题会被经常问到、自己该如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
+5. **面试之前做好定向复习。** 也就是专门针对你要面试的公司来复习。比如你在面试之前可以在网上找找有没有你要面试的公司的面经。
+6. **准备好自己的项目介绍。** 如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:①对项目整体设计的一个感受(面试官可能会让你画系统的架构图);②在这个项目中你负责了什么、做了什么、担任了什么角色;③ 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用;④项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用 redis 做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+7. **面试之后记得复盘。** 面试遭遇失败是很正常的事情,所以善于总结自己的失败原因才是最重要的。如果失败,不要灰心;如果通过,切勿狂喜。
+
+
+**一些还算不错的 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)
+
+### Question5: 我该自学还是报培训班呢?
+
+ 我本人更加赞同自学(你要知道去了公司可没人手把手教你了,而且几乎所有的公司都对培训班出生的有偏见。为什么有偏见,你学个东西还要去培训班,说明什么,同等水平下,你的自学能力以及自律能力一定是比不上自学的人的)。但是如果,你连每天在寝室坚持学上8个小时以上都坚持不了,或者总是容易半途而废的话,我还是推荐你去培训班。观望身边同学去培训班的,大多是非计算机专业或者是没有自律能力以及自学能力非常差的人。
+
+ 另外,如果自律能力不行,你也可以通过结伴学习、参加老师的项目等方式来督促自己学习。
+
+ 总结:去不去培训班主要还是看自己,如果自己能坚持自学就自学,坚持不下来就去培训班。
+
+### Question6: 没有项目经历/博客/Github开源项目怎么办?
+
+ 从现在开始做!
+
+ 网上有很多非常不错的项目视频,你就跟着一步一步做,不光要做,还要改进,改善。另外,如果你的老师有相关 Java 后台项目的话,你也可以主动申请参与进来。
+
+ 如果有自己的博客,也算是简历上的一个亮点。建议可以在掘金、Segmentfault、CSDN等技术交流社区写博客,当然,你也可以自己搭建一个博客(采用 Hexo+Githu Pages 搭建非常简单)。写一些什么?学习笔记、实战内容、读书笔记等等都可以。
+
+ 多用 Github,用好 Github,上传自己不错的项目,写好 readme 文档,在其他技术社区做好宣传。相信你也会收获一个不错的开源项目!
+
+
+### Question7: 大厂到底青睐什么样的应届生?
+
+ 从阿里、腾讯等大厂招聘官网对于Java后端方向/后端方向的应届实习生的要求,我们大概可以总结归纳出下面这 4 点能给简历增加很多分数:
+
+- 参加过竞赛(含金量超高的是ACM);
+- 对数据结构与算法非常熟练;
+- 参与过实际项目(比如学校网站);
+- 参与过某个知名的开源项目或者自己的某个开源项目很不错;
+
+ 除了我上面说的这三点,在面试Java工程师的时候,下面几点也提升你的个人竞争力:
+
+- 熟悉Python、Shell、Perl等脚本语言;
+- 熟悉 Java 优化,JVM调优;
+- 熟悉 SOA 模式;
+- 熟悉自己所用框架的底层知识比如Spring;
+- 了解分布式一些常见的理论;
+- 具备高并发开发经验;大数据开发经验等等。
+
diff --git a/docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md b/docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md
new file mode 100644
index 00000000000..1ae36a35734
--- /dev/null
+++ b/docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md
@@ -0,0 +1,88 @@
+不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个“有章可循”说的意思只是说应对技术面试是可以提前准备。 我其实特别不喜欢那种临近考试就提前背啊记啊各种题的行为,非常反对!我觉得这种方法特别极端,而且在稍有一点经验的面试官面前是根本没有用的。建议大家还是一步一个脚印踏踏实实地走。
+
+
+
+- [1 如何获取大厂面试机会?](#1-如何获取大厂面试机会)
+- [2 面试前的准备](#2--面试前的准备)
+ - [2.1 准备自己的自我介绍](#21-准备自己的自我介绍)
+ - [2.2 关于着装](#22-关于着装)
+ - [2.3 随身带上自己的成绩单和简历](#23-随身带上自己的成绩单和简历)
+ - [2.4 如果需要笔试就提前刷一些笔试题](#24-如果需要笔试就提前刷一些笔试题)
+ - [2.5 花时间一些逻辑题](#25-花时间一些逻辑题)
+ - [2.6 准备好自己的项目介绍](#26-准备好自己的项目介绍)
+ - [2.7 提前准备技术面试](#27-提前准备技术面试)
+ - [2.7 面试之前做好定向复习](#27-面试之前做好定向复习)
+- [3 面试之后复盘](#3-面试之后复盘)
+
+
+
+## 1 如何获取大厂面试机会?
+
+**在讲如何获取大厂面试机会之前,先来给大家科普/对比一下两个校招非常常见的概念——春招和秋招。**
+
+1. **招聘人数** :秋招多于春招 ;
+2. **招聘时间** : 秋招一般7月左右开始,大概一直持续到10月底。但是大厂(如BAT)都会早开始早结束,所以一定要把握好时间。春招最佳时间为3月,次佳时间为4月,进入5月基本就不会再有春招了(金三银四)。
+3. **应聘难度** :秋招略大于春招;
+4. **招聘公司:** 秋招数量多,而春招数量较少,一般为秋招的补充。
+
+**综上,一般来说,秋招的含金量明显是高于春招的。**
+
+**下面我就说一下我自己知道的一些方法,不过应该也涵盖了大部分获取面试机会的方法。**
+
+1. **关注大厂官网,随时投递简历(走流程的网申);**
+2. **线下参加宣讲会,直接投递简历;**
+3. **找到师兄师姐/认识的人,帮忙内推(能够让你避开网申简历筛选,笔试筛选,还是挺不错的,不过也还是需要你的简历够棒);**
+4. **博客发文被看中/Github优秀开源项目作者,大厂内部人员邀请你面试;**
+5. **求职类网站投递简历(不是太推荐,适合海投);**
+
+
+除了这些方法,我也遇到过这样的经历:有些大公司的一些部门可能暂时没招够人,然后如果你的亲戚或者朋友刚好在这个公司,而你正好又在寻求offer,那么面试机会基本上是有了,而且这种面试的难度好像一般还普遍比其他正规面试低很多。
+
+## 2 面试前的准备
+
+### 2.1 准备自己的自我介绍
+
+从HR面、技术面到高管面/部门主管面,面试官一般会让你先自我介绍一下,所以好好准备自己的自我介绍真的非常重要。网上一般建议的是准备好两份自我介绍:一份对hr说的,主要讲能突出自己的经历,会的编程技术一语带过;另一份对技术面试官说的,主要讲自己会的技术细节,项目经验,经历那些就一语带过。
+
+我这里简单分享一下我自己的自我介绍的一个简单的模板吧:
+
+> 面试官,您好!我叫某某。大学时间我主要利用课外时间学习某某。在校期间参与过一个某某系统的开发,另外,自己学习过程中也写过很多系统比如某某系统。在学习之余,我比较喜欢通过博客整理分享自己所学知识。我现在是某某社区的认证作者,写过某某很不错的文章。另外,我获得过某某奖,我的Github上开源的某个项目已经有多少Star了。
+
+### 2.2 关于着装
+
+穿西装、打领带、小皮鞋?NO!NO!NO!这是互联网公司面试又不是去走红毯,所以你只需要穿的简单大方就好,不需要太正式。
+
+### 2.3 随身带上自己的成绩单和简历
+
+有的公司在面试前都会让你交一份成绩单和简历当做面试中的参考。
+
+### 2.4 如果需要笔试就提前刷一些笔试题
+
+平时空闲时间多的可以刷一下笔试题目(牛客网上有很多)。但是不要只刷面试题,不动手code,程序员不是为了考试而存在的。
+
+### 2.5 花时间一些逻辑题
+
+面试中发现有些公司都有逻辑题测试环节,并且都把逻辑笔试成绩作为很重要的一个参考。
+
+### 2.6 准备好自己的项目介绍
+
+如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:
+
+1. 对项目整体设计的一个感受(面试官可能会让你画系统的架构图)
+2. 在这个项目中你负责了什么、做了什么、担任了什么角色
+3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
+4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+
+### 2.7 提前准备技术面试
+
+搞清楚自己面试中可能涉及哪些知识点、哪些知识点是重点。面试中哪些问题会被经常问到、自己该如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
+
+### 2.7 面试之前做好定向复习
+
+所谓定向复习就是专门针对你要面试的公司来复习。比如你在面试之前可以在网上找找有没有你要面试的公司的面经。
+
+举个栗子:在我面试 ThoughtWorks 的前几天我就在网上找了一些关于 ThoughtWorks 的技术面的一些文章。然后知道了 ThoughtWorks 的技术面会让我们在之前做的作业的基础上增加一个或两个功能,所以我提前一天就把我之前做的程序重新重构了一下。然后在技术面的时候,简单的改了几行代码之后写个测试就完事了。如果没有提前准备,我觉得 20 分钟我很大几率会完不成这项任务。
+
+## 3 面试之后复盘
+
+如果失败,不要灰心;如果通过,切勿狂喜。面试和工作实际上是两回事,可能很多面试未通过的人,工作能力比你强的多,反之亦然。我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
diff --git "a/docs/essential-content-for-interview/PreparingForInterview/\345\246\202\346\236\234\351\235\242\350\257\225\345\256\230\351\227\256\344\275\240\342\200\234\344\275\240\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230\351\227\256\346\210\221\345\220\227\357\274\237\342\200\235\346\227\266\357\274\214\344\275\240\350\257\245\345\246\202\344\275\225\345\233\236\347\255\224.md" "b/docs/essential-content-for-interview/PreparingForInterview/\345\246\202\346\236\234\351\235\242\350\257\225\345\256\230\351\227\256\344\275\240\342\200\234\344\275\240\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230\351\227\256\346\210\221\345\220\227\357\274\237\342\200\235\346\227\266\357\274\214\344\275\240\350\257\245\345\246\202\344\275\225\345\233\236\347\255\224.md"
new file mode 100644
index 00000000000..7a55d539d11
--- /dev/null
+++ "b/docs/essential-content-for-interview/PreparingForInterview/\345\246\202\346\236\234\351\235\242\350\257\225\345\256\230\351\227\256\344\275\240\342\200\234\344\275\240\346\234\211\344\273\200\344\271\210\351\227\256\351\242\230\351\227\256\346\210\221\345\220\227\357\274\237\342\200\235\346\227\266\357\274\214\344\275\240\350\257\245\345\246\202\344\275\225\345\233\236\347\255\224.md"
@@ -0,0 +1,64 @@
+我还记得当时我去参加面试的时候,几乎每一场面试,特别是HR面和高管面的时候,面试官总是会在结尾问我:“问了你这么多问题了,你有什么问题问我吗?”。这个时候很多人内心就会陷入短暂的纠结中:我该问吗?不问的话面试官会不会对我影响不好?问什么问题?问这个问题会不会让面试官对我的影响不好啊?
+
+
+
+### 这个问题对最终面试结果的影响到底大不大?
+
+就技术面试而言,回答这个问题的时候,只要你不是触碰到你所面试的公司的雷区,那么我觉得这对你能不能拿到最终offer来说影响确实是不大的。我说这些并不代表你就可以直接对面试官说:“我没问题了。”,笔主当时面试的时候确实也说过挺多次“没问题要问了。”,最终也没有导致笔主被pass掉(可能是前面表现比较好,哈哈,自恋一下)。我现在回想起来,觉得自己当时做法其实挺不对的。面试本身就是一个双向选择的过程,你对这个问题的回答也会侧面反映出你对这次面试的上心程度,你的问题是否有价值,也影响了你最终的选择与公司是否选择你。
+
+面试官在技术面试中主要考察的还是你这样个人到底有没有胜任这个工作的能力以及你是否适合公司未来的发展需要,很多公司还需要你认同它的文化,我觉得你只要不是太笨,应该不会栽在这里。除非你和另外一个人在能力上相同,但是只能在你们两个人中选一个,那么这个问题才对你能不能拿到offer至关重要。有准备总比没准备好,给面试官留一个好的影响总归是没错的。
+
+但是,就非技术面试来说,我觉得好好回答这个问题对你最终的结果还是比较重要的。
+
+总的来说不管是技术面试还是非技术面试,如果你想赢得公司的青睐和尊重,我觉得我们都应该重视这个问题。
+
+### 真诚一点,不要问太 Low 的问题
+
+回答这个问题很重要的一点就是你没有必要放低自己的姿态问一些很虚或者故意讨好面试官的问题,也不要把自己从面经上学到的东西照搬下来使用。面试官也不是傻子,特别是那种特别有经验的面试官,你是真心诚意的问问题,还是从别处照搬问题来讨好面试官,人家可能一听就听出来了。总的来说,还是要真诚。除此之外,不要问太 Low 的问题,会显得你整个人格局比较小或者说你根本没有准备(侧面反映你对这家公司不上心,既然你不上心,为什么要要你呢)。举例几个比较 Low 的问题,大家看看自己有没有问过其中的问题:
+
+- 贵公司的主要业务是什么?(面试之前自己不知道提前网上查一下吗?)
+- 贵公司的男女比例如何?(考虑脱单?记住你是来工作的!)
+- 贵公司一年搞几次外出旅游?(你是来工作的,这些娱乐活动先别放在心上!)
+- ......
+
+### 有哪些有价值的问题值得问?
+
+针对这个问题。笔主专门找了几个专门做HR工作的小哥哥小姐姐们询问并且查阅了挺多前辈们的回答,然后结合自己的实际经历,我概括了下面几个比较适合问的问题。
+
+#### 面对HR或者其他Level比较低的面试官时
+
+1. **能不能谈谈你作为一个公司老员工对公司的感受?** (这个问题比较容易回答,不会让面试官陷入无话可说的尴尬境地。另外,从面试官的回答中你可以加深对这个公司的了解,让你更加清楚这个公司到底是不是你想的那样或者说你是否能适应这个公司的文化。除此之外,这样的问题在某种程度上还可以拉进你与面试官的距离。)
+2. **能不能问一下,你当时因为什么原因选择加入这家公司的呢或者说这家公司有哪些地方吸引你?有什么地方你觉得还不太好或者可以继续完善吗?** (类似第一个问题,都是问面试官个人对于公司的看法。)
+3. **我觉得我这次表现的不是太好,你有什么建议或者评价给我吗?**(这个是我常问的。我觉得说自己表现不好只是这个语境需要这样来说,这样可以显的你比较谦虚好学上进。)
+4. **接下来我会有一段空档期,有什么值得注意或者建议学习的吗?** (体现出你对工作比较上心,自助学习意识比较强。)
+5. **这个岗位为什么还在招人?** (岗位真实性和价值咨询)
+6. **大概什么时候能给我回复呢?** (终面的时候,如果面试官没有说的话,可以问一下)
+7. ......
+
+
+
+#### 面对部门领导
+
+1. **部门的主要人员分配以及对应的主要工作能简单介绍一下吗?**
+2. **未来如果我要加入这个团队,你对我的期望是什么?** (部门领导一般情况下是你的直属上级了,你以后和他打交道的机会应该是最多的。你问这个问题,会让他感觉你是一个对他的部门比较上心,比较有团体意识,并且愿意倾听的候选人。)
+3. **公司对新入职的员工的培养机制是什么样的呢?** (正规的公司一般都有培养机制,提前问一下是对你自己的负责也会显的你比较上心)
+4. **以您来看,这个岗位未来在公司内部的发展如何?** (在我看来,问这个问题也是对你自己的负责吧,谁不想发展前景更好的岗位呢?)
+5. **团队现在面临的最大挑战是什么?** (这样的问题不会暴露你对公司的不了解,并且也能让你对未来工作的挑战或困难有一个提前的预期。)
+
+
+
+#### 面对Level比较高的(比如总裁,老板)
+
+1. **贵公司的发展目标和方向是什么?** (看下公司的发展是否满足自己的期望)
+2. **与同行业的竞争者相比,贵公司的核心竞争优势在什么地方?** (充分了解自己的优势和劣势)
+3. **公司现在面临的最大挑战是什么?**
+
+### 来个补充,顺便送个祝福给大家
+
+薪酬待遇和相关福利问题一般在终面的时候(最好不要在前面几面的时候就问到这个问题),面试官会提出来或者在面试完之后以邮件的形式告知你。一般来说,如果面试官很愿意为你回答问题,对你的问题也比较上心的话,那他肯定是觉得你就是他们要招的人。
+
+大家在面试的时候,可以根据自己对于公司或者岗位的了解程度,对上面提到的问题进行适当修饰或者修改。上面提到的一些问题只是给没有经验的朋友一个参考,如果你还有其他比较好的问题的话,那当然也更好啦!
+
+金三银四。过了二月就到了面试高峰期或者说是黄金期。几份惊喜几份愁,愿各位能始终不忘初心!每个人都有每个人的难处。引用一句《阿甘正传》里面的台词:“生活就像一盒巧克力,你永远不知道下一块是什么味道“。
+
+
\ No newline at end of file
diff --git "a/docs/essential-content-for-interview/PreparingForInterview/\347\250\213\345\272\217\345\221\230\347\232\204\347\256\200\345\216\206\344\271\213\351\201\223.md" "b/docs/essential-content-for-interview/PreparingForInterview/\347\250\213\345\272\217\345\221\230\347\232\204\347\256\200\345\216\206\344\271\213\351\201\223.md"
new file mode 100644
index 00000000000..f0627de96e2
--- /dev/null
+++ "b/docs/essential-content-for-interview/PreparingForInterview/\347\250\213\345\272\217\345\221\230\347\232\204\347\256\200\345\216\206\344\271\213\351\201\223.md"
@@ -0,0 +1,121 @@
+
+
+- [程序员简历就该这样写](#程序员简历就该这样写)
+ - [为什么说简历很重要?](#为什么说简历很重要)
+ - [先从面试前来说](#先从面试前来说)
+ - [再从面试中来说](#再从面试中来说)
+ - [下面这几点你必须知道](#下面这几点你必须知道)
+ - [必须了解的两大法则](#必须了解的两大法则)
+ - [STAR法则(Situation Task Action Result)](#star法则situation-task-action-result)
+ - [FAB 法则(Feature Advantage Benefit)](#fab-法则feature-advantage-benefit)
+ - [项目经历怎么写?](#项目经历怎么写)
+ - [专业技能该怎么写?](#专业技能该怎么写)
+ - [排版注意事项](#排版注意事项)
+ - [其他的一些小tips](#其他的一些小tips)
+ - [推荐的工具/网站](#推荐的工具网站)
+
+
+
+# 程序员简历就该这样写
+
+本篇文章除了教大家用Markdown如何写一份程序员专属的简历,后面还会给大家推荐一些不错的用来写Markdown简历的软件或者网站,以及如何优雅的将Markdown格式转变为PDF格式或者其他格式。
+
+推荐大家使用Markdown语法写简历,然后再将Markdown格式转换为PDF格式后进行简历投递。
+
+如果你对Markdown语法不太了解的话,可以花半个小时简单看一下Markdown语法说明: http://www.markdown.cn 。
+
+## 为什么说简历很重要?
+
+一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情况下,写出一份好的简历也是一项很棒的能力。为什么说简历很重要呢?
+
+### 先从面试前来说
+
+- 假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR就会决定你这一关是Fail还是Pass。
+- 假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。
+
+另外,就算你通过了筛选,后面的面试中,面试官也会根据你的简历来判断你究竟是否值得他花费很多时间去面试。
+
+所以,简历就像是我们的一个门面一样,它在很大程度上决定了你能否进入到下一轮的面试中。
+
+### 再从面试中来说
+
+我发现大家比较喜欢看面经 ,这点无可厚非,但是大部分面经都没告诉你很多问题都是在特定条件下才问的。举个简单的例子:一般情况下你的简历上注明你会的东西才会被问到(Java、数据结构、网络、算法这些基础是每个人必问的),比如写了你会 redis,那面试官就很大概率会问你 redis 的一些问题。比如:redis的常见数据类型及应用场景、redis是单线程为什么还这么快、 redis 和 memcached 的区别、redis 内存淘汰机制等等。
+
+所以,首先,你要明确的一点是:**你不会的东西就不要写在简历上**。另外,**你要考虑你该如何才能让你的亮点在简历中凸显出来**,比如:你在某某项目做了什么事情解决了什么问题(只要有项目就一定有要解决的问题)、你的某一个项目里使用了什么技术后整体性能和并发量提升了很多等等。
+
+面试和工作是两回事,聪明的人会把面试官往自己擅长的领域领,其他人则被面试官牵着鼻子走。虽说面试和工作是两回事,但是你要想要获得自己满意的 offer ,你自身的实力必须要强。
+
+## 下面这几点你必须知道
+
+1. 大部分公司的HR都说我们不看重学历(骗你的!),但是如果你的学校不出众的话,很难在一堆简历中脱颖而出,除非你的简历上有特别的亮点,比如:某某大厂的实习经历、获得了某某大赛的奖等等。
+2. **大部分应届生找工作的硬伤是没有工作经验或实习经历,所以如果你是应届生就不要错过秋招和春招。一旦错过,你后面就极大可能会面临社招,这个时候没有工作经验的你可能就会面临各种碰壁,导致找不到一个好的工作**
+3. **写在简历上的东西一定要慎重,这是面试官大量提问的地方;**
+4. **将自己的项目经历完美的展示出来非常重要。**
+
+## 必须了解的两大法则
+
+### STAR法则(Situation Task Action Result)
+
+- **Situation:** 事情是在什么情况下发生;
+- **Task::** 你是如何明确你的任务的;
+- **Action:** 针对这样的情况分析,你采用了什么行动方式;
+- **Result:** 结果怎样,在这样的情况下你学习到了什么。
+
+简而言之,STAR法则,就是一种讲述自己故事的方式,或者说,是一个清晰、条理的作文模板。不管是什么,合理熟练运用此法则,可以轻松的对面试官描述事物的逻辑方式,表现出自己分析阐述问题的清晰性、条理性和逻辑性。
+
+### FAB 法则(Feature Advantage Benefit)
+
+- **Feature:** 是什么;
+- **Advantage:** 比别人好在哪些地方;
+- **Benefit:** 如果雇佣你,招聘方会得到什么好处。
+
+简单来说,这个法则主要是让你的面试官知道你的优势、招了你之后对公司有什么帮助。
+
+## 项目经历怎么写?
+
+简历上有一两个项目经历很正常,但是真正能把项目经历很好的展示给面试官的非常少。对于项目经历大家可以考虑从如下几点来写:
+
+1. 对项目整体设计的一个感受
+2. 在这个项目中你负责了什么、做了什么、担任了什么角色
+3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
+4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+
+## 专业技能该怎么写?
+
+先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几天时间学习一下,然后在简历上可以写上自己了解这个技能。比如你可以这样写(下面这部分内容摘自我的简历,大家可以根据自己的情况做一些修改和完善):
+
+- 计算机网络、数据结构、算法、操作系统等课内基础知识:掌握
+- Java 基础知识:掌握
+- JVM 虚拟机(Java内存区域、虚拟机垃圾算法、虚拟垃圾收集器、JVM内存管理):掌握
+- 高并发、高可用、高性能系统开发:掌握
+- Struts2、Spring、Hibernate、Ajax、Mybatis、JQuery :掌握
+- SSH 整合、SSM 整合、 SOA 架构:掌握
+- Dubbo: 掌握
+- Zookeeper: 掌握
+- 常见消息队列: 掌握
+- Linux:掌握
+- MySQL常见优化手段:掌握
+- Spring Boot +Spring Cloud +Docker:了解
+- Hadoop 生态相关技术中的 HDFS、Storm、MapReduce、Hive、Hbase :了解
+- Python 基础、一些常见第三方库比如OpenCV、wxpy、wordcloud、matplotlib:熟悉
+
+## 排版注意事项
+
+1. 尽量简洁,不要太花里胡哨;
+2. 一些技术名词不要弄错了大小写比如MySQL不要写成mysql,Java不要写成Java。这个在我看来还是比较忌讳的,所以一定要注意这个细节;
+3. 中文和数字英文之间加上空格的话看起来会舒服一点;
+
+## 其他的一些小tips
+
+1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。
+2. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。
+3. 如果自己的Github比较活跃的话,写上去也会为你加分很多。
+4. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容
+5. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。
+6. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。
+7. 简历最后最好能加上:“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的你会很有礼貌。
+
+## 推荐的工具/网站
+
+- 冷熊简历(MarkDown在线简历工具,可在线预览、编辑和生成PDF):
+- Typora+[Java程序员简历模板](https://github.com/geekcompany/ResumeSample/blob/master/java.md)
diff --git "a/docs/essential-content-for-interview/PreparingForInterview/\347\276\216\345\233\242\351\235\242\350\257\225\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md" "b/docs/essential-content-for-interview/PreparingForInterview/\347\276\216\345\233\242\351\235\242\350\257\225\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md"
new file mode 100644
index 00000000000..46996cdb3e9
--- /dev/null
+++ "b/docs/essential-content-for-interview/PreparingForInterview/\347\276\216\345\233\242\351\235\242\350\257\225\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md"
@@ -0,0 +1,950 @@
+
+
+- [一 基础篇](#一-基础篇)
+ - [1. `System.out.println(3|9)`输出什么?](#1-systemoutprintln39输出什么)
+ - [2. 说一下转发\(Forward\)和重定向\(Redirect\)的区别](#2-说一下转发forward和重定向redirect的区别)
+ - [3. 在浏览器中输入url地址到显示主页的过程,整个过程会使用哪些协议](#3-在浏览器中输入url地址到显示主页的过程整个过程会使用哪些协议)
+ - [4. TCP 三次握手和四次挥手](#4-tcp-三次握手和四次挥手)
+ - [为什么要三次握手](#为什么要三次握手)
+ - [为什么要传回 SYN](#为什么要传回-syn)
+ - [传了 SYN,为啥还要传 ACK](#传了-syn为啥还要传-ack)
+ - [为什么要四次挥手](#为什么要四次挥手)
+ - [5. IP地址与MAC地址的区别](#5-ip地址与mac地址的区别)
+ - [6. HTTP请求,响应报文格式](#6-http请求响应报文格式)
+ - [7. 为什么要使用索引?索引这么多优点,为什么不对表中的每一个列创建一个索引呢?索引是如何提高查询速度的?说一下使用索引的注意事项?Mysql索引主要使用的两种数据结构?什么是覆盖索引?](#7-为什么要使用索引索引这么多优点为什么不对表中的每一个列创建一个索引呢索引是如何提高查询速度的说一下使用索引的注意事项mysql索引主要使用的两种数据结构什么是覆盖索引)
+ - [8. 进程与线程的区别是什么?进程间的几种通信方式说一下?线程间的几种通信方式知道不?](#8-进程与线程的区别是什么进程间的几种通信方式说一下线程间的几种通信方式知道不)
+ - [9. 为什么要用单例模式?手写几种线程安全的单例模式?](#9-为什么要用单例模式手写几种线程安全的单例模式)
+ - [10. 简单介绍一下bean;知道Spring的bean的作用域与生命周期吗?](#10-简单介绍一下bean知道spring的bean的作用域与生命周期吗)
+ - [11. Spring 中的事务传播行为了解吗?TransactionDefinition 接口中哪五个表示隔离级别的常量?](#11-spring-中的事务传播行为了解吗transactiondefinition-接口中哪五个表示隔离级别的常量)
+ - [事务传播行为](#事务传播行为)
+ - [隔离级别](#隔离级别)
+ - [12. SpringMVC 原理了解吗?](#12-springmvc-原理了解吗)
+ - [13. Spring AOP IOC 实现原理](#13-spring-aop-ioc-实现原理)
+- [二 进阶篇](#二-进阶篇)
+ - [1 消息队列MQ的套路](#1-消息队列mq的套路)
+ - [1.1 介绍一下消息队列MQ的应用场景/使用消息队列的好处](#11-介绍一下消息队列mq的应用场景使用消息队列的好处)
+ - [1)通过异步处理提高系统性能](#1通过异步处理提高系统性能)
+ - [2)降低系统耦合性](#2降低系统耦合性)
+ - [1.2 那么使用消息队列会带来什么问题?考虑过这些问题吗?](#12-那么使用消息队列会带来什么问题考虑过这些问题吗)
+ - [1.3 介绍一下你知道哪几种消息队列,该如何选择呢?](#13-介绍一下你知道哪几种消息队列该如何选择呢)
+ - [1.4 关于消息队列其他一些常见的问题展望](#14-关于消息队列其他一些常见的问题展望)
+ - [2 谈谈 InnoDB 和 MyIsam 两者的区别](#2-谈谈-innodb-和-myisam-两者的区别)
+ - [2.1 两者的对比](#21-两者的对比)
+ - [2.2 关于两者的总结](#22-关于两者的总结)
+ - [3 聊聊 Java 中的集合吧!](#3-聊聊-java-中的集合吧)
+ - [3.1 Arraylist 与 LinkedList 有什么不同?\(注意加上从数据结构分析的内容\)](#31-arraylist-与-linkedlist-有什么不同注意加上从数据结构分析的内容)
+ - [3.2 HashMap的底层实现](#32-hashmap的底层实现)
+ - [1)JDK1.8之前](#1jdk18之前)
+ - [2)JDK1.8之后](#2jdk18之后)
+ - [3.3 既然谈到了红黑树,你给我手绘一个出来吧,然后简单讲一下自己对于红黑树的理解](#33-既然谈到了红黑树你给我手绘一个出来吧然后简单讲一下自己对于红黑树的理解)
+ - [3.4 红黑树这么优秀,为何不直接使用红黑树得了?](#34-红黑树这么优秀为何不直接使用红黑树得了)
+ - [3.5 HashMap 和 Hashtable 的区别/HashSet 和 HashMap 区别](#35-hashmap-和-hashtable-的区别hashset-和-hashmap-区别)
+- [三 终结篇](#三-终结篇)
+ - [1. Object类有哪些方法?](#1-object类有哪些方法)
+ - [1.1 Object类的常见方法总结](#11-object类的常见方法总结)
+ - [1.2 hashCode与equals](#12-hashcode与equals)
+ - [1.2.1 hashCode\(\)介绍](#121-hashcode介绍)
+ - [1.2.2 为什么要有hashCode](#122-为什么要有hashcode)
+ - [1.2.3 hashCode\(\)与equals\(\)的相关规定](#123-hashcode与equals的相关规定)
+ - [1.2.4 为什么两个对象有相同的hashcode值,它们也不一定是相等的?](#124-为什么两个对象有相同的hashcode值它们也不一定是相等的)
+ - [1.3 ==与equals](#13-与equals)
+ - [2 ConcurrentHashMap 相关问题](#2-concurrenthashmap-相关问题)
+ - [2.1 ConcurrentHashMap 和 Hashtable 的区别](#21-concurrenthashmap-和-hashtable-的区别)
+ - [2.2 ConcurrentHashMap线程安全的具体实现方式/底层具体实现](#22-concurrenthashmap线程安全的具体实现方式底层具体实现)
+ - [JDK1.7\(上面有示意图\)](#jdk17上面有示意图)
+ - [JDK1.8\(上面有示意图\)](#jdk18上面有示意图)
+ - [3 谈谈 synchronized 和 ReenTrantLock 的区别](#3-谈谈-synchronized-和-reentrantlock-的区别)
+ - [4 线程池了解吗?](#4-线程池了解吗)
+ - [4.1 为什么要用线程池?](#41-为什么要用线程池)
+ - [4.2 Java 提供了哪几种线程池?他们各自的使用场景是什么?](#42-java-提供了哪几种线程池他们各自的使用场景是什么)
+ - [Java 主要提供了下面4种线程池](#java-主要提供了下面4种线程池)
+ - [各种线程池的适用场景介绍](#各种线程池的适用场景介绍)
+ - [4.3 创建的线程池的方式](#43-创建的线程池的方式)
+ - [5 Nginx](#5-nginx)
+ - [5.1 简单介绍一下Nginx](#51-简单介绍一下nginx)
+ - [反向代理](#反向代理)
+ - [负载均衡](#负载均衡)
+ - [动静分离](#动静分离)
+ - [5.2 为什么要用 Nginx?](#52-为什么要用-nginx)
+ - [5.3 Nginx 的四个主要组成部分了解吗?](#53-nginx-的四个主要组成部分了解吗)
+
+
+
+
+这些问题是2018年去美团面试的同学被问到的一些常见的问题,希望对你有帮助!
+
+# 一 基础篇
+
+
+## 1. `System.out.println(3|9)`输出什么?
+
+正确答案:11。
+
+**考察知识点:&和&&;|和||**
+
+**&和&&:**
+
+共同点:两者都可做逻辑运算符。它们都表示运算符的两边都是true时,结果为true;
+
+不同点: &也是位运算符。& 表示在运算时两边都会计算,然后再判断;&&表示先运算符号左边的东西,然后判断是否为true,是true就继续运算右边的然后判断并输出,是false就停下来直接输出不会再运行后面的东西。
+
+**|和||:**
+
+共同点:两者都可做逻辑运算符。它们都表示运算符的两边任意一边为true,结果为true,两边都不是true,结果就为false;
+
+不同点:|也是位运算符。| 表示两边都会运算,然后再判断结果;|| 表示先运算符号左边的东西,然后判断是否为true,是true就停下来直接输出不会再运行后面的东西,是false就继续运算右边的然后判断并输出。
+
+**回到本题:**
+
+3 | 9=0011(二进制) | 1001(二进制)=1011(二进制)=11(十进制)
+
+## 2. 说一下转发(Forward)和重定向(Redirect)的区别
+
+**转发是服务器行为,重定向是客户端行为。**
+
+**转发(Forword)** 通过RequestDispatcher对象的`forward(HttpServletRequest request,HttpServletResponse response)`方法实现的。`RequestDispatcher` 可以通过`HttpServletRequest` 的 `getRequestDispatcher()`方法获得。例如下面的代码就是跳转到 login_success.jsp 页面。
+
+```java
+request.getRequestDispatcher("login_success.jsp").forward(request, response);
+```
+
+**重定向(Redirect)** 是利用服务器返回的状态吗来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过HttpServletRequestResponse的setStatus(int status)方法设置状态码。如果服务器返回301或者302,则浏览器会到新的网址重新请求该资源。
+
+1. **从地址栏显示来说**:forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址。所以地址栏显示的是新的URL。
+2. **从数据共享来说**:forward:转发页面和转发到的页面可以共享request里面的数据。redirect:不能共享数据。
+3. **从运用地方来说**:forward:一般用于用户登陆的时候,根据角色转发到相应的模块。redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等。
+4. **从效率来说**:forward:高。redirect:低。
+
+
+## 3. 在浏览器中输入url地址到显示主页的过程,整个过程会使用哪些协议
+
+图片来源:《图解HTTP》:
+
+
+
+总体来说分为以下几个过程:
+
+1. DNS解析
+2. TCP连接
+3. 发送HTTP请求
+4. 服务器处理请求并返回HTTP报文
+5. 浏览器解析渲染页面
+6. 连接结束
+
+具体可以参考下面这篇文章:
+
+- [https://segmentfault.com/a/1190000006879700](https://segmentfault.com/a/1190000006879700)
+
+## 4. TCP 三次握手和四次挥手
+
+为了准确无误地把数据送达目标处,TCP协议采用了三次握手策略。
+
+**漫画图解:**
+
+图片来源:《图解HTTP》
+
+
+**简单示意图:**
+
+
+- 客户端–发送带有 SYN 标志的数据包–一次握手–服务端
+- 服务端–发送带有 SYN/ACK 标志的数据包–二次握手–客户端
+- 客户端–发送带有带有 ACK 标志的数据包–三次握手–服务端
+
+#### 为什么要三次握手
+
+**三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。**
+
+第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常。
+
+第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己接收正常,对方发送正常
+
+第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
+
+所以三次握手就能确认双发收发功能都正常,缺一不可。
+
+#### 为什么要传回 SYN
+接收端传回发送端所发送的 SYN 是为了告诉发送端,我接收到的信息确实就是你所发送的信号了。
+
+> SYN 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务器使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement[汉译:确认字符 ,在数据通信传输中,接收站发给发送站的一种传输控制字符。它表示确认发来的数据已经接受无误。 ])消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。
+
+
+#### 传了 SYN,为啥还要传 ACK
+
+双方通信无误必须是两者互相发送信息都无误。传了 SYN,证明发送方(主动关闭方)到接收方(被动关闭方)的通道没有问题,但是接收方到发送方的通道还需要 ACK 信号来进行验证。
+
+
+
+断开一个 TCP 连接则需要“四次挥手”:
+
+- 客户端-发送一个 FIN,用来关闭客户端到服务器的数据传送
+- 服务器-收到这个 FIN,它发回一 个 ACK,确认序号为收到的序号加1 。和 SYN 一样,一个 FIN 将占用一个序号
+- 服务器-关闭与客户端的连接,发送一个FIN给客户端
+- 客户端-发回 ACK 报文确认,并将确认序号设置为收到序号加1
+
+
+#### 为什么要四次挥手
+
+任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。
+
+举个例子:A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。
+
+上面讲的比较概括,推荐一篇讲的比较细致的文章:[https://blog.csdn.net/qzcsu/article/details/72861891](https://blog.csdn.net/qzcsu/article/details/72861891)
+
+
+
+## 5. IP地址与MAC地址的区别
+
+参考:[https://blog.csdn.net/guoweimelon/article/details/50858597](https://blog.csdn.net/guoweimelon/article/details/50858597)
+
+IP地址是指互联网协议地址(Internet Protocol Address)IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。
+
+
+
+MAC 地址又称为物理地址、硬件地址,用来定义网络设备的位置。网卡的物理地址通常是由网卡生产厂家写入网卡的,具有全球唯一性。MAC地址用于在网络中唯一标示一个网卡,一台电脑会有一或多个网卡,每个网卡都需要有一个唯一的MAC地址。
+
+## 6. HTTP请求,响应报文格式
+
+
+
+HTTP请求报文主要由请求行、请求头部、请求正文3部分组成
+
+HTTP响应报文主要由状态行、响应头部、响应正文3部分组成
+
+详细内容可以参考:[https://blog.csdn.net/a19881029/article/details/14002273](https://blog.csdn.net/a19881029/article/details/14002273)
+
+## 7. 为什么要使用索引?索引这么多优点,为什么不对表中的每一个列创建一个索引呢?索引是如何提高查询速度的?说一下使用索引的注意事项?Mysql索引主要使用的两种数据结构?什么是覆盖索引?
+
+**为什么要使用索引?**
+
+1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
+2. 可以大大加快 数据的检索速度(大大减少的检索的数据量), 这也是创建索引的最主要的原因。
+3. 帮助服务器避免排序和临时表
+4. 将随机IO变为顺序IO
+5. 可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
+
+**索引这么多优点,为什么不对表中的每一个列创建一个索引呢?**
+
+1. 当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
+2. 索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。
+3. 创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
+
+**索引是如何提高查询速度的?**
+
+将无序的数据变成相对有序的数据(就像查目录一样)
+
+**说一下使用索引的注意事项**
+
+1. 避免 where 子句中对字段施加函数,这会造成无法命中索引。
+2. 在使用InnoDB时使用与业务无关的自增主键作为主键,即使用逻辑主键,而不要使用业务主键。
+3. 将打算加索引的列设置为 NOT NULL ,否则将导致引擎放弃使用索引而进行全表扫描
+4. 删除长期未使用的索引,不用的索引的存在会造成不必要的性能损耗 MySQL 5.7 可以通过查询 sys 库的 schema_unused_indexes 视图来查询哪些索引从未被使用
+5. 在使用 limit offset 查询缓慢时,可以借助索引来提高性能
+
+**Mysql索引主要使用的哪两种数据结构?**
+
+- 哈希索引:对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
+- BTree索引:Mysql的BTree索引使用的是B树中的B+Tree。但对于主要的两种存储引擎(MyISAM和InnoDB)的实现方式是不同的。
+
+更多关于索引的内容可以查看我的这篇文章:[【思维导图-索引篇】搞定数据库索引就是这么简单](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484486&idx=1&sn=215450f11e042bca8a58eac9f4a97686&chksm=fd985227caefdb3117b8375f150676f5824aa20d1ebfdbcfb93ff06e23e26efbafae6cf6b48e&token=1990180468&lang=zh_CN#rd)
+
+**什么是覆盖索引?**
+
+如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称
+之为“覆盖索引”。我们知道在InnoDB存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再查找一次,这样就会比较慢。覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!
+
+
+## 8. 进程与线程的区别是什么?进程间的几种通信方式说一下?线程间的几种通信方式知道不?
+ **进程与线程的区别是什么?**
+
+线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。另外,也正是因为共享资源,所以线程中执行时一般都要进行同步和互斥。总的来说,进程和线程的主要差别在于它们是不同的操作系统资源管理方式。
+
+**进程间的几种通信方式说一下?**
+
+
+1. **管道(pipe)**:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有血缘关系的进程间使用。进程的血缘关系通常指父子进程关系。管道分为pipe(无名管道)和fifo(命名管道)两种,有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间通信。
+2. **信号量(semophore)**:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它通常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
+3. **消息队列(message queue)**:消息队列是由消息组成的链表,存放在内核中 并由消息队列标识符标识。消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。消息队列与管道通信相比,其优势是对每个消息指定特定的消息类型,接收的时候不需要按照队列次序,而是可以根据自定义条件接收特定类型的消息。
+4. **信号(signal)**:信号是一种比较复杂的通信方式,用于通知接收进程某一事件已经发生。
+5. **共享内存(shared memory)**:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,共享内存是最快的IPC方式,它是针对其他进程间的通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。
+6. **套接字(socket)**:socket,即套接字是一种通信机制,凭借这种机制,客户/服务器(即要进行通信的进程)系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。
+
+**线程间的几种通信方式知道不?**
+
+1、锁机制
+
+- 互斥锁:提供了以排它方式阻止数据结构被并发修改的方法。
+- 读写锁:允许多个线程同时读共享数据,而对写操作互斥。
+- 条件变量:可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。
+
+2、信号量机制:包括无名线程信号量与有名线程信号量
+
+3、信号机制:类似于进程间的信号处理。
+
+线程间通信的主要目的是用于线程同步,所以线程没有象进程通信中用于数据交换的通信机制。
+
+## 9. 为什么要用单例模式?手写几种线程安全的单例模式?
+
+**简单来说使用单例模式可以带来下面几个好处:**
+
+- 对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销;
+- 由于 new 操作的次数减少,因而对系统内存的使用频率也会降低,这将减轻 GC 压力,缩短 GC 停顿时间。
+
+**懒汉式(双重检查加锁版本)**
+
+```java
+public class Singleton {
+
+ //volatile保证,当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确处理uniqueInstance变量
+ private volatile static Singleton uniqueInstance;
+ private Singleton() {
+ }
+ public static Singleton getInstance() {
+ //检查实例,如果不存在,就进入同步代码块
+ if (uniqueInstance == null) {
+ //只有第一次才彻底执行这里的代码
+ synchronized(Singleton.class) {
+ //进入同步代码块后,再检查一次,如果仍是null,才创建实例
+ if (uniqueInstance == null) {
+ uniqueInstance = new Singleton();
+ }
+ }
+ }
+ return uniqueInstance;
+ }
+}
+```
+
+**静态内部类方式**
+
+静态内部实现的单例是懒加载的且线程安全。
+
+只有通过显式调用 getInstance 方法时,才会显式装载 SingletonHolder 类,从而实例化 instance(只有第一次使用这个单例的实例的时候才加载,同时不会有线程安全问题)。
+
+```java
+public class Singleton {
+ private static class SingletonHolder {
+ private static final Singleton INSTANCE = new Singleton();
+ }
+ private Singleton (){}
+ public static final Singleton getInstance() {
+ return SingletonHolder.INSTANCE;
+ }
+}
+```
+
+## 10. 简单介绍一下bean;知道Spring的bean的作用域与生命周期吗?
+
+在 Spring 中,那些组成应用程序的主体及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲,bean 就是由 IOC 容器初始化、装配及管理的对象,除此之外,bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。
+
+Spring中的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢? 例如对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框架之后,每个Action都是单例的,那么对于Spring托管的单例Service Bean,如何保证其安全呢? Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于 JVM,每个 JVM 内只有一个实例。
+
+
+
+Spring的bean的生命周期以及更多内容可以查看:[一文轻松搞懂Spring中bean的作用域与生命周期](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484400&idx=2&sn=7201eb365102fce017f89cb3527fb0bc&chksm=fd985591caefdc872a2fac897288119f94c345e4e12150774f960bf5f816b79e4b9b46be3d7f&token=1990180468&lang=zh_CN#rd)
+
+
+## 11. Spring 中的事务传播行为了解吗?TransactionDefinition 接口中哪五个表示隔离级别的常量?
+
+#### 事务传播行为
+
+事务传播行为(为了解决业务层方法之间互相调用的事务问题):
+当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行。在TransactionDefinition定义中包括了如下几个表示传播行为的常量:
+
+**支持当前事务的情况:**
+
+- TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
+- TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
+- TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
+
+**不支持当前事务的情况:**
+
+- TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
+- TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
+- TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
+
+**其他情况:**
+
+- TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
+
+
+#### 隔离级别
+
+TransactionDefinition 接口中定义了五个表示隔离级别的常量:
+
+- **TransactionDefinition.ISOLATION_DEFAULT:** 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
+- **TransactionDefinition.ISOLATION_READ_UNCOMMITTED:** 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
+- **TransactionDefinition.ISOLATION_READ_COMMITTED:** 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
+- **TransactionDefinition.ISOLATION_REPEATABLE_READ:** 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
+- **TransactionDefinition.ISOLATION_SERIALIZABLE:** 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
+
+## 12. SpringMVC 原理了解吗?
+
+
+
+客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler-> HandlerAdapter 会根据 Handler 来调用真正的处理器处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象->前端控制器 DispatcherServlet 渲染数据(Model)->将得到视图对象返回给用户
+
+关于 SpringMVC 原理更多内容可以查看我的这篇文章:[SpringMVC 工作原理详解](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484496&idx=1&sn=5472ffa687fe4a05f8900d8ee6726de4&chksm=fd985231caefdb27fc75b44ecf76b6f43e4617e0b01b3c040f8b8fab32e51dfa5118eed1d6ad&token=1990180468&lang=zh_CN#rd)
+
+## 13. Spring AOP IOC 实现原理
+
+过了秋招挺长一段时间了,说实话我自己也忘了如何简要概括 Spring AOP IOC 实现原理,就在网上找了一个较为简洁的答案,下面分享给各位。
+
+**IOC:** 控制反转也叫依赖注入。IOC利用java反射机制,AOP利用代理模式。IOC 概念看似很抽象,但是很容易理解。说简单点就是将对象交给容器管理,你只需要在spring配置文件中配置对应的bean以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类。
+
+**AOP:** 面向切面编程。(Aspect-Oriented Programming) 。AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码,属于静态代理。
+
+
+
+# 二 进阶篇
+
+## 1 消息队列MQ的套路
+
+消息队列/消息中间件应该是Java程序员必备的一个技能了,如果你之前没接触过消息队列的话,建议先去百度一下某某消息队列入门,然后花2个小时就差不多可以学会任何一种消息队列的使用了。如果说仅仅学会使用是万万不够的,在实际生产环境还要考虑消息丢失等等情况。关于消息队列面试相关的问题,推荐大家也可以看一下视频《Java工程师面试突击第1季-中华石杉老师》,如果大家没有资源的话,可以在我的公众号“Java面试通关手册”后台回复关键字“1”即可!
+
+### 1.1 介绍一下消息队列MQ的应用场景/使用消息队列的好处
+
+面试官一般会先问你这个问题,预热一下,看你知道消息队列不,一般在第一面的时候面试官可能只会问消息队列MQ的应用场景/使用消息队列的好处、使用消息队列会带来什么问题、消息队列的技术选型这几个问题,不会太深究下去,在后面的第二轮/第三轮技术面试中可能会深入问一下。
+
+**《大型网站技术架构》第四章和第七章均有提到消息队列对应用性能及扩展性的提升。**
+
+#### 1)通过异步处理提高系统性能
+
+如上图,**在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列之后,用户的请求数据发送给消息队列之后立即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。**
+
+通过以上分析我们可以得出**消息队列具有很好的削峰作用的功能**——即**通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。** 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。如下图所示:
+
+因为**用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败**。因此使用消息队列进行异步处理之后,需要**适当修改业务流程进行配合**,比如**用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功**,以免交易纠纷。这就类似我们平时手机订火车票和电影票。
+
+#### 2)降低系统耦合性
+我们知道模块分布式部署以后聚合方式通常有两种:1.**分布式消息队列**和2.**分布式服务**。
+
+> **先来简单说一下分布式服务:**
+
+目前使用比较多的用来构建**SOA(Service Oriented Architecture面向服务体系结构)**的**分布式服务框架**是阿里巴巴开源的**Dubbo**。如果想深入了解Dubbo的可以看我写的关于Dubbo的这一篇文章:**《高性能优秀的服务框架-dubbo介绍》**:[https://juejin.im/post/5acadeb1f265da2375072f9c](https://juejin.im/post/5acadeb1f265da2375072f9c)
+
+> **再来谈我们的分布式消息队列:**
+
+我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。
+
+我们最常见的**事件驱动架构**类似生产者消费者模式,在大型网站中通常用利用消息队列实现事件驱动结构。如下图所示:
+
+**消息队列使利用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。** 从上图可以看到**消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合**,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。**对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计**。
+
+消息接受者对消息进行过滤、处理、包装后,构造成一个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是一系列流程。
+
+**另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息。**
+
+**备注:** 不要认为消息队列只能利用发布-订阅模式工作,只不过在解耦这个特定业务环境下是使用发布-订阅模式的,**比如在我们的ActiveMQ消息队列中还有点对点工作模式**,具体的会在后面的文章给大家详细介绍,这一篇文章主要还是让大家对消息队列有一个更透彻的了解。
+
+> 这个问题一般会在上一个问题问完之后,紧接着被问到。“使用消息队列会带来什么问题?”这个问题要引起重视,一般我们都会考虑使用消息队列会带来的好处而忽略它带来的问题!
+
+### 1.2 那么使用消息队列会带来什么问题?考虑过这些问题吗?
+
+- **系统可用性降低:** 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!
+- **系统复杂性提高:** 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
+- **一致性问题:** 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!
+
+> 了解下面这个问题是为了我们更好的进行技术选型!该部分摘自:《Java工程师面试突击第1季-中华石杉老师》,如果大家没有资源的话,可以在我的公众号“Java面试通关手册”后台回复关键字“1”即可!
+
+### 1.3 介绍一下你知道哪几种消息队列,该如何选择呢?
+
+
+| 特性 | ActiveMQ | RabbitMQ | RocketMQ | Kafaka |
+| :---------------------- | -----------------------------------------------------------: | -----------------------------------------------------------: | -----------------------------------------------------------: | -----------------------------------------------------------: |
+| 单机吞吐量 | 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 | 万级,吞吐量比RocketMQ和Kafka要低了一个数量级 | 10万级,RocketMQ也是可以支撑高吞吐的一种MQ | 10万级别,这是kafka最大的优点,就是吞吐量高。一般配合大数据类的系统来进行实时数据计算、日志采集等场景 |
+| topic数量对吞吐量的影响 | | | topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降这是RocketMQ的一大优势,在同等机器下,可以支撑大量的topic | topic从几十个到几百个的时候,吞吐量会大幅度下降。所以在同等机器下,kafka尽量保证topic数量不要过多。如果要支撑大规模topic,需要增加更多的机器资源 |
+| 可用性 | 高,基于主从架构实现高可用性 | 高,基于主从架构实现高可用性 | 非常高,分布式架构 | 非常高,kafka是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
+| 消息可靠性 | 有较低的概率丢失数据 | | 经过参数优化配置,可以做到0丢失 | 经过参数优化配置,消息可以做到0丢失 |
+| 时效性 | ms级 | 微秒级,这是rabbitmq的一大特点,延迟是最低的 | ms级 | 延迟在ms级以内 |
+| 功能支持 | MQ领域的功能极其完备 | 基于erlang开发,所以并发能力很强,性能极其好,延时很低 | MQ功能较为完善,还是分布式的,扩展性好 | 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准 |
+| 优劣势总结 | 非常成熟,功能强大,在业内大量的公司以及项目中都有应用。偶尔会有较低概率丢失消息,而且现在社区以及国内应用都越来越少,官方社区现在对ActiveMQ 5.x维护越来越少,几个月才发布一个版本而且确实主要是基于解耦和异步来用的,较少在大规模吞吐的场景中使用 | erlang语言开发,性能极其好,延时很低;吞吐量到万级,MQ功能比较完备而且开源提供的管理界面非常棒,用起来很好用。社区相对比较活跃,几乎每个月都发布几个版本分在国内一些互联网公司近几年用rabbitmq也比较多一些但是问题也是显而易见的,RabbitMQ确实吞吐量会低一些,这是因为他做的实现机制比较重。而且erlang开发,国内有几个公司有实力做erlang源码级别的研究和定制?如果说你没这个实力的话,确实偶尔会有一些问题,你很难去看懂源码,你公司对这个东西的掌控很弱,基本职能依赖于开源社区的快速维护和修复bug。而且rabbitmq集群动态扩展会很麻烦,不过这个我觉得还好。其实主要是erlang语言本身带来的问题。很难读源码,很难定制和掌控。 | 接口简单易用,而且毕竟在阿里大规模应用过,有阿里品牌保障。日处理消息上百亿之多,可以做到大规模吞吐,性能也非常好,分布式扩展也很方便,社区维护还可以,可靠性和可用性都是ok的,还可以支撑大规模的topic数量,支持复杂MQ业务场景。而且一个很大的优势在于,阿里出品都是java系的,我们可以自己阅读源码,定制自己公司的MQ,可以掌控。社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准JMS规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ挺好的 | kafka的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时kafka最好是支撑较少的topic数量即可,保证其超高吞吐量。而且kafka唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。 |
+
+> 这部分内容,我这里不给出答案,大家可以自行根据自己学习的消息队列查阅相关内容,我可能会在后面的文章中介绍到这部分内容。另外,下面这些问题在视频《Java工程师面试突击第1季-中华石杉老师》中都有提到,如果大家没有资源的话,可以在我的公众号“Java面试通关手册”后台回复关键字“1”即可!
+
+### 1.4 关于消息队列其他一些常见的问题展望
+
+1. 引入消息队列之后如何保证高可用性?
+2. 如何保证消息不被重复消费呢?
+3. 如何保证消息的可靠性传输(如何处理消息丢失的问题)?
+4. 我该怎么保证从消息队列里拿到的数据按顺序执行?
+5. 如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?
+6. 如果让你来开发一个消息队列中间件,你会怎么设计架构?
+
+
+
+## 2 谈谈 InnoDB 和 MyIsam 两者的区别
+
+### 2.1 两者的对比
+
+1. **count运算上的区别:** 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需要消耗多少资源的。而对于InnoDB来说,则没有这种缓存
+2. **是否支持事务和崩溃后的安全恢复:** MyISAM 强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。但是 InnoDB 提供事务支持,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
+3. **是否支持外键:** MyISAM不支持,而InnoDB支持。
+
+
+### 2.2 关于两者的总结
+
+MyISAM更适合读密集的表,而InnoDB更适合写密集的的表。 在数据库做主从分离的情况下,经常选择MyISAM作为主库的存储引擎。
+
+一般来说,如果需要事务支持,并且有较高的并发读取频率(MyISAM的表锁的粒度太大,所以当该表写并发量较高时,要等待的查询就会很多了),InnoDB是不错的选择。如果你的数据量很大(MyISAM支持压缩特性可以减少磁盘的空间占用),而且不需要支持事务时,MyISAM是最好的选择。
+
+
+## 3 聊聊 Java 中的集合吧!
+
+### 3.1 Arraylist 与 LinkedList 有什么不同?(注意加上从数据结构分析的内容)
+
+- **1. 是否保证线程安全:** ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
+- **2. 底层数据结构:** Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向链表数据结构(注意双向链表和双向循环链表的区别:);
+- **3. 插入和删除是否受元素位置的影响:** ① **ArrayList 采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。** 比如:执行`add(E e) `方法的时候, ArrayList 会默认在将指定的元素追加到此列表的末尾,这种情况时间复杂度就是O(1)。但是如果要在指定位置 i 插入和删除元素的话(`add(int index, E element) `)时间复杂度就为 O(n-i)。因为在进行上述操作的时候集合中第 i 和第 i 个元素之后的(n-i)个元素都要执行向后位/向前移一位的操作。 ② **LinkedList 采用链表存储,所以插入,删除元素时间复杂度不受元素位置的影响,都是近似 O(1) 而数组为近似 O(n) 。**
+- **4. 是否支持快速随机访问:** LinkedList 不支持高效的随机元素访问,而 ArrayList 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index) `方法)。
+- **5. 内存空间占用:** ArrayList的空 间浪费主要体现在在list列表的结尾会预留一定的容量空间,而LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。
+
+**补充内容:RandomAccess接口**
+
+```java
+public interface RandomAccess {
+}
+```
+
+查看源码我们发现实际上 RandomAccess 接口中什么都没有定义。所以,在我看来 RandomAccess 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。
+
+在 binarySearch() 方法中,它要判断传入的 list 是否RamdomAccess的实例,如果是,调用 indexedBinarySearch() 方法,如果不是,那么调用 iteratorBinarySearch() 方法
+
+```java
+ public static
+ int binarySearch(List extends Comparable super T>> list, T key) {
+ if (list instanceof RandomAccess || list.size() Java 中的集合这类问题几乎是面试必问的,问到这类问题的时候,HashMap 又是几乎必问的问题,所以大家一定要引起重视!
+
+### 3.2 HashMap的底层实现
+
+#### 1)JDK1.8之前
+
+JDK1.8 之前 HashMap 底层是 **数组和链表** 结合在一起使用也就是 **链表散列**。**HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 `(n - 1) & hash` 判断当前元素存放的位置(这里的 n 指的时数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。**
+
+**所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。**
+
+**JDK 1.8 HashMap 的 hash 方法源码:**
+
+JDK 1.8 的 hash方法 相比于 JDK 1.7 hash 方法更加简化,但是原理不变。
+
+```java
+ static final int hash(Object key) {
+ int h;
+ // key.hashCode():返回散列值也就是hashcode
+ // ^ :按位异或
+ // >>>:无符号右移,忽略符号位,空位都以0补齐
+ return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
+ }
+```
+对比一下 JDK1.7的 HashMap 的 hash 方法源码.
+
+```java
+static int hash(int h) {
+ // This function ensures that hashCodes that differ only by
+ // constant multiples at each bit position have a bounded
+ // number of collisions (approximately 8 at default load factor).
+
+ h ^= (h >>> 20) ^ (h >>> 12);
+ return h ^ (h >>> 7) ^ (h >>> 4);
+}
+```
+
+相比于 JDK1.8 的 hash 方法 ,JDK 1.7 的 hash 方法的性能会稍差一点点,因为毕竟扰动了 4 次。
+
+所谓 **“拉链法”** 就是:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。
+
+
+
+
+
+
+#### 2)JDK1.8之后
+
+相比于之前的版本, JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
+
+
+
+TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
+
+> 问完 HashMap 的底层原理之后,面试官可能就会紧接着问你 HashMap 底层数据结构相关的问题!
+
+### 3.3 既然谈到了红黑树,你给我手绘一个出来吧,然后简单讲一下自己对于红黑树的理解
+
+
+
+**红黑树特点:**
+
+1. 每个节点非红即黑;
+2. 根节点总是黑色的;
+3. 每个叶子节点都是黑色的空节点(NIL节点);
+4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
+5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)
+
+
+**红黑树的应用:**
+
+TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。
+
+**为什么要用红黑树**
+
+简单来说红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
+
+
+### 3.4 红黑树这么优秀,为何不直接使用红黑树得了?
+
+说一下自己对于这个问题的看法:我们知道红黑树属于(自)平衡二叉树,但是为了保持“平衡”是需要付出代价的,红黑树在插入新数据后可能需要通过左旋,右旋、变色这些操作来保持平衡,这费事啊。你说说我们引入红黑树就是为了查找数据快,如果链表长度很短的话,根本不需要引入红黑树的,你引入之后还要付出代价维持它的平衡。但是链表过长就不一样了。至于为什么选 8 这个值呢?通过概率统计所得,这个值是综合查询成本和新增元素成本得出的最好的一个值。
+
+### 3.5 HashMap 和 Hashtable 的区别/HashSet 和 HashMap 区别
+
+**HashMap 和 Hashtable 的区别**
+
+1. **线程是否安全:** HashMap 是非线程安全的,Hashtable 是线程安全的;Hashtable 内部的方法基本都经过 `synchronized` 修饰。(如果你要保证线程安全的话就使用 ConcurrentHashMap 吧!);
+2. **效率:** 因为线程安全的问题,HashMap 要比 Hashtable 效率高一点。另外,Hashtable 基本被淘汰,不要在代码中使用它;
+3. **对Null key 和Null value的支持:** HashMap 中,null 可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为 null。但是在 Hashtable 中 put 进的键值只要有一个 null,直接抛出 NullPointerException。
+4. **初始容量大小和每次扩充容量大小的不同 :** ①创建时如果不指定容量初始值,Hashtable 默认的初始大小为11,之后每次扩充,容量变为原来的2n+1。HashMap 默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。②创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为2的幂次方大小(HashMap 中的`tableSizeFor()`方法保证,下面给出了源代码)。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。
+5. **底层数据结构:** JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。Hashtable 没有这样的机制。
+
+**HashSet 和 HashMap 区别**
+
+如果你看过 HashSet 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 clone() 方法、writeObject()方法、readObject()方法是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。)
+
+
+
+# 三 终结篇
+
+## 1. Object类有哪些方法?
+
+这个问题,面试中经常出现。我觉得不论是出于应付面试还是说更好地掌握Java这门编程语言,大家都要掌握!
+
+### 1.1 Object类的常见方法总结
+
+Object类是一个特殊的类,是所有类的父类。它主要提供了以下11个方法:
+
+```java
+
+public final native Class> getClass()//native方法,用于返回当前运行时对象的Class对象,使用了final关键字修饰,故不允许子类重写。
+
+public native int hashCode() //native方法,用于返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。
+public boolean equals(Object obj)//用于比较2个对象的内存地址是否相等,String类对该方法进行了重写用户比较字符串的值是否相等。
+
+protected native Object clone() throws CloneNotSupportedException//naitive方法,用于创建并返回当前对象的一份拷贝。一般情况下,对于任何对象 x,表达式 x.clone() != x 为true,x.clone().getClass() == x.getClass() 为true。Object本身没有实现Cloneable接口,所以不重写clone方法并且进行调用的话会发生CloneNotSupportedException异常。
+
+public String toString()//返回类的名字@实例的哈希码的16进制的字符串。建议Object所有的子类都重写这个方法。
+
+public final native void notify()//native方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
+
+public final native void notifyAll()//native方法,并且不能重写。跟notify一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
+
+public final native void wait(long timeout) throws InterruptedException//native方法,并且不能重写。暂停线程的执行。注意:sleep方法没有释放锁,而wait方法释放了锁 。timeout是等待时间。
+
+public final void wait(long timeout, int nanos) throws InterruptedException//多了nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
+
+public final void wait() throws InterruptedException//跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
+
+protected void finalize() throws Throwable { }//实例被垃圾回收器回收的时候触发的操作
+
+```
+
+> 问完上面这个问题之后,面试官很可能紧接着就会问你“hashCode与equals”相关的问题。
+
+### 1.2 hashCode与equals
+
+面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”
+
+#### 1.2.1 hashCode()介绍
+
+hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。另外需要注意的是: Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法通常用来将对象的 内存地址 转换为整数之后返回。
+
+```java
+ public native int hashCode();
+```
+
+散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
+
+#### 1.2.2 为什么要有hashCode
+
+
+**我们以“HashSet如何检查重复”为例子来说明为什么要有hashCode:**
+
+当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head fist java》第二版)。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。
+
+
+#### 1.2.3 hashCode()与equals()的相关规定
+
+1. 如果两个对象相等,则hashcode一定也是相同的
+2. 两个对象相等,对两个对象分别调用equals方法都返回true
+3. 两个对象有相同的hashcode值,它们也不一定是相等的
+4. **因此,equals方法被覆盖过,则hashCode方法也必须被覆盖**
+5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
+
+#### 1.2.4 为什么两个对象有相同的hashcode值,它们也不一定是相等的?
+
+在这里解释一位小伙伴的问题。以下内容摘自《Head Fisrt Java》。
+
+因为hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode)。
+
+我们刚刚也提到了 HashSet,如果 HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。
+
+> ==与equals 的对比也是比较常问的基础问题之一!
+
+### 1.3 ==与equals
+
+**==** : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)
+
+**equals()** : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
+
+- 情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
+- 情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
+
+
+**举个例子:**
+
+```java
+public class test1 {
+ public static void main(String[] args) {
+ String a = new String("ab"); // a 为一个引用
+ String b = new String("ab"); // b为另一个引用,对象的内容一样
+ String aa = "ab"; // 放在常量池中
+ String bb = "ab"; // 从常量池中查找
+ if (aa == bb) // true
+ System.out.println("aa==bb");
+ if (a == b) // false,非同一对象
+ System.out.println("a==b");
+ if (a.equals(b)) // true
+ System.out.println("aEQb");
+ if (42 == 42.0) { // true
+ System.out.println("true");
+ }
+ }
+}
+```
+
+**说明:**
+
+- String中的equals()方法是被重写过的,因为Object的equals()方法是比较的对象的内存地址,而String的equals()方法比较的是对象的值。
+- 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
+
+> 在[【备战春招/秋招系列5】美团面经总结进阶篇 (附详解答案)](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484625&idx=1&sn=9c4fa1f7d4291a5fbd7daa44bac2b012&chksm=fd9852b0caefdba6edcf9a827aa4a17ddc97bf6ad2e5ee6f7e1aa1b443b54444d05d2b76732b&token=723699735&lang=zh_CN#rd) 这篇文章中,我们已经提到了一下关于 HashMap 在面试中常见的问题:HashMap 的底层实现、简单讲一下自己对于红黑树的理解、红黑树这么优秀,为何不直接使用红黑树得了、HashMap 和 Hashtable 的区别/HashSet 和 HashMap 区别。HashMap 和 ConcurrentHashMap 这俩兄弟在一般只要面试中问到集合相关的问题就一定会被问到,所以各位务必引起重视!
+
+## 2 ConcurrentHashMap 相关问题
+
+### 2.1 ConcurrentHashMap 和 Hashtable 的区别
+
+ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。
+
+- **底层数据结构:** JDK1.7的 ConcurrentHashMap 底层采用 **分段的数组+链表** 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 **数组+链表** 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;
+- **实现线程安全的方式(重要):** ① **在JDK1.7的时候,ConcurrentHashMap(分段锁)** 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。(默认分配16个Segment,比Hashtable效率提高16倍。) **到了 JDK1.8 的时候已经摒弃了Segment的概念,而是直接用 Node 数组+链表+红黑树的数据结构来实现,并发控制使用 synchronized 和 CAS 来操作。(JDK1.6以后 对 synchronized锁做了很多优化)** 整个看起来就像是优化过且线程安全的 HashMap,虽然在JDK1.8中还能看到 Segment 的数据结构,但是已经简化了属性,只是为了兼容旧版本;② **Hashtable(同一把锁)**:使用 synchronized 来保证线程安全,效率非常低下。当一个线程访问同步方法时,其他线程也访问同步方法,可能会进入阻塞或轮询状态,如使用 put 添加元素,另一个线程不能使用 put 添加元素,也不能使用 get,竞争会越来越激烈效率越低。
+
+**两者的对比图:**
+
+图片来源:http://www.cnblogs.com/chengxiao/p/6842045.html
+
+Hashtable:
+
+
+JDK1.7的ConcurrentHashMap:
+
+JDK1.8的ConcurrentHashMap(TreeBin: 红黑二叉树节点
+Node: 链表节点):
+
+
+### 2.2 ConcurrentHashMap线程安全的具体实现方式/底层具体实现
+
+#### JDK1.7(上面有示意图)
+
+首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。
+
+**ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成**。
+
+Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。
+
+```java
+static class Segment extends ReentrantLock implements Serializable {
+}
+```
+
+一个 ConcurrentHashMap 里包含一个 Segment 数组。Segment 的结构和HashMap类似,是一种数组和链表结构,一个 Segment 包含一个 HashEntry 数组,每个 HashEntry 是一个链表结构的元素,每个 Segment 守护着一个HashEntry数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得对应的 Segment的锁。
+
+#### JDK1.8(上面有示意图)
+
+ConcurrentHashMap取消了Segment分段锁,采用CAS和synchronized来保证并发安全。数据结构跟HashMap1.8的结构类似,数组+链表/红黑二叉树。
+
+synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。
+
+## 3 谈谈 synchronized 和 ReentrantLock 的区别
+
+**① 两者都是可重入锁**
+
+两者都是可重入锁。“可重入锁”概念是:自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
+
+**② synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API**
+
+synchronized 是依赖于 JVM 实现的,前面我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。ReentrantLock 是 JDK 层面实现的(也就是 API 层面,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。
+
+**③ ReentrantLock 比 synchronized 增加了一些高级功能**
+
+相比synchronized,ReentrantLock增加了一些高级功能。主要来说主要有三点:**①等待可中断;②可实现公平锁;③可实现选择性通知(锁可以绑定多个条件)**
+
+- **ReentrantLock提供了一种能够中断等待锁的线程的机制**,通过 lock.lockInterruptibly() 来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
+- **ReentrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。** ReentrantLock默认情况是非公平的,可以通过 ReentrantLock类的`ReentrantLock(boolean fair)`构造方法来制定是否是公平的。
+- synchronized关键字与wait()和notify/notifyAll()方法相结合可以实现等待/通知机制,ReentrantLock类当然也可以实现,但是需要借助于Condition接口与newCondition() 方法。Condition是JDK1.5之后才有的,它具有很好的灵活性,比如可以实现多路通知功能也就是在一个Lock对象中可以创建多个Condition实例(即对象监视器),**线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。 在使用notify/notifyAll()方法进行通知时,被通知的线程是由 JVM 选择的,用ReentrantLock类结合Condition实例可以实现“选择性通知”** ,这个功能非常重要,而且是Condition接口默认提供的。而synchronized关键字就相当于整个Lock对象中只有一个Condition实例,所有的线程都注册在它一个身上。如果执行notifyAll()方法的话就会通知所有处于等待状态的线程这样会造成很大的效率问题,而Condition实例的signalAll()方法 只会唤醒注册在该Condition实例中的所有等待线程。
+
+如果你想使用上述功能,那么选择ReentrantLock是一个不错的选择。
+
+**④ 两者的性能已经相差无几**
+
+在JDK1.6之前,synchronized 的性能是比 ReentrantLock 差很多。具体表示为:synchronized 关键字吞吐量岁线程数的增加,下降得非常严重。而ReentrantLock 基本保持一个比较稳定的水平。我觉得这也侧面反映了, synchronized 关键字还有非常大的优化余地。后续的技术发展也证明了这一点,我们上面也讲了在 JDK1.6 之后 JVM 团队对 synchronized 关键字做了很多优化。JDK1.6 之后,synchronized 和 ReentrantLock 的性能基本是持平了。所以网上那些说因为性能才选择 ReentrantLock 的文章都是错的!JDK1.6之后,性能已经不是选择synchronized和ReentrantLock的影响因素了!而且虚拟机在未来的性能改进中会更偏向于原生的synchronized,所以还是提倡在synchronized能满足你的需求的情况下,优先考虑使用synchronized关键字来进行同步!优化后的synchronized和ReentrantLock一样,在很多地方都是用到了CAS操作。
+
+
+## 4 线程池了解吗?
+
+
+### 4.1 为什么要用线程池?
+
+线程池提供了一种限制和管理资源(包括执行一个任务)。 每个线程池还维护一些基本统计信息,例如已完成任务的数量。
+
+这里借用《Java并发编程的艺术》提到的来说一下使用线程池的好处:
+
+- **降低资源消耗。** 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
+- **提高响应速度。** 当任务到达时,任务可以不需要的等到线程创建就能立即执行。
+- **提高线程的可管理性。** 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
+
+### 4.2 Java 提供了哪几种线程池?他们各自的使用场景是什么?
+
+#### Java 主要提供了下面4种线程池
+
+- **FixedThreadPool:** 该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
+- **SingleThreadExecutor:** 方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
+- **CachedThreadPool:** 该方法返回一个可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
+- **ScheduledThreadPoolExecutor:** 主要用来在给定的延迟后运行任务,或者定期执行任务。ScheduledThreadPoolExecutor又分为:ScheduledThreadPoolExecutor(包含多个线程)和SingleThreadScheduledExecutor (只包含一个线程)两种。
+
+#### 各种线程池的适用场景介绍
+
+- **FixedThreadPool:** 适用于为了满足资源管理需求,而需要限制当前线程数量的应用场景。它适用于负载比较重的服务器;
+- **SingleThreadExecutor:** 适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景;
+- **CachedThreadPool:** 适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器;
+- **ScheduledThreadPoolExecutor:** 适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程的数量的应用场景;
+- **SingleThreadScheduledExecutor:** 适用于需要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。
+
+### 4.3 创建的线程池的方式
+
+**(1) 使用 Executors 创建**
+
+我们上面刚刚提到了 Java 提供的几种线程池,通过 Executors 工具类我们可以很轻松的创建我们上面说的几种线程池。但是实际上我们一般都不是直接使用Java提供好的线程池,另外在《阿里巴巴Java开发手册》中强制线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 构造函数 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
+
+```java
+Executors 返回线程池对象的弊端如下:
+
+FixedThreadPool 和 SingleThreadExecutor : 允许请求的队列长度为 Integer.MAX_VALUE,可能堆积大量的请求,从而导致OOM。
+CachedThreadPool 和 ScheduledThreadPool : 允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致OOM。
+
+```
+**(2) ThreadPoolExecutor的构造函数创建**
+
+
+我们可以自己直接调用 ThreadPoolExecutor 的构造函数来自己创建线程池。在创建的同时,给 BlockQueue 指定容量就可以了。示例如下:
+
+```java
+private static ExecutorService executor = new ThreadPoolExecutor(13, 13,
+ 60L, TimeUnit.SECONDS,
+ new ArrayBlockingQueue(13));
+```
+
+这种情况下,一旦提交的线程数超过当前可用线程数时,就会抛出java.util.concurrent.RejectedExecutionException,这是因为当前线程池使用的队列是有边界队列,队列已经满了便无法继续处理新的请求。但是异常(Exception)总比发生错误(Error)要好。
+
+**(3) 使用开源类库**
+
+Hollis 大佬之前在他的文章中也提到了:“除了自己定义ThreadPoolExecutor外。还有其他方法。这个时候第一时间就应该想到开源类库,如apache和guava等。”他推荐使用guava提供的ThreadFactoryBuilder来创建线程池。下面是参考他的代码示例:
+
+```java
+public class ExecutorsDemo {
+
+ private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
+ .setNameFormat("demo-pool-%d").build();
+
+ private static ExecutorService pool = new ThreadPoolExecutor(5, 200,
+ 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
+
+ public static void main(String[] args) {
+
+ for (int i = 0; i < Integer.MAX_VALUE; i++) {
+ pool.execute(new SubThread());
+ }
+ }
+}
+```
+
+通过上述方式创建线程时,不仅可以避免OOM的问题,还可以自定义线程名称,更加方便的出错的时候溯源。
+
+## 5 Nginx
+
+### 5.1 简单介绍一下Nginx
+
+Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器。 Nginx 主要提供反向代理、负载均衡、动静分离(静态资源服务)等服务。下面我简单地介绍一下这些名词。
+
+#### 反向代理
+
+谈到反向代理,就不得不提一下正向代理。无论是正向代理,还是反向代理,说到底,就是代理模式的衍生版本罢了
+
+- **正向代理:**某些情况下,代理我们用户去访问服务器,需要用户手动的设置代理服务器的ip和端口号。正向代理比较常见的一个例子就是 VPN 了。
+- **反向代理:** 是用来代理服务器的,代理我们要访问的目标服务器。代理服务器接受请求,然后将请求转发给内部网络的服务器,并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。
+
+通过下面两幅图,大家应该更好理解(图源:http://blog.720ui.com/2016/nginx_action_05_proxy/):
+
+
+
+
+
+所以,简单的理解,就是正向代理是为客户端做代理,代替客户端去访问服务器,而反向代理是为服务器做代理,代替服务器接受客户端请求。
+
+#### 负载均衡
+
+在高并发情况下需要使用,其原理就是将并发请求分摊到多个服务器执行,减轻每台服务器的压力,多台服务器(集群)共同完成工作任务,从而提高了数据的吞吐量。
+
+Nginx支持的weight轮询(默认)、ip_hash、fair、url_hash这四种负载均衡调度算法,感兴趣的可以自行查阅。
+
+负载均衡相比于反向代理更侧重的是将请求分担到多台服务器上去,所以谈论负载均衡只有在提供某服务的服务器大于两台时才有意义。
+
+#### 动静分离
+
+动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路。
+
+### 5.2 为什么要用 Nginx?
+
+> 这部分内容参考极客时间—[Nginx核心知识100讲的内容](https://time.geekbang.org/course/intro/138?code=AycjiiQk6uQRxnVJzBupFkrGkvZlmYELPRsZbWzaAHE=)。
+
+如果面试官问你这个问题,就一定想看你知道 Nginx 服务器的一些优点吗。
+
+Nginx 有以下5个优点:
+
+1. 高并发、高性能(这是其他web服务器不具有的)
+2. 可扩展性好(模块化设计,第三方插件生态圈丰富)
+3. 高可靠性(可以在服务器行持续不间断的运行数年)
+4. 热部署(这个功能对于 Nginx 来说特别重要,热部署指可以在不停止 Nginx服务的情况下升级 Nginx)
+5. BSD许可证(意味着我们可以将源代码下载下来进行修改然后使用自己的版本)
+
+### 5.3 Nginx 的四个主要组成部分了解吗?
+
+> 这部分内容参考极客时间—[Nginx核心知识100讲的内容](https://time.geekbang.org/course/intro/138?code=AycjiiQk6uQRxnVJzBupFkrGkvZlmYELPRsZbWzaAHE=)。
+
+- Nginx 二进制可执行文件:由各模块源码编译出一个文件
+- nginx.conf 配置文件:控制Nginx 行为
+- acess.log 访问日志: 记录每一条HTTP请求信息
+- error.log 错误日志:定位问题
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\347\224\250Markdown\345\206\231\344\270\200\344\273\275\351\253\230\350\264\250\351\207\217\347\232\204\347\256\200\345\216\206.md" "b/docs/essential-content-for-interview/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\347\224\250Markdown\345\206\231\344\270\200\344\273\275\351\253\230\350\264\250\351\207\217\347\232\204\347\256\200\345\216\206.md"
similarity index 100%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\347\224\250Markdown\345\206\231\344\270\200\344\273\275\351\253\230\350\264\250\351\207\217\347\232\204\347\256\200\345\216\206.md"
rename to "docs/essential-content-for-interview/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\347\224\250Markdown\345\206\231\344\270\200\344\273\275\351\253\230\350\264\250\351\207\217\347\232\204\347\256\200\345\216\206.md"
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\347\256\200\345\216\206\346\250\241\346\235\277.md" "b/docs/essential-content-for-interview/\347\256\200\345\216\206\346\250\241\346\235\277.md"
similarity index 100%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\347\256\200\345\216\206\346\250\241\346\235\277.md"
rename to "docs/essential-content-for-interview/\347\256\200\345\216\206\346\250\241\346\235\277.md"
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md" "b/docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
similarity index 100%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
rename to "docs/essential-content-for-interview/\351\235\242\350\257\225\345\277\205\345\244\207\344\271\213\344\271\220\350\247\202\351\224\201\344\270\216\346\202\262\350\247\202\351\224\201.md"
diff --git a/docs/github-trending/2018-12.md b/docs/github-trending/2018-12.md
new file mode 100644
index 00000000000..3637e93ea0c
--- /dev/null
+++ b/docs/github-trending/2018-12.md
@@ -0,0 +1,78 @@
+本文数据统计于 1.1 号凌晨,由 SnailClimb 整理。
+
+### 1. JavaGuide
+
+- **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- **star**: 18.2k
+- **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
+
+### 2. mall
+
+- **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
+- **star**: 3.3k
+- **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
+
+### 3. advanced-java
+
+- **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- **star**: 3.3k
+- **介绍**: 互联网 Java 工程师进阶知识完全扫盲
+
+### 4. matrix
+
+- **Github地址**:[https://github.com/Tencent/matrix](https://github.com/Tencent/matrix)
+- **star**: 2.5k
+- **介绍**: Matrix 是一款微信研发并日常使用的 APM(Application Performance Manage),当前主要运行在 Android 平台上。 Matrix 的目标是建立统一的应用性能接入框架,通过各种性能监控方案,对性能监控项的异常数据进行采集和分析,输出相应的问题分析、定位与优化建议,从而帮助开发者开发出更高质量的应用。
+
+### 5. miaosha
+
+- **Github地址**:[https://github.com/qiurunze123/miaosha](https://github.com/qiurunze123/miaosha)
+- **star**: 2.4k
+- **介绍**: 高并发大流量如何进行秒杀架构,我对这部分知识做了一个系统的整理,写了一套系统。
+
+### 6. arthas
+
+- **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
+- **star**: 8.2k
+- **介绍**: Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。
+
+### 7 spring-boot
+
+- **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
+- **star:** 32.6k
+- **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
+
+ **关于Spring Boot官方的介绍:**
+
+ > 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项目只需要少量的配置即可)
+
+### 8. tutorials
+
+- **Github地址**:[https://github.com/eugenp/tutorials](https://github.com/eugenp/tutorials)
+- **star**: 10k
+- **介绍**: 该项目是一系列小而专注的教程 - 每个教程都涵盖Java生态系统中单一且定义明确的开发领域。 当然,它们的重点是Spring Framework - Spring,Spring Boot和Spring Securiyt。 除了Spring之外,还有以下技术:核心Java,Jackson,HttpClient,Guava。
+
+### 9. qmq
+
+- **Github地址**:[https://github.com/qunarcorp/qmq](https://github.com/qunarcorp/qmq)
+- **star**: 1.1k
+- **介绍**: QMQ是去哪儿网内部广泛使用的消息中间件,自2012年诞生以来在去哪儿网所有业务场景中广泛的应用,包括跟交易息息相关的订单场景; 也包括报价搜索等高吞吐量场景。
+
+
+### 10. symphony
+
+- **Github地址**:[https://github.com/b3log/symphony](https://github.com/b3log/symphony)
+- **star**: 9k
+- **介绍**: 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台。
+
+### 11. incubator-dubbo
+
+- **Github地址**:[https://github.com/apache/incubator-dubbo](https://github.com/apache/incubator-dubbo)
+- **star**: 23.6k
+- **介绍**: 阿里开源的一个基于Java的高性能开源RPC框架。
+
+### 12. apollo
+
+- **Github地址**:[https://github.com/ctripcorp/apollo](https://github.com/ctripcorp/apollo)
+- **star**: 10k
+- **介绍**: Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。
diff --git a/docs/github-trending/2019-1.md b/docs/github-trending/2019-1.md
new file mode 100644
index 00000000000..aa1de92f623
--- /dev/null
+++ b/docs/github-trending/2019-1.md
@@ -0,0 +1,76 @@
+### 1. JavaGuide
+
+- **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- **star**: 22.8k
+- **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
+
+### 2. advanced-java
+
+- **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- **star**: 7.9k
+- **介绍**: 互联网 Java 工程师进阶知识完全扫盲
+
+### 3. fescar
+
+- **Github地址**:[https://github.com/alibaba/fescar](https://github.com/alibaba/fescar)
+- **star**: 4.6k
+- **介绍**: 具有 **高性能** 和 **易用性** 的 **微服务架构** 的 **分布式事务** 的解决方案。(特点:高性能且易于使用,旨在实现简单并快速的事务提交与回滚。
+
+### 4. mall
+
+- **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
+- **star**: 5.6 k
+- **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
+
+### 5. miaosha
+
+- **Github地址**:[https://github.com/qiurunze123/miaosha](https://github.com/qiurunze123/miaosha)
+- **star**: 4.4k
+- **介绍**: 高并发大流量如何进行秒杀架构,我对这部分知识做了一个系统的整理,写了一套系统。
+
+### 6. flink
+
+- **Github地址**:[https://github.com/apache/flink](https://github.com/apache/flink)
+- **star**: 7.1 k
+- **介绍**: Apache Flink是一个开源流处理框架,具有强大的流和批处理功能。
+
+### 7. cim
+
+- **Github地址**:[https://github.com/crossoverJie/cim](https://github.com/crossoverJie/cim)
+- **star**: 1.8 k
+- **介绍**: cim(cross IM) 适用于开发者的即时通讯系统。
+
+### 8. symphony
+
+- **Github地址**:[https://github.com/b3log/symphony](https://github.com/b3log/symphony)
+- **star**: 10k
+- **介绍**: 一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)平台。
+
+### 9. spring-boot
+
+- **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
+- **star:** 32.6k
+- **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
+
+ **关于Spring Boot官方的介绍:**
+
+ > 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项目只需要少量的配置即可)
+
+### 10. arthas
+
+- **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
+- **star**: 9.5k
+- **介绍**: Arthas 是Alibaba开源的Java诊断工具。
+
+**概览:**
+
+当你遇到以下类似问题而束手无策时,`Arthas`可以帮助你解决:
+
+0. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
+1. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
+2. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
+3. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
+4. 是否有一个全局视角来查看系统的运行状况?
+5. 有什么办法可以监控到JVM的实时运行状态?
+
+`Arthas`支持JDK 6+,支持Linux/Mac/Winodws,采用命令行交互模式,同时提供丰富的 `Tab` 自动补全功能,进一步方便进行问题的定位和诊断。
diff --git a/docs/github-trending/2019-2.md b/docs/github-trending/2019-2.md
new file mode 100644
index 00000000000..51d34b32f78
--- /dev/null
+++ b/docs/github-trending/2019-2.md
@@ -0,0 +1,64 @@
+### 1. JavaGuide
+
+- **Github地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- **Star**: 27.2k (4,437 stars this month)
+- **介绍**: 【Java学习+面试指南】 一份涵盖大部分Java程序员所需要掌握的核心知识。
+
+### 2.DoraemonKit
+
+- **Github地址**:
+- **Star**: 5.2k (3,786 stars this month)
+- **介绍**: 简称 "DoKit" 。一款功能齐全的客户端( iOS 、Android )研发助手,你值得拥有。
+
+### 3.advanced-java
+
+- **Github地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- **Star**:11.2k (3,042 stars this month)
+- **介绍**: 互联网 Java 工程师进阶知识完全扫盲。
+
+### 4. spring-boot-examples
+
+- **Github地址**:
+- **star**: 9.6 k (1,764 stars this month)
+- **介绍**: Spring Boot 教程、技术栈示例代码,快速简单上手教程。
+
+### 5. mall
+
+- **Github地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
+- **star**: 7.4 k (1,736 stars this month)
+- **介绍**: mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
+
+### 6. fescar
+
+- **Github地址**:[https://github.com/alibaba/fescar](https://github.com/alibaba/fescar)
+- **star**: 6.0 k (1,308 stars this month)
+- **介绍**: 具有 **高性能** 和 **易用性** 的 **微服务架构** 的 **分布式事务** 的解决方案。(特点:高性能且易于使用,旨在实现简单并快速的事务提交与回滚。)
+
+### 7. h4cker
+
+- **Github地址**:
+- **star**: 2.1 k (1,303 stars this month)
+- **介绍**: 该仓库主要由Omar Santos维护,包括与道德黑客/渗透测试,数字取证和事件响应(DFIR),漏洞研究,漏洞利用开发,逆向工程等相关的资源。
+
+### 8. spring-boot
+
+- **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
+- **star:** 34.8k (1,073 stars this month)
+- **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
+
+ **关于Spring Boot官方的介绍:**
+
+ > 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项目只需要少量的配置即可)
+
+### 9. arthas
+
+- **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
+- **star**: 10.5 k (970 stars this month)
+- **介绍**: Arthas 是Alibaba开源的Java诊断工具。
+
+### 10. tutorials
+
+- **Github地址**:[https://github.com/eugenp/tutorials](https://github.com/eugenp/tutorials)
+- **star**: 12.1 k (789 stars this month)
+- **介绍**: 该项目是一系列小而专注的教程 - 每个教程都涵盖Java生态系统中单一且定义明确的开发领域。 当然,它们的重点是Spring Framework - Spring,Spring Boot和Spring Securiyt。 除了Spring之外,还有以下技术:核心Java,Jackson,HttpClient,Guava。
+
diff --git a/docs/github-trending/2019-3.md b/docs/github-trending/2019-3.md
new file mode 100644
index 00000000000..eaed4a5d483
--- /dev/null
+++ b/docs/github-trending/2019-3.md
@@ -0,0 +1,60 @@
+### 1. JavaGuide
+
+- **Github 地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- **Star**: 32.9k (6,196 stars this month)
+- **介绍**: 【Java 学习+面试指南】 一份涵盖大部分 Java 程序员所需要掌握的核心知识。
+
+### 2.advanced-java
+
+- **Github 地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- **Star**: 15.1k (4,012 stars this month)
+- **介绍**: 互联网 Java 工程师进阶知识完全扫盲。
+
+### 3.spring-boot-examples
+
+- **Github 地址**:[https://github.com/ityouknow/spring-boot-examples](https://github.com/ityouknow/spring-boot-examples)
+- **Star**: 12.8k (3,462 stars this month)
+- **介绍**: Spring Boot 教程、技术栈示例代码,快速简单上手教程。
+
+### 4. mall
+
+- **Github 地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
+- **star**: 9.7 k (2,418 stars this month)
+- **介绍**: mall 项目是一套电商系统,包括前台商城系统及后台管理系统,基于 SpringBoot+MyBatis 实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
+
+### 5. seata
+
+- **Github 地址** : [https://github.com/seata/seata](https://github.com/seata/seata)
+- **star**: 7.2 k (1359 stars this month)
+- **介绍**: Seata 是一种易于使用,高性能,基于 Java 的开源分布式事务解决方案。
+
+### 6. quarkus
+
+- **Github 地址**:[https://github.com/quarkusio/quarkus](https://github.com/quarkusio/quarkus)
+- **star**: 12 k (1,224 stars this month)
+- **介绍**: Quarkus 是为 GraalVM 和 HotSpot 量身定制的 Kubernetes Native Java 框架,由最佳的 Java 库和标准精心打造而成。Quarkus 的目标是使 Java 成为 Kubernetes 和无服务器环境中的领先平台,同时为开发人员提供统一的反应式和命令式编程模型,以优化地满足更广泛的分布式应用程序架构。
+
+### 7. arthas
+
+- **Github 地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
+- **star**: 11.6 k (1,199 stars this month)
+- **介绍**: Arthas 是 Alibaba 开源的 Java 诊断工具。
+
+### 8.DoraemonKit
+
+- **Github 地址**:
+- **Star**: 6.2k (1,177 stars this month)
+- **介绍**: 简称 "DoKit" 。一款功能齐全的客户端( iOS 、Android )研发助手,你值得拥有。
+
+### 9.elasticsearch
+
+- **Github 地址** [https://github.com/elastic/elasticsearch](https://github.com/elastic/elasticsearch)
+- **Star**: 39.7k (1,069 stars this month)
+- **介绍**: 开源,分布式,RESTful 搜索引擎。
+
+### 10. tutorials
+
+- **Github 地址**:[https://github.com/eugenp/tutorials](https://github.com/eugenp/tutorials)
+- **star**: 13 k (998 stars this month)
+- **介绍**: 该项目是一系列小而专注的教程 - 每个教程都涵盖 Java 生态系统中单一且定义明确的开发领域。 当然,它们的重点是 Spring Framework - Spring,Spring Boot 和 Spring Securiyt。 除了 Spring 之外,还有以下技术:核心 Java,Jackson,HttpClient,Guava。
+
diff --git a/docs/github-trending/2019-4.md b/docs/github-trending/2019-4.md
new file mode 100644
index 00000000000..713a76da642
--- /dev/null
+++ b/docs/github-trending/2019-4.md
@@ -0,0 +1,98 @@
+以下涉及到的数据统计与 2019 年 5 月 1 日 12 点,数据来源: 。
+
+下面的内容从 Java 学习文档到最热门的框架再到热门的工具应有尽有,比如下面推荐到的开源项目 Hutool 就是近期比较热门的项目之一,它是 Java 工具包,能够帮助我们简化代码!我觉得下面这些项目对于学习 Java 的朋友还是很有帮助的!
+
+
+### 1. JavaGuide
+
+- **Github 地址**: [https://github.com/Snailclimb/JavaGuide](https://github.com/Snailclimb/JavaGuide)
+- **Star**: 37.9k (5,660 stars this month)
+- **介绍**: 【Java 学习+面试指南】 一份涵盖大部分 Java 程序员所需要掌握的核心知识。
+
+### 2. advanced-java
+
+- **Github 地址**:[https://github.com/doocs/advanced-java](https://github.com/doocs/advanced-java)
+- **Star**: 15.1k (4,654 stars this month)
+- **介绍**: 互联网 Java 工程师进阶知识完全扫盲。
+
+### 3. CS-Notes
+
+- **Github 地址**:
+- **Star**: 59.2k (4,012 stars this month)
+- **介绍**: 技术面试必备基础知识。
+
+### 4. ghidra
+
+- **Github 地址**:
+- **Star**: 15.0k (2,995 stars this month)
+- **介绍**: Ghidra是一个软件逆向工程(SRE)框架。
+
+### 5. mall
+
+- **Github 地址**: [https://github.com/macrozheng/mall](https://github.com/macrozheng/mall)
+- **star**: 11.6 k (2,100 stars this month)
+- **介绍**: mall 项目是一套电商系统,包括前台商城系统及后台管理系统,基于 SpringBoot+MyBatis 实现。 前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。 后台管理系统包含商品管理、订单管理、会员管理、促销管理、运营管理、内容管理、统计报表、财务管理、权限管理、设置等模块。
+
+### 6. ZXBlog
+
+- **Github 地址**:
+- **star**: 2.1 k (2,086 stars this month)
+- **介绍**: 记录各种学习笔记(算法、Java、数据库、并发......)。
+
+### 7.DoraemonKit
+
+- **Github地址**:
+- **Star**: 7.6k (1,541 stars this month)
+- **介绍**: 简称 "DoKit" 。一款功能齐全的客户端( iOS 、Android )研发助手,你值得拥有。
+
+### 8. spring-boot
+
+- **Github地址**: [https://github.com/spring-projects/spring-boot](https://github.com/spring-projects/spring-boot)
+- **star:** 37.3k (1,489 stars this month)
+- **介绍**: 虽然Spring的组件代码是轻量级的,但它的配置却是重量级的(需要大量XML配置),不过Spring Boot 让这一切成为了过去。 另外Spring Cloud也是基于Spring Boot构建的,我个人非常有必要学习一下。
+
+**Spring Boot官方的介绍:**
+
+> 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项目只需要少量的配置即可)
+
+### 9. spring-boot-examples
+
+- **Github 地址**:[https://github.com/ityouknow/spring-boot-examples](https://github.com/ityouknow/spring-boot-examples)
+- **Star**: 12.8k (1,453 stars this month)
+- **介绍**: Spring Boot 教程、技术栈示例代码,快速简单上手教程。
+
+### 10. seata
+
+- **Github 地址** : [https://github.com/seata/seata](https://github.com/seata/seata)
+- **star**: 8.4 k (1441 stars this month)
+- **介绍**: Seata 是一种易于使用,高性能,基于 Java 的开源分布式事务解决方案。
+
+### 11. litemall
+
+- **Github 地址**:[https://github.com/ityouknow/spring-boot-examples](https://github.com/ityouknow/spring-boot-examples)
+- **Star**: 6.0k (1,427 stars this month)
+- **介绍**: 又一个小商城。litemall = Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端 + Vue用户移动端。
+
+### 12. skywalking
+
+- **Github 地址**:
+- **Star**: 8.0k (1,381 stars this month)
+- **介绍**: 针对分布式系统的应用性能监控,尤其是针对微服务、云原生和面向容器的分布式系统架构。
+
+### 13. elasticsearch
+
+- **Github 地址** [https://github.com/elastic/elasticsearch](https://github.com/elastic/elasticsearch)
+- **Star**: 4.0k (1,068stars this month)
+- **介绍**: 开源,分布式,RESTful 搜索引擎。
+
+### 14. arthas
+
+- **Github地址**:[https://github.com/alibaba/arthas](https://github.com/alibaba/arthas)
+- **star**: 12.6 k (1,080 stars this month)
+- **介绍**: Arthas 是Alibaba开源的Java诊断工具。
+
+### 15. hutool
+
+- **Github地址**:
+- **star**: 4.5 k (1,031 stars this month)
+- **介绍**: Hutool是一个Java工具包,也只是一个工具包,它帮助我们简化每一行代码,减少每一个方法,让Java语言也可以“甜甜的”。Hutool最初是我项目中“util”包的一个整理,后来慢慢积累并加入更多非业务相关功能,并广泛学习其它开源项目精髓,经过自己整理修改,最终形成丰富的开源工具集。官网: 。
\ No newline at end of file
diff --git a/docs/github-trending/JavaGithubTrending.md b/docs/github-trending/JavaGithubTrending.md
new file mode 100644
index 00000000000..d43b2060fe9
--- /dev/null
+++ b/docs/github-trending/JavaGithubTrending.md
@@ -0,0 +1,5 @@
+- [2018 年 12 月](https://github.com/Snailclimb/JavaGuide/blob/master/docs/github-trending/2018-12.md)
+- [2019 年 1 月](https://github.com/Snailclimb/JavaGuide/blob/master/docs/github-trending/2019-1.md)
+- [2019 年 2 月](https://github.com/Snailclimb/JavaGuide/blob/master/docs/github-trending/2019-2.md)
+- [2019 年 3 月](https://github.com/Snailclimb/JavaGuide/blob/master/docs/github-trending/2019-3.md)
+- [2019 年 4 月](https://github.com/Snailclimb/JavaGuide/blob/master/docs/github-trending/2019-4.md)
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 00000000000..3d8c75e550b
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,45 @@
+
+
+
+
+ JavaGuide
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/Java\347\233\270\345\205\263/ArrayList-Grow.md" b/docs/java/ArrayList-Grow.md
similarity index 97%
rename from "Java\347\233\270\345\205\263/ArrayList-Grow.md"
rename to docs/java/ArrayList-Grow.md
index 79837e34553..6dd4cc93daf 100644
--- "a/Java\347\233\270\345\205\263/ArrayList-Grow.md"
+++ b/docs/java/ArrayList-Grow.md
@@ -54,7 +54,7 @@
```
-细心的同学一定会发现 :**以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。** 下面在我们分析 ArrayList 扩容时会降到这一点内容!
+细心的同学一定会发现 :**以无参数构造方法创建 ArrayList 时,实际上初始化赋值的是一个空数组。当真正对数组进行添加元素操作时,才真正分配容量。即向数组中添加第一个元素时,数组容量扩为10。** 下面在我们分析 ArrayList 扩容时会讲到这一点内容!
## 二 一步一步分析 ArrayList 扩容机制
@@ -145,7 +145,7 @@
}
```
-**int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍!** 记清楚了!不是网上很多人说的 1.5 倍+1!
+**int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍!(JDK1.6版本以后)** JDk1.6版本时,扩容之后容量为 1.5 倍+1!详情请参考源码
> ">>"(移位运算符):>>1 右移一位相当于除2,右移n位相当于除以 2 的 n 次方。这里 oldCapacity 明显右移了1位所以相当于oldCapacity /2。对于大数据的2进制运算,位移运算符比那些普通运算符的运算要快很多,因为程序仅仅移动一下而已,不去计算,这样提高了效率,节省了资源
@@ -308,7 +308,7 @@ ArrayList 源码中有一个 `ensureCapacity` 方法不知道大家注意到没
```
-**最好在 add 大量元素之前用 `ensureCapacity` 方法,以减少增量从新分配的次数**
+**最好在 add 大量元素之前用 `ensureCapacity` 方法,以减少增量重新分配的次数**
我们通过下面的代码实际测试以下这个方法的效果:
@@ -344,4 +344,4 @@ public class EnsureCapacityTest {
```
-通过运行结果,我们可以很明显的看出向 ArrayList 添加大量元素之前最好先使用`ensureCapacity` 方法,以减少增量从新分配的次数
+通过运行结果,我们可以很明显的看出向 ArrayList 添加大量元素之前最好先使用`ensureCapacity` 方法,以减少增量重新分配的次数
diff --git "a/Java\347\233\270\345\205\263/ArrayList.md" b/docs/java/ArrayList.md
similarity index 96%
rename from "Java\347\233\270\345\205\263/ArrayList.md"
rename to docs/java/ArrayList.md
index d6792edb241..c3e8dd47896 100644
--- "a/Java\347\233\270\345\205\263/ArrayList.md"
+++ b/docs/java/ArrayList.md
@@ -1,4 +1,3 @@
-
- [ArrayList简介](#arraylist简介)
@@ -19,15 +18,15 @@
它继承于 **AbstractList**,实现了 **List**, **RandomAccess**, **Cloneable**, **java.io.Serializable** 这些接口。
在我们学数据结构的时候就知道了线性表的顺序存储,插入删除元素的时间复杂度为**O(n)**,求表长以及增加元素,取第 i 元素的时间复杂度为**O(1)**
-
+
ArrayList 继承了AbstractList,实现了List。它是一个数组队列,提供了相关的添加、删除、修改、遍历等功能。
-
- ArrayList 实现了**RandomAccess 接口**,即提供了随机访问功能。RandomAccess 是 Java 中用来被 List 实现,为 List 提供**快速访问功能**的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
-
+
+ ArrayList 实现了**RandomAccess 接口**, RandomAccess 是一个标志接口,表明实现这个这个接口的 List 集合是支持**快速随机访问**的。在 ArrayList 中,我们即可以通过元素的序号快速获取元素对象,这就是快速随机访问。
+
ArrayList 实现了**Cloneable 接口**,即覆盖了函数 clone(),**能被克隆**。
-
+
ArrayList 实现**java.io.Serializable 接口**,这意味着ArrayList**支持序列化**,**能通过序列化去传输**。
-
+
和 Vector 不同,**ArrayList 中的操作不是线程安全的**!所以,建议在单线程中才使用 ArrayList,而在多线程中可以选择 Vector 或者 CopyOnWriteArrayList。
### ArrayList核心源码
@@ -85,7 +84,7 @@ public class ArrayList extends AbstractList
}
/**
- *默认构造函数,其默认初始容量为10
+ *默认构造函数,DEFAULTCAPACITY_EMPTY_ELEMENTDATA 为0.初始化为10,也就是说初始其实是空数组 当添加第一个元素的时候数组容量才变成10
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
@@ -177,7 +176,7 @@ public class ArrayList extends AbstractList
newCapacity = minCapacity;
//再检查新容量是否超出了ArrayList所定义的最大容量,
//若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,
- //如果minCapacity大于最大容量,则新容量则为ArrayList定义的最大容量,否则,新容量大小则为 minCapacity。
+ //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
@@ -631,7 +630,7 @@ public class ArrayList extends AbstractList
newCapacity = minCapacity;
//再检查新容量是否超出了ArrayList所定义的最大容量,
//若超出了,则调用hugeCapacity()来比较minCapacity和 MAX_ARRAY_SIZE,
- //如果minCapacity大于最大容量,则新容量则为ArrayList定义的最大容量,否则,新容量大小则为 minCapacity。
+ //如果minCapacity大于MAX_ARRAY_SIZE,则新容量则为Interger.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE。
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
@@ -653,15 +652,15 @@ public class ArrayList extends AbstractList
3. .java 中的**size()方法**是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!
-
+
#### 内部类
```java
(1)private class Itr implements Iterator
(2)private class ListItr extends Itr implements ListIterator
(3)private class SubList extends AbstractList implements RandomAccess
(4)static final class ArrayListSpliterator implements Spliterator
-```
- ArrayList有四个内部类,其中的**Itr是实现了Iterator接口**,同时重写了里面的**hasNext()**,**next()**,**remove()**等方法;其中的**ListItr**继承**Itr**,实现了**ListIterator接口**,同时重写了**hasPrevious()**,**nextIndex()**,**previousIndex()**,**previous()**,**set(E e)**,**add(E e)**等方法,所以这也可以看出了**Iterator和ListIterator的区别:**ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。
+```
+ ArrayList有四个内部类,其中的**Itr是实现了Iterator接口**,同时重写了里面的**hasNext()**,**next()**,**remove()**等方法;其中的**ListItr**继承**Itr**,实现了**ListIterator接口**,同时重写了**hasPrevious()**,**nextIndex()**,**previousIndex()**,**previous()**,**set(E e)**,**add(E e)**等方法,所以这也可以看出了 **Iterator和ListIterator的区别:**ListIterator在Iterator的基础上增加了添加对象,修改对象,逆向遍历等方法,这些是Iterator不能实现的。
### ArrayList经典Demo
```java
diff --git a/docs/java/BIO-NIO-AIO.md b/docs/java/BIO-NIO-AIO.md
new file mode 100644
index 00000000000..c5ec6dddd04
--- /dev/null
+++ b/docs/java/BIO-NIO-AIO.md
@@ -0,0 +1,347 @@
+熟练掌握 BIO,NIO,AIO 的基本概念以及一些常见问题是你准备面试的过程中不可或缺的一部分,另外这些知识点也是你学习 Netty 的基础。
+
+
+
+- [BIO,NIO,AIO 总结](#bionioaio-总结)
+ - [1. BIO \(Blocking I/O\)](#1-bio-blocking-io)
+ - [1.1 传统 BIO](#11-传统-bio)
+ - [1.2 伪异步 IO](#12-伪异步-io)
+ - [1.3 代码示例](#13-代码示例)
+ - [1.4 总结](#14-总结)
+ - [2. NIO \(New I/O\)](#2-nio-new-io)
+ - [2.1 NIO 简介](#21-nio-简介)
+ - [2.2 NIO的特性/NIO与IO区别](#22-nio的特性nio与io区别)
+ - [1)Non-blocking IO(非阻塞IO)](#1non-blocking-io(非阻塞io))
+ - [2)Buffer\(缓冲区\)](#2buffer缓冲区)
+ - [3)Channel \(通道\)](#3channel-通道)
+ - [4)Selectors\(选择器\)](#4selectors选择器)
+ - [2.3 NIO 读数据和写数据方式](#23-nio-读数据和写数据方式)
+ - [2.4 NIO核心组件简单介绍](#24-nio核心组件简单介绍)
+ - [2.5 代码示例](#25-代码示例)
+ - [3. AIO \(Asynchronous I/O\)](#3-aio-asynchronous-io)
+ - [参考](#参考)
+
+
+
+
+# BIO,NIO,AIO 总结
+
+ Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。
+
+在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞。
+
+**同步与异步**
+
+- **同步:** 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回。
+- **异步:** 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者并没有返回结果,此时我们可以处理其他的请求,被调用者通常依靠事件,回调等机制来通知调用者其返回结果。
+
+同步和异步的区别最大在于异步的话调用者不需要等待处理结果,被调用者会通过回调等机制来通知调用者其返回结果。
+
+**阻塞和非阻塞**
+
+- **阻塞:** 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
+- **非阻塞:** 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
+
+举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在哪里傻等着水开(**同步阻塞**)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(**同步非阻塞**)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(**异步非阻塞**)。
+
+
+## 1. BIO (Blocking I/O)
+
+同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
+
+### 1.1 传统 BIO
+
+BIO通信(一请求一应答)模型图如下(图源网络,原出处不明):
+
+
+
+采用 **BIO 通信模型** 的服务端,通常由一个独立的 Acceptor 线程负责监听客户端的连接。我们一般通过在`while(true)` 循环中服务端会调用 `accept()` 方法等待接收客户端的连接的方式监听请求,请求一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成, 不过可以通过多线程来支持多个客户端的连接,如上图所示。
+
+如果要让 **BIO 通信模型** 能够同时处理多个客户端请求,就必须使用多线程(主要原因是`socket.accept()`、`socket.read()`、`socket.write()` 涉及的三个主要函数都是同步阻塞的),也就是说它在接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的 **一请求一应答通信模型** 。我们可以设想一下如果这个连接不做任何事情的话就会造成不必要的线程开销,不过可以通过 **线程池机制** 改善,线程池还可以让线程的创建和回收成本相对较低。使用`FixedThreadPool` 可以有效的控制了线程的最大数量,保证了系统有限的资源的控制,实现了N(客户端请求数量):M(处理客户端请求的线程数量)的伪异步I/O模型(N 可以远远大于 M),下面一节"伪异步 BIO"中会详细介绍到。
+
+**我们再设想一下当客户端并发访问量增加后这种模型会出现什么问题?**
+
+在 Java 虚拟机中,线程是宝贵的资源,线程的创建和销毁成本很高,除此之外,线程的切换成本也是很高的。尤其在 Linux 这样的操作系统中,线程本质上就是一个进程,创建和销毁线程都是重量级的系统函数。如果并发访问量增加会导致线程数急剧膨胀可能会导致线程堆栈溢出、创建新线程失败等问题,最终导致进程宕机或者僵死,不能对外提供服务。
+
+### 1.2 伪异步 IO
+
+为了解决同步阻塞I/O面临的一个链路需要一个线程处理的问题,后来有人对它的线程模型进行了优化一一一后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远远大于N.通过线程池可以灵活地调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
+
+伪异步IO模型图(图源网络,原出处不明):
+
+
+
+采用线程池和任务队列可以实现一种叫做伪异步的 I/O 通信框架,它的模型图如上图所示。当有新的客户端接入时,将客户端的 Socket 封装成一个Task(该任务实现java.lang.Runnable接口)投递到后端的线程池中进行处理,JDK 的线程池维护一个消息队列和 N 个活跃线程,对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。
+
+伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。不过因为它的底层任然是同步阻塞的BIO模型,因此无法从根本上解决问题。
+
+### 1.3 代码示例
+
+下面代码中演示了BIO通信(一请求一应答)模型。我们会在客户端创建多个线程依次连接服务端并向其发送"当前时间+:hello world",服务端会为每个客户端线程创建一个线程来处理。代码示例出自闪电侠的博客,原地址如下:
+
+[https://www.jianshu.com/p/a4e03835921a](https://www.jianshu.com/p/a4e03835921a)
+
+**客户端**
+
+```java
+/**
+ *
+ * @author 闪电侠
+ * @date 2018年10月14日
+ * @Description:客户端
+ */
+public class IOClient {
+
+ public static void main(String[] args) {
+ // TODO 创建多个线程,模拟多个客户端连接服务端
+ new Thread(() -> {
+ try {
+ Socket socket = new Socket("127.0.0.1", 3333);
+ while (true) {
+ try {
+ socket.getOutputStream().write((new Date() + ": hello world").getBytes());
+ Thread.sleep(2000);
+ } catch (Exception e) {
+ }
+ }
+ } catch (IOException e) {
+ }
+ }).start();
+
+ }
+
+}
+
+```
+
+**服务端**
+
+```java
+/**
+ * @author 闪电侠
+ * @date 2018年10月14日
+ * @Description: 服务端
+ */
+public class IOServer {
+
+ public static void main(String[] args) throws IOException {
+ // TODO 服务端处理客户端连接请求
+ ServerSocket serverSocket = new ServerSocket(3333);
+
+ // 接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理
+ new Thread(() -> {
+ while (true) {
+ try {
+ // 阻塞方法获取新的连接
+ Socket socket = serverSocket.accept();
+
+ // 每一个新的连接都创建一个线程,负责读取数据
+ new Thread(() -> {
+ try {
+ int len;
+ byte[] data = new byte[1024];
+ InputStream inputStream = socket.getInputStream();
+ // 按字节流方式读取数据
+ while ((len = inputStream.read(data)) != -1) {
+ System.out.println(new String(data, 0, len));
+ }
+ } catch (IOException e) {
+ }
+ }).start();
+
+ } catch (IOException e) {
+ }
+
+ }
+ }).start();
+
+ }
+
+}
+```
+
+### 1.4 总结
+
+在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
+
+
+
+## 2. NIO (New I/O)
+
+### 2.1 NIO 简介
+
+ NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
+
+NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 `Socket` 和 `ServerSocket` 相对应的 `SocketChannel` 和 `ServerSocketChannel` 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
+
+### 2.2 NIO的特性/NIO与IO区别
+
+如果是在面试中回答这个问题,我觉得首先肯定要从 NIO 流是非阻塞 IO 而 IO 流是阻塞 IO 说起。然后,可以从 NIO 的3个核心组件/特性为 NIO 带来的一些改进来分析。如果,你把这些都回答上了我觉得你对于 NIO 就有了更为深入一点的认识,面试官问到你这个问题,你也能很轻松的回答上来了。
+
+#### 1)Non-blocking IO(非阻塞IO)
+
+**IO流是阻塞的,NIO流是不阻塞的。**
+
+Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
+
+Java IO的各种流是阻塞的。这意味着,当一个线程调用 `read()` 或 `write()` 时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
+
+#### 2)Buffer(缓冲区)
+
+**IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。**
+
+Buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I/O中·可以将数据直接写入或者将数据直接读到 Stream 对象中。虽然 Stream 中也有 Buffer 开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而 NIO 却是直接读到 Buffer 中进行操作。
+
+在NIO厍中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
+
+最常用的缓冲区是 ByteBuffer,一个 ByteBuffer 提供了一组功能用于操作 byte 数组。除了ByteBuffer,还有其他的一些缓冲区,事实上,每一种Java基本类型(除了Boolean类型)都对应有一种缓冲区。
+
+#### 3)Channel (通道)
+
+NIO 通过Channel(通道) 进行读写。
+
+通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
+
+#### 4)Selectors(选择器)
+
+NIO有选择器,而IO没有。
+
+选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。
+
+
+
+### 2.3 NIO 读数据和写数据方式
+通常来说NIO中的所有IO都是从 Channel(通道) 开始的。
+
+- 从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
+- 从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。
+
+数据读取和写入操作图示:
+
+
+
+
+### 2.4 NIO核心组件简单介绍
+
+NIO 包含下面几个核心的组件:
+
+- Channel(通道)
+- Buffer(缓冲区)
+- Selector(选择器)
+
+整个NIO体系包含的类远远不止这三个,只能说这三个是NIO体系的“核心API”。我们上面已经对这三个概念进行了基本的阐述,这里就不多做解释了。
+
+### 2.5 代码示例
+
+代码示例出自闪电侠的博客,原地址如下:
+
+[https://www.jianshu.com/p/a4e03835921a](https://www.jianshu.com/p/a4e03835921a)
+
+客户端 IOClient.java 的代码不变,我们对服务端使用 NIO 进行改造。以下代码较多而且逻辑比较复杂,大家看看就好。
+
+```java
+/**
+ *
+ * @author 闪电侠
+ * @date 2019年2月21日
+ * @Description: NIO 改造后的服务端
+ */
+public class NIOServer {
+ public static void main(String[] args) throws IOException {
+ // 1. serverSelector负责轮询是否有新的连接,服务端监测到新的连接之后,不再创建一个新的线程,
+ // 而是直接将新连接绑定到clientSelector上,这样就不用 IO 模型中 1w 个 while 循环在死等
+ Selector serverSelector = Selector.open();
+ // 2. clientSelector负责轮询连接是否有数据可读
+ Selector clientSelector = Selector.open();
+
+ new Thread(() -> {
+ try {
+ // 对应IO编程中服务端启动
+ ServerSocketChannel listenerChannel = ServerSocketChannel.open();
+ listenerChannel.socket().bind(new InetSocketAddress(3333));
+ listenerChannel.configureBlocking(false);
+ listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
+
+ while (true) {
+ // 监测是否有新的连接,这里的1指的是阻塞的时间为 1ms
+ if (serverSelector.select(1) > 0) {
+ Set set = serverSelector.selectedKeys();
+ Iterator keyIterator = set.iterator();
+
+ while (keyIterator.hasNext()) {
+ SelectionKey key = keyIterator.next();
+
+ if (key.isAcceptable()) {
+ try {
+ // (1)
+ // 每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector
+ SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
+ clientChannel.configureBlocking(false);
+ clientChannel.register(clientSelector, SelectionKey.OP_READ);
+ } finally {
+ keyIterator.remove();
+ }
+ }
+
+ }
+ }
+ }
+ } catch (IOException ignored) {
+ }
+ }).start();
+ new Thread(() -> {
+ try {
+ while (true) {
+ // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为 1ms
+ if (clientSelector.select(1) > 0) {
+ Set set = clientSelector.selectedKeys();
+ Iterator keyIterator = set.iterator();
+
+ while (keyIterator.hasNext()) {
+ SelectionKey key = keyIterator.next();
+
+ if (key.isReadable()) {
+ try {
+ SocketChannel clientChannel = (SocketChannel) key.channel();
+ ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
+ // (3) 面向 Buffer
+ clientChannel.read(byteBuffer);
+ byteBuffer.flip();
+ System.out.println(
+ Charset.defaultCharset().newDecoder().decode(byteBuffer).toString());
+ } finally {
+ keyIterator.remove();
+ key.interestOps(SelectionKey.OP_READ);
+ }
+ }
+
+ }
+ }
+ }
+ } catch (IOException ignored) {
+ }
+ }).start();
+
+ }
+}
+```
+
+为什么大家都不愿意用 JDK 原生 NIO 进行开发呢?从上面的代码中大家都可以看出来,是真的难用!除了编程复杂、编程模型难之外,它还有以下让人诟病的问题:
+
+- JDK 的 NIO 底层由 epoll 实现,该实现饱受诟病的空轮询 bug 会导致 cpu 飙升 100%
+- 项目庞大之后,自行实现的 NIO 很容易出现各类 bug,维护成本较高,上面这一坨代码我都不能保证没有 bug
+
+Netty 的出现很大程度上改善了 JDK 原生 NIO 所存在的一些让人难以忍受的问题。
+
+### 3. AIO (Asynchronous I/O)
+
+AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
+
+AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。(除了 AIO 其他的 IO 类型都是同步的,这一点可以从底层IO线程模型解释,推荐一篇文章:[《漫话:如何给女朋友解释什么是Linux的五种IO模型?》](https://mp.weixin.qq.com/s?__biz=Mzg3MjA4MTExMw==&mid=2247484746&idx=1&sn=c0a7f9129d780786cabfcac0a8aa6bb7&source=41#wechat_redirect) )
+
+查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。
+
+## 参考
+
+- 《Netty 权威指南》第二版
+- https://zhuanlan.zhihu.com/p/23488863 (美团技术团队)
diff --git a/docs/java/Basis/Arrays,CollectionsCommonMethods.md b/docs/java/Basis/Arrays,CollectionsCommonMethods.md
new file mode 100644
index 00000000000..0710de44a95
--- /dev/null
+++ b/docs/java/Basis/Arrays,CollectionsCommonMethods.md
@@ -0,0 +1,383 @@
+
+
+- [Collections 工具类和 Arrays 工具类常见方法](#collections-工具类和-arrays-工具类常见方法)
+ - [Collections](#collections)
+ - [排序操作](#排序操作)
+ - [查找,替换操作](#查找替换操作)
+ - [同步控制](#同步控制)
+ - [Arrays类的常见操作](#arrays类的常见操作)
+ - [排序 : `sort()`](#排序--sort)
+ - [查找 : `binarySearch()`](#查找--binarysearch)
+ - [比较: `equals()`](#比较-equals)
+ - [填充 : `fill()`](#填充--fill)
+ - [转列表 `asList()`](#转列表-aslist)
+ - [转字符串 `toString()`](#转字符串-tostring)
+ - [复制 `copyOf()`](#复制-copyof)
+
+
+# Collections 工具类和 Arrays 工具类常见方法
+
+## Collections
+
+Collections 工具类常用方法:
+
+1. 排序
+2. 查找,替换操作
+3. 同步控制(不推荐,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合)
+
+### 排序操作
+
+```java
+void reverse(List list)//反转
+void shuffle(List list)//随机排序
+void sort(List list)//按自然排序的升序排序
+void sort(List list, Comparator c)//定制排序,由Comparator控制排序逻辑
+void swap(List list, int i , int j)//交换两个索引位置的元素
+void rotate(List list, int distance)//旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面。
+```
+
+**示例代码:**
+
+```java
+ ArrayList arrayList = new ArrayList();
+ arrayList.add(-1);
+ arrayList.add(3);
+ arrayList.add(3);
+ arrayList.add(-5);
+ arrayList.add(7);
+ arrayList.add(4);
+ arrayList.add(-9);
+ arrayList.add(-7);
+ System.out.println("原始数组:");
+ System.out.println(arrayList);
+ // void reverse(List list):反转
+ Collections.reverse(arrayList);
+ System.out.println("Collections.reverse(arrayList):");
+ System.out.println(arrayList);
+
+
+ Collections.rotate(arrayList, 4);
+ System.out.println("Collections.rotate(arrayList, 4):");
+ System.out.println(arrayList);
+
+ // void sort(List list),按自然排序的升序排序
+ Collections.sort(arrayList);
+ System.out.println("Collections.sort(arrayList):");
+ System.out.println(arrayList);
+
+ // void shuffle(List list),随机排序
+ Collections.shuffle(arrayList);
+ System.out.println("Collections.shuffle(arrayList):");
+ System.out.println(arrayList);
+
+ // void swap(List list, int i , int j),交换两个索引位置的元素
+ Collections.swap(arrayList, 2, 5);
+ System.out.println("Collections.swap(arrayList, 2, 5):");
+ System.out.println(arrayList);
+
+ // 定制排序的用法
+ Collections.sort(arrayList, new Comparator() {
+
+ @Override
+ public int compare(Integer o1, Integer o2) {
+ return o2.compareTo(o1);
+ }
+ });
+ System.out.println("定制排序后:");
+ System.out.println(arrayList);
+```
+
+### 查找,替换操作
+
+```java
+int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
+int max(Collection coll)//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
+int max(Collection coll, Comparator c)//根据定制排序,返回最大元素,排序规则由Comparatator类控制。类比int min(Collection coll, Comparator c)
+void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素。
+int frequency(Collection c, Object o)//统计元素出现次数
+int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
+boolean replaceAll(List list, Object oldVal, Object newVal), 用新元素替换旧元素
+```
+
+**示例代码:**
+
+```java
+ ArrayList arrayList = new ArrayList();
+ arrayList.add(-1);
+ arrayList.add(3);
+ arrayList.add(3);
+ arrayList.add(-5);
+ arrayList.add(7);
+ arrayList.add(4);
+ arrayList.add(-9);
+ arrayList.add(-7);
+ ArrayList arrayList2 = new ArrayList();
+ arrayList2.add(-3);
+ arrayList2.add(-5);
+ arrayList2.add(7);
+ System.out.println("原始数组:");
+ System.out.println(arrayList);
+
+ System.out.println("Collections.max(arrayList):");
+ System.out.println(Collections.max(arrayList));
+
+ System.out.println("Collections.min(arrayList):");
+ System.out.println(Collections.min(arrayList));
+
+ System.out.println("Collections.replaceAll(arrayList, 3, -3):");
+ Collections.replaceAll(arrayList, 3, -3);
+ System.out.println(arrayList);
+
+ System.out.println("Collections.frequency(arrayList, -3):");
+ System.out.println(Collections.frequency(arrayList, -3));
+
+ System.out.println("Collections.indexOfSubList(arrayList, arrayList2):");
+ System.out.println(Collections.indexOfSubList(arrayList, arrayList2));
+
+ System.out.println("Collections.binarySearch(arrayList, 7):");
+ // 对List进行二分查找,返回索引,List必须是有序的
+ Collections.sort(arrayList);
+ System.out.println(Collections.binarySearch(arrayList, 7));
+```
+
+### 同步控制
+
+Collections提供了多个`synchronizedXxx()`方法·,该方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题。
+
+我们知道 HashSet,TreeSet,ArrayList,LinkedList,HashMap,TreeMap 都是线程不安全的。Collections提供了多个静态方法可以把他们包装成线程同步的集合。
+
+**最好不要用下面这些方法,效率非常低,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合。**
+
+方法如下:
+
+```java
+synchronizedCollection(Collection c) //返回指定 collection 支持的同步(线程安全的)collection。
+synchronizedList(List list)//返回指定列表支持的同步(线程安全的)List。
+synchronizedMap(Map m) //返回由指定映射支持的同步(线程安全的)Map。
+synchronizedSet(Set s) //返回指定 set 支持的同步(线程安全的)set。
+```
+
+### Collections还可以设置不可变集合,提供了如下三类方法:
+
+```java
+emptyXxx(): 返回一个空的、不可变的集合对象,此处的集合既可以是List,也可以是Set,还可以是Map。
+singletonXxx(): 返回一个只包含指定对象(只有一个或一个元素)的不可变的集合对象,此处的集合可以是:List,Set,Map。
+unmodifiableXxx(): 返回指定集合对象的不可变视图,此处的集合可以是:List,Set,Map。
+上面三类方法的参数是原有的集合对象,返回值是该集合的”只读“版本。
+```
+
+**示例代码:**
+
+```java
+ ArrayList arrayList = new ArrayList();
+ arrayList.add(-1);
+ arrayList.add(3);
+ arrayList.add(3);
+ arrayList.add(-5);
+ arrayList.add(7);
+ arrayList.add(4);
+ arrayList.add(-9);
+ arrayList.add(-7);
+ HashSet integers1 = new HashSet<>();
+ integers1.add(1);
+ integers1.add(3);
+ integers1.add(2);
+ Map scores = new HashMap();
+ scores.put("语文" , 80);
+ scores.put("Java" , 82);
+
+ //Collections.emptyXXX();创建一个空的、不可改变的XXX对象
+ List