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\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/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/Java\347\233\270\345\205\263/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
deleted file mode 100644
index cb0bd1fe0e3..00000000000
--- "a/Java\347\233\270\345\205\263/Java\351\233\206\345\220\210\346\241\206\346\236\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,353 +0,0 @@
-
-
-1. [List,Set,Map三者的区别及总结](#list,setmap三者的区别及总结)
-1. [Arraylist 与 LinkedList 区别](#arraylist-与-linkedlist-区别)
-1. [ArrayList 与 Vector 区别(为什么要用Arraylist取代Vector呢?)](#arraylist-与-vector-区别)
-1. [HashMap 和 Hashtable 的区别](#hashmap-和-hashtable-的区别)
-1. [HashSet 和 HashMap 区别](#hashset-和-hashmap-区别)
-1. [HashMap 和 ConcurrentHashMap 的区别](#hashmap-和-concurrenthashmap-的区别)
-1. [HashSet如何检查重复](#hashset如何检查重复)
-1. [comparable 和 comparator的区别](#comparable-和-comparator的区别)
- 1. [Comparator定制排序](#comparator定制排序)
- 1. [重写compareTo方法实现按年龄来排序](#重写compareto方法实现按年龄来排序)
-1. [如何对Object的list排序?](#如何对object的list排序)
-1. [如何实现数组与List的相互转换?](#如何实现数组与list的相互转换)
-1. [如何求ArrayList集合的交集 并集 差集 去重复并集](#如何求arraylist集合的交集-并集-差集-去重复并集)
-1. [HashMap 的工作原理及代码实现](#hashmap-的工作原理及代码实现)
-1. [ConcurrentHashMap 的工作原理及代码实现](#concurrenthashmap-的工作原理及代码实现)
-1. [集合框架底层数据结构总结](#集合框架底层数据结构总结)
- 1. [- Collection](#--collection)
- 1. [1. List](#1-list)
- 1. [2. Set](#2-set)
- 1. [- Map](#--map)
-1. [集合的选用](#集合的选用)
-1. [集合的常用方法](#集合的常用方法)
-
-
-
-
-## List,Set,Map三者的区别及总结
-- **List:对付顺序的好帮手**
-
- List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象
-- **Set:注重独一无二的性质**
-
- 不允许重复的集合。不会有多个元素引用相同的对象。
-
-- **Map:用Key来搜索的专家**
-
- 使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
-
-
-## Arraylist 与 LinkedList 区别
-Arraylist底层使用的是数组(存读数据效率高,插入删除特定位置效率低),LinkedList 底层使用的是双向链表数据结构(插入,删除效率特别高)(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别:); 详细可阅读JDK1.7-LinkedList循环链表优化。学过数据结构这门课后我们就知道采用链表存储,插入,删除元素时间复杂度不受元素位置的影响,都是近似O(1)而数组为近似O(n),因此当数据特别多,而且经常需要插入删除元素时建议选用LinkedList.一般程序只用Arraylist就够用了,因为一般数据量都不会蛮大,Arraylist是使用最多的集合类。
-
-## ArrayList 与 Vector 区别
-Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector
-,代码要在同步操作上耗费大量的时间。Arraylist不是同步的,所以在不需要同步时建议使用Arraylist。
-
-## HashMap 和 Hashtable 的区别
-1. HashMap是非线程安全的,HashTable是线程安全的;HashTable内部的方法基本都经过synchronized修饰。
-
-2. 因为线程安全的问题,HashMap要比HashTable效率高一点,HashTable基本被淘汰。
-3. HashMap允许有null值的存在,而在HashTable中put进的键值只要有一个null,直接抛出NullPointerException。
-
-Hashtable和HashMap有几个主要的不同:线程安全以及速度。仅在你需要完全的线程安全的时候使用Hashtable,而如果你使用Java5或以上的话,请使用ConcurrentHashMap吧
-
-## HashSet 和 HashMap 区别
-
-
-## HashMap 和 ConcurrentHashMap 的区别
-[HashMap与ConcurrentHashMap的区别](https://blog.csdn.net/xuefeng0707/article/details/40834595)
-
-1. ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。)
-2. HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
-
-## HashSet如何检查重复
-当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。(摘自我的Java启蒙书《Head fist java》第二版)
-
-**hashCode()与equals()的相关规定:**
-1. 如果两个对象相等,则hashcode一定也是相同的
-2. 两个对象相等,对两个equals方法返回true
-3. 两个对象有相同的hashcode值,它们也不一定是相等的
-4. 综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
-5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。
-
-**==与equals的区别**
-
-1. ==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同
-2. ==是指对内存地址进行比较 equals()是对字符串的内容进行比较
-3. ==指引用是否相同 equals()指的是值是否相同
-
-## comparable 和 comparator的区别
-- comparable接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序
-- comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序
-
-一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort().
-
-### Comparator定制排序
-```java
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
-/**
- * TODO Collections类方法测试之排序
- * @author 寇爽
- * @date 2017年11月20日
- * @version 1.8
- */
-public class CollectionsSort {
-
- public static void main(String[] args) {
-
- 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);
-/*
- * void rotate(List list, int distance),旋转。
- * 当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将
- * list的前distance个元素整体移到后面。
-
- 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);
-
- // 定制排序的用法
- Collections.sort(arrayList, new Comparator() {
-
- @Override
- public int compare(Integer o1, Integer o2) {
- return o2.compareTo(o1);
- }
- });
- System.out.println("定制排序后:");
- System.out.println(arrayList);
- }
-
-}
-
-```
-### 重写compareTo方法实现按年龄来排序
-```java
-package map;
-
-import java.util.Set;
-import java.util.TreeMap;
-
-public class TreeMap2 {
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- TreeMap pdata = new TreeMap();
- pdata.put(new Person("张三", 30), "zhangsan");
- pdata.put(new Person("李四", 20), "lisi");
- pdata.put(new Person("王五", 10), "wangwu");
- pdata.put(new Person("小红", 5), "xiaohong");
- // 得到key的值的同时得到key所对应的值
- Set keys = pdata.keySet();
- for (Person key : keys) {
- System.out.println(key.getAge() + "-" + key.getName());
-
- }
- }
-}
-
-// person对象没有实现Comparable接口,所以必须实现,这样才不会出错,才可以使treemap中的数据按顺序排列
-// 前面一个例子的String类已经默认实现了Comparable接口,详细可以查看String类的API文档,另外其他
-// 像Integer类等都已经实现了Comparable接口,所以不需要另外实现了
-
-class Person implements Comparable {
- private String name;
- private int age;
-
- public Person(String name, int age) {
- super();
- this.name = name;
- this.age = age;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- /**
- * TODO重写compareTo方法实现按年龄来排序
- */
- @Override
- public int compareTo(Person o) {
- // TODO Auto-generated method stub
- if (this.age > o.getAge()) {
- return 1;
- } else if (this.age < o.getAge()) {
- return -1;
- }
- return age;
- }
-}
-```
-
-## 如何对Object的list排序
-- 对objects数组进行排序,我们可以用Arrays.sort()方法
-- 对objects的集合进行排序,需要使用Collections.sort()方法
-
-
-## 如何实现数组与List的相互转换
-List转数组:toArray(arraylist.size()方法;数组转List:Arrays的asList(a)方法
-```java
-List arrayList = new ArrayList();
- arrayList.add("s");
- arrayList.add("e");
- arrayList.add("n");
- /**
- * ArrayList转数组
- */
- int size=arrayList.size();
- String[] a = arrayList.toArray(new String[size]);
- //输出第二个元素
- System.out.println(a[1]);//结果:e
- //输出整个数组
- System.out.println(Arrays.toString(a));//结果:[s, e, n]
- /**
- * 数组转list
- */
- List list=Arrays.asList(a);
- /**
- * list转Arraylist
- */
- List arrayList2 = new ArrayList();
- arrayList2.addAll(list);
- System.out.println(list);
-```
-## 如何求ArrayList集合的交集 并集 差集 去重复并集
-需要用到List接口中定义的几个方法:
-
-- addAll(Collection extends E> c) :按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾
-实例代码:
-- retainAll(Collection> c): 仅保留此列表中包含在指定集合中的元素。
-- removeAll(Collection> c) :从此列表中删除指定集合中包含的所有元素。
-```java
-package list;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- *TODO 两个集合之间求交集 并集 差集 去重复并集
- * @author 寇爽
- * @date 2017年11月21日
- * @version 1.8
- */
-public class MethodDemo {
-
- public static void main(String[] args) {
- // TODO Auto-generated method stub
- List list1 = new ArrayList();
- list1.add(1);
- list1.add(2);
- list1.add(3);
- list1.add(4);
-
- List list2 = new ArrayList();
- list2.add(2);
- list2.add(3);
- list2.add(4);
- list2.add(5);
- // 并集
- // list1.addAll(list2);
- // 交集
- //list1.retainAll(list2);
- // 差集
- // list1.removeAll(list2);
- // 无重复并集
- list2.removeAll(list1);
- list1.addAll(list2);
- for (Integer i : list1) {
- System.out.println(i);
- }
- }
-
-}
-
-```
-
-## HashMap 的工作原理及代码实现
-
-[集合框架源码学习之HashMap(JDK1.8)](https://juejin.im/post/5ab0568b5188255580020e56)
-
-## ConcurrentHashMap 的工作原理及代码实现
-
-[ConcurrentHashMap实现原理及源码分析](http://www.cnblogs.com/chengxiao/p/6842045.html)
-
-
-## 集合框架底层数据结构总结
-### - Collection
-
-#### 1. List
- - Arraylist:数组(查询快,增删慢 线程不安全,效率高 )
- - Vector:数组(查询快,增删慢 线程安全,效率低 )
- - LinkedList:链表(查询慢,增删快 线程不安全,效率高 )
-
-#### 2. Set
- - HashSet(无序,唯一):哈希表或者叫散列集(hash table)
- - LinkedHashSet:链表和哈希表组成 。 由链表保证元素的排序 , 由哈希表证元素的唯一性
- - TreeSet(有序,唯一):红黑树(自平衡的排序二叉树。)
-
-### - Map
- - HashMap:基于哈希表的Map接口实现(哈希表对键进行散列,Map结构即映射表存放键值对)
- - LinkedHashMap:HashMap 的基础上加上了链表数据结构
- - HashTable:哈希表
- - TreeMap:红黑树(自平衡的排序二叉树)
-
-
-## 集合的选用
-主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用Map接口下的集合,需要排序时选择TreeMap,不需要排序时就选择HashMap,需要保证线程安全就选用ConcurrentHashMap.当我们只需要存放元素值时,就选择实现Collection接口的集合,需要保证元素唯一时选择实现Set接口的集合比如TreeSet或HashSet,不需要就选择实现List接口的比如ArrayList或LinkedList,然后再根据实现这些接口的集合的特点来选用。
-
-2018/3/11更新
-## 集合的常用方法
-今天下午无意看见一道某大厂的面试题,面试题的内容就是问你某一个集合常见的方法有哪些。虽然平时也经常见到这些集合,但是猛一下让我想某一个集合的常用的方法难免会有遗漏或者与其他集合搞混,所以建议大家还是照着API文档把常见的那几个集合的常用方法看一看。
-
-会持续更新。。。
-
-**参考书籍:**
-
-《Head first java 》第二版 推荐阅读真心不错 (适合基础较差的)
-
- 《Java核心技术卷1》推荐阅读真心不错 (适合基础较好的)
-
- 《算法》第四版 (适合想对数据结构的Java实现感兴趣的)
-
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 4f38f3a1261..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 819d37faca2..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 区+Survivor1 区+Survivor2 区。值得注意的是,在 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`
-
-
-运行结果(红色字体描述有误,应该是对应于JDK1.7的永久代):
-
-
-
-从上图我们可以看出eden区内存几乎已经被分配完全(即使程序什么也不做,新生代也会使用2000多k内存)。假如我们再为allocation2分配内存会出现什么情况呢?
-
-```java
-allocation2 = new byte[900*1024];
-```
-
-
-**简单解释一下为什么会出现这种情况:** 因为给allocation2分配内存的时候eden区内存几乎已经被分配完了,我们刚刚讲了当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC.GC期间虚拟机又发现allocation1无法存入Survivor空间,所以只好通过 **分配担保机制** 把新生代的对象提前转移到老年代中去,老年代上的空间足够存放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\277\231\345\207\240\351\201\223Java\351\233\206\345\220\210\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\207\240\344\271\216\345\277\205\351\227\256.md" "b/Java\347\233\270\345\205\263/\350\277\231\345\207\240\351\201\223Java\351\233\206\345\220\210\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\207\240\344\271\216\345\277\205\351\227\256.md"
deleted file mode 100644
index 18587f42392..00000000000
--- "a/Java\347\233\270\345\205\263/\350\277\231\345\207\240\351\201\223Java\351\233\206\345\220\210\346\241\206\346\236\266\351\235\242\350\257\225\351\242\230\345\207\240\344\271\216\345\277\205\351\227\256.md"
+++ /dev/null
@@ -1,288 +0,0 @@
-
-
-
-
-- [Arraylist 与 LinkedList 异同](#arraylist-与-linkedlist-异同)
- - [补充:数据结构基础之双向链表](#补充:数据结构基础之双向链表)
-- [ArrayList 与 Vector 区别](#arraylist-与-vector-区别)
-- [HashMap的底层实现](#hashmap的底层实现)
- - [JDK1.8之前](#jdk18之前)
- - [JDK1.8之后](#jdk18之后)
-- [HashMap 和 Hashtable 的区别](#hashmap-和-hashtable-的区别)
-- [HashMap 的长度为什么是2的幂次方](#hashmap-的长度为什么是2的幂次方)
-- [HashMap 多线程操作导致死循环问题](#hashmap-多线程操作导致死循环问题)
-- [HashSet 和 HashMap 区别](#hashset-和-hashmap-区别)
-- [ConcurrentHashMap 和 Hashtable 的区别](#concurrenthashmap-和-hashtable-的区别)
-- [ConcurrentHashMap线程安全的具体实现方式/底层具体实现](#concurrenthashmap线程安全的具体实现方式底层具体实现)
- - [JDK1.7(上面有示意图)](#jdk17(上面有示意图))
- - [JDK1.8 (上面有示意图)](#jdk18-(上面有示意图))
-- [集合框架底层数据结构总结](#集合框架底层数据结构总结)
- - [Collection](#collection)
- - [1. List](#1-list)
- - [2. Set](#2-set)
- - [Map](#map)
- - [推荐阅读:](#推荐阅读:)
-
-
-
-## Arraylist 与 LinkedList 异同
-
-- **1. 是否保证线程安全:** ArrayList 和 LinkedList 都是不同步的,也就是不保证线程安全;
-- **2. 底层数据结构:** Arraylist 底层使用的是Object数组;LinkedList 底层使用的是双向链表数据结构(JDK1.6之前为循环链表,JDK1.7取消了循环。注意双向链表和双向循环链表的区别:); 详细可阅读[JDK1.7-LinkedList循环链表优化](https://www.cnblogs.com/xingele0917/p/3696593.html)
-- **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更多的空间(因为要存放直接后继和直接前驱以及数据)。
--**6.补充内容: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()>>:无符号右移,忽略符号位,空位都以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 次。
-
-所谓 **“拉链法”** 就是:将链表和数组相结合。也就是说创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。
-
-
-
-
-
-
-### JDK1.8之后
-相比于之前的版本, JDK1.8之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
-
-
-
->TreeMap、TreeSet以及JDK1.8之后的HashMap底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
-
-**推荐阅读:**
-
-- 《Java 8系列之重新认识HashMap》 :[https://zhuanlan.zhihu.com/p/21673805](https://zhuanlan.zhihu.com/p/21673805)
-
-## 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 没有这样的机制。
-
-**HasMap 中带有初始容量的构造函数:**
-
-```java
- public HashMap(int initialCapacity, float loadFactor) {
- if (initialCapacity < 0)
- throw new IllegalArgumentException("Illegal initial capacity: " +
- initialCapacity);
- if (initialCapacity > MAXIMUM_CAPACITY)
- initialCapacity = MAXIMUM_CAPACITY;
- if (loadFactor <= 0 || Float.isNaN(loadFactor))
- throw new IllegalArgumentException("Illegal load factor: " +
- loadFactor);
- this.loadFactor = loadFactor;
- this.threshold = tableSizeFor(initialCapacity);
- }
- public HashMap(int initialCapacity) {
- this(initialCapacity, DEFAULT_LOAD_FACTOR);
- }
-```
-
-下面这个方法保证了 HashMap 总是使用2的幂作为哈希表的大小。
-
-```java
- /**
- * Returns a power of two size for the given target capacity.
- */
- static final int tableSizeFor(int cap) {
- int n = cap - 1;
- n |= n >>> 1;
- n |= n >>> 2;
- n |= n >>> 4;
- n |= n >>> 8;
- n |= n >>> 16;
- return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
- }
-```
-
-## HashMap 的长度为什么是2的幂次方
-
-为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。我们上面也讲到了过了,Hash 值的范围值-2147483648到2147483647,前后加起来大概40亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但问题是一个40亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ `(n - 1) & hash` ”。(n代表数组长度)。这也就解释了 HashMap 的长度为什么是2的幂次方。
-
-**这个算法应该如何设计呢?**
-
-我们首先可能会想到采用%取余的操作来实现。但是,重点来了:**“取余(%)操作中如果除数是2的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是2的 n 次方;)。”** 并且 **采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是2的幂次方。**
-
-## HashMap 多线程操作导致死循环问题
-
-在多线程下,进行 put 操作会导致 HashMap 死循环,原因在于 HashMap 的扩容 resize()方法。由于扩容是新建一个数组,复制原数据到数组。由于数组下标挂有链表,所以需要复制链表,但是多线程操作有可能导致环形链表。复制链表过程如下:
-以下模拟2个线程同时扩容。假设,当前 HashMap 的空间为2(临界值为1),hashcode 分别为 0 和 1,在散列地址 0 处有元素 A 和 B,这时候要添加元素 C,C 经过 hash 运算,得到散列地址为 1,这时候由于超过了临界值,空间不够,需要调用 resize 方法进行扩容,那么在多线程条件下,会出现条件竞争,模拟过程如下:
-
- 线程一:读取到当前的 HashMap 情况,在准备扩容时,线程二介入
-
-
-
-线程二:读取 HashMap,进行扩容
-
-
-
-线程一:继续执行
-
-
-
-这个过程为,先将 A 复制到新的 hash 表中,然后接着复制 B 到链头(A 的前边:B.next=A),本来 B.next=null,到此也就结束了(跟线程二一样的过程),但是,由于线程二扩容的原因,将 B.next=A,所以,这里继续复制A,让 A.next=B,由此,环形链表出现:B.next=A; A.next=B
-
-**注意:jdk1.8已经解决了死循环的问题。**详细信息请阅读[jdk1.8 hashmap多线程put不会造成死循环](https://blog.csdn.net/qq_27007251/article/details/71403647)
-
-
-## HashSet 和 HashMap 区别
-
-如果你看过 HashSet 源码的话就应该知道:HashSet 底层就是基于 HashMap 实现的。(HashSet 的源码非常非常少,因为除了 clone() 方法、writeObject()方法、readObject()方法是 HashSet 自己不得不实现之外,其他方法都是直接调用 HashMap 中的方法。)
-
-
-
-## ConcurrentHashMap 和 Hashtable 的区别
-
-ConcurrentHashMap 和 Hashtable 的区别主要体现在实现线程安全的方式上不同。
-
-- **底层数据结构:** JDK1.7的 ConcurrentHashMap 底层采用 **分段的数组+链表** 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。Hashtable 和 JDK1.8 之前的 HashMap 的底层数据结构类似都是采用 **数组+链表** 的形式,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的;
-- **实现线程安全的方式(重要):** ① **在JDK1.7的时候,ConcurrentHashMap(分段锁)** 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 **到了 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: 链表节点):
-
-
-## 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倍。
-
-
-
-## 集合框架底层数据结构总结
-### Collection
-
-#### 1. List
- - **Arraylist:** Object数组
- - **Vector:** Object数组
- - **LinkedList:** 双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)
- 详细可阅读[JDK1.7-LinkedList循环链表优化](https://www.cnblogs.com/xingele0917/p/3696593.html)
-
-#### 2. Set
- - **HashSet(无序,唯一):** 基于 HashMap 实现的,底层采用 HashMap 来保存元素
- - **LinkedHashSet:** LinkedHashSet 继承与 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 Hashmap 实现一样,不过还是有一点点区别的。
- - **TreeSet(有序,唯一):** 红黑树(自平衡的排序二叉树。)
-
-### Map
- - **HashMap:** JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突).JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
- - **LinkedHashMap:** LinkedHashMap 继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看:[《LinkedHashMap 源码详细分析(JDK1.8)》](https://www.imooc.com/article/22931)
- - **HashTable:** 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
- - **TreeMap:** 红黑树(自平衡的排序二叉树)
-
-
-
-
-### 推荐阅读:
-
-- [jdk1.8中ConcurrentHashMap的实现原理](https://blog.csdn.net/fjse51/article/details/55260493)
-- [HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!](https://crossoverjie.top/2018/07/23/java-senior/ConcurrentHashMap/)
-- [HASHMAP、HASHTABLE、CONCURRENTHASHMAP的原理与区别](http://www.yuanrengu.com/index.php/2017-01-17.html)
-- [ConcurrentHashMap实现原理及源码分析](https://www.cnblogs.com/chengxiao/p/6842045.html)
-- [java-并发-ConcurrentHashMap高并发机制-jdk1.8](https://blog.csdn.net/jianghuxiaojin/article/details/52006118#commentBox)
diff --git a/README.md b/README.md
index 3affa224314..c5bfd282454 100644
--- a/README.md
+++ b/README.md
@@ -1,199 +1,253 @@
-# Java 学习/面试指南
+点击订阅[Java面试进阶指南](https://xiaozhuanlan.com/javainterview?rel=javaguide)(专为Java面试方向准备)。[为什么要弄这个专栏?](https://shimo.im/docs/9BJjNsNg7S4dCnz3/)
-**一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字“1”即可免费无套路获取。**
-
-**【限时福利】** 极客时间[《Java 并发编程面试必备》](#Java并发编程专栏)专栏限时特惠,购买之后的小伙伴加 [我的微信](#联系我) 报上自己的极客时间大名可以找我会把24元返现退给大家,减轻各位学习成本。
+
+
+
+
+
+
+
+
+
+
+
+
-为了优化大家的阅读体验,我重新进行了排版,并且增加了较为详细的[目录](#目录)供大家参考!对本仓库提过有价值的 issue 或 pr 的小伙伴将出现在 [Contributor](#Contributor) 这里。另外, 由于我个人能力有限,很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。**对于不错的原创文章我根据你的选择给予现金奖励、付费专栏或者书籍进行奖励!所以,快提 pr 或者邮件的方式(邮件地址在主页)给我投稿吧!** 当然,我觉得奖励是次要的,最重要的是你可以从自己整理知识点的过程中学习到很多知识。
+Special Sponsors
-
-

-
+
+
+
+
+
+
+
+
-微信交流群添加 [我的微信](#我的微信) 后回复关键字“加群”即可入群。
-
+推荐使用 在线阅读(访问速度慢的话,请使用 ),在线阅读内容本仓库同步一致。这种方式阅读的优势在于:有侧边栏阅读体验更好,Gitee pages 的访问速度相对来说也比较快。
## 目录
-* [:coffee: Java](#coffee-java)
- * [Java/J2EE 基础](#javaj2ee-基础)
- * [Java 集合框架](#java-集合框架)
- * [Java 多线程](#java-多线程)
- * [Java BIO,NIO,AIO](#java-bionioaio)
- * [Java 虚拟机 jvm](#java-虚拟机-jvm)
-* [:open_file_folder: 数据结构与算法](#open_file_folder-数据结构与算法)
- * [数据结构](#数据结构)
- * [算法](#算法)
-* [:computer: 计算机网络与数据通信](#computer-计算机网络与数据通信)
- * [网络相关](#网络相关)
- * [数据通信\(RESTful,RPC,消息队列\)总结](#数据通信restfulrpc消息队列总结)
-* [:iphone: 操作系统](#iphone-操作系统)
- * [Linux相关](#linux相关)
-* [:pencil2: 主流框架/软件](#pencil2-主流框架软件)
- * [Spring](#spring)
- * [ZooKeeper](#zookeeper)
-* [:floppy_disk: 数据存储](#floppy_disk-数据存储)
- * [MySQL](#mysql)
- * [Redis](#redis)
-* [:punch: 架构](#punch-架构)
-* [:musical_note: 面试必备](#musical_note-面试必备)
- * [备战面试](#备战面试)
- * [最最最常见的Java面试题总结](#最最最常见的java面试题总结)
- * [Java学习/面试开源仓库推荐](#java学习面试开源仓库推荐)
-* [:art: 闲谈](#art-闲谈)
-* [:envelope: 说明](#envelope-说明)
-
-## 待办
-
-* [ ] Java 8 新特性总结
-* [x] BIO,NIO,AIO 总结
-* [ ] Netty 总结
-* [ ] 数据结构总结重构
-
-## :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)
-* [Java常见关键字总结:static、final、this、super](https://github.com/Snailclimb/Java-Guide/blob/master/Java相关/final、static、this、super.md)
+- [Java](#java)
+ - [基础](#基础)
+ - [容器](#容器)
+ - [并发](#并发)
+ - [JVM](#jvm)
+ - [I/O](#io)
+ - [Java 8](#java-8)
+ - [编程规范](#编程规范)
+- [网络](#网络)
+- [操作系统](#操作系统)
+ - [Linux相关](#linux相关)
+- [数据结构与算法](#数据结构与算法)
+ - [数据结构](#数据结构)
+ - [算法](#算法)
+- [数据库](#数据库)
+ - [MySQL](#mysql)
+ - [Redis](#redis)
+- [系统设计](#系统设计)
+ - [设计模式(工厂模式、单例模式 ... )](#设计模式)
+ - [常用框架(Spring、Zookeeper ... )](#常用框架)
+ - [数据通信(消息队列、Dubbo ... )](#数据通信)
+ - [网站架构](#网站架构)
+- [面试指南](#面试指南)
+ - [备战面试](#备战面试)
+ - [常见面试题总结](#常见面试题总结)
+ - [面经](#面经)
+- [工具](#工具)
+ - [Git](#git)
+ - [Docker](#Docker)
+- [资料](#资料)
+ - [书单](#书单)
+ - [Github榜单](#Github榜单)
+- [待办](#待办)
+- [说明](#说明)
+
+## Java
+
+### 基础
+
+* [Java 基础知识回顾](docs/java/Java基础知识.md)
+* [J2EE 基础知识回顾](docs/java/J2EE基础知识.md)
+
+### 容器
+
+* [常见面试题](docs/java/collection/Java集合框架常见面试题.md)
+* [ArrayList 源码学习](docs/java/collection/ArrayList.md)
+* [LinkedList 源码学习](docs/java/collection/LinkedList.md)
+* [HashMap(JDK1.8)源码学习](docs/java/collection/HashMap.md)
+
+### 并发
+
+* [Java 并发基础常见面试题总结](docs/java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md)
+* [Java 并发进阶常见面试题总结](docs/java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md)
+* [并发容器总结](docs/java/Multithread/并发容器总结.md)
+* [乐观锁与悲观锁](docs/essential-content-for-interview/面试必备之乐观锁与悲观锁.md)
+* [JUC 中的 Atomic 原子类总结](docs/java/Multithread/Atomic.md)
+* [AQS 原理以及 AQS 同步组件总结](docs/java/Multithread/AQS.md)
+
+### JVM
+
+* [一 Java内存区域](docs/java/jvm/Java内存区域.md)
+* [二 JVM垃圾回收](docs/java/jvm/JVM垃圾回收.md)
+* [三 JDK 监控和故障处理工具](docs/java/jvm/JDK监控和故障处理工具总结.md)
+* [四 类文件结构](docs/java/jvm/类文件结构.md)
+* [五 类加载过程](docs/java/jvm/类加载过程.md)
+* [六 类加载器](docs/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)
+
+## 操作系统
-
-### 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)
+### Linux相关
-### Java 多线程
+* [后端程序员必备的 Linux 基础知识](docs/operating-system/后端程序员必备的Linux基础知识.md)
+* [Shell 编程入门](docs/operating-system/Shell.md)
-* [多线程系列文章](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)
-* [并发编程面试必备:乐观锁与悲观锁](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/面试必备之乐观锁与悲观锁.md)
-* [并发编程面试必备:JUC 中的 Atomic 原子类总结](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Multithread/Atomic.md)
-* [并发编程面试必备:AQS 原理以及 AQS 同步组件总结](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Multithread/AQS.md)
-* [BATJ都爱问的多线程面试题](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Multithread/BATJ都爱问的多线程面试题.md)
-* [并发容器总结](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Multithread/并发容器总结.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虚拟机》第2版学习笔记](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Java虚拟机(jvm).md)
+- [数据结构知识学习与面试](docs/dataStructures-algorithms/数据结构.md)
-### Java BIO,NIO,AIO
+### 算法
-* [BIO,NIO,AIO 总结 ](https://github.com/Snailclimb/JavaGuide/blob/master/Java%E7%9B%B8%E5%85%B3/BIO%2CNIO%2CAIO%20summary.md)
-* [Java IO 与 NIO系列文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/Java%20IO与NIO.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)
-### 设计模式
+## 数据库
-* [设计模式系列文章](https://github.com/Snailclimb/Java_Guide/blob/master/Java相关/设计模式.md)
+### MySQL
-## :open_file_folder: 数据结构与算法
+* [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
-* [数据结构知识学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/数据结构与算法/数据结构.md)
+* [Redis 总结](docs/database/Redis/Redis.md)
+* [Redlock分布式锁](docs/database/Redis/Redlock分布式锁.md)
+* [如何做可靠的分布式锁,Redlock真的可行么](docs/database/Redis/如何做可靠的分布式锁,Redlock真的可行么.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: 计算机网络与数据通信
+- [设计模式系列文章](docs/system-design/设计模式.md)
-### 网络相关
+### 常用框架
-* [计算机网络常见面试题](https://github.com/Snailclimb/Java_Guide/blob/master/计算机网络与数据通信/计算机网络.md)
-* [计算机网络基础知识总结](https://github.com/Snailclimb/Java_Guide/blob/master/计算机网络与数据通信/干货:计算机网络知识总结.md)
-* [HTTPS中的TLS](https://github.com/Snailclimb/Java_Guide/blob/master/计算机网络与数据通信/HTTPS中的TLS.md)
+#### Spring
-### 数据通信(RESTful,RPC,消息队列)总结
+- [Spring 学习与面试](docs/system-design/framework/spring/Spring.md)
+- [Spring中bean的作用域与生命周期](docs/system-design/framework/spring/SpringBean.md)
+- [SpringMVC 工作原理详解](docs/system-design/framework/spring/SpringMVC-Principle.md)
+- [Spring中都用到了那些设计模式?](docs/system-design/framework/spring/Spring-Design-Patterns.md)
-* [数据通信(RESTful、RPC、消息队列)相关知识点总结](https://github.com/Snailclimb/Java-Guide/blob/master/计算机网络与数据通信/数据通信(RESTful、RPC、消息队列).md)
-* [Dubbo 总结:关于 Dubbo 的重要知识点](https://github.com/Snailclimb/Java-Guide/blob/master/计算机网络与数据通信/dubbo.md)
-* [消息队列总结:新手也能看懂,消息队列其实很简单](https://github.com/Snailclimb/Java-Guide/blob/master/计算机网络与数据通信/message-queue.md)
-* [一文搞懂 RabbitMQ 的重要概念以及安装](https://github.com/Snailclimb/Java-Guide/blob/master/计算机网络与数据通信/rabbitmq.md)
+#### ZooKeeper
-## :iphone: 操作系统
+- [ZooKeeper 相关概念总结](docs/system-design/framework/ZooKeeper.md)
+- [ZooKeeper 数据模型和常见命令](docs/system-design/framework/ZooKeeper数据模型和常见命令.md)
-### Linux相关
+### 数据通信
-* [后端程序员必备的 Linux 基础知识](https://github.com/Snailclimb/Java-Guide/blob/master/操作系统/后端程序员必备的Linux基础知识.md)
-* [Shell 编程入门](https://github.com/Snailclimb/Java-Guide/blob/master/操作系统/Shell.md)
-## :pencil2: 主流框架/软件
+- [数据通信(RESTful、RPC、消息队列)相关知识点总结](docs/system-design/data-communication/summary.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)
+- [RocketMQ的几个简单问题与答案](docs/system-design/data-communication/RocketMQ-Questions.md)
-### 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)
+- [一文读懂分布式应该学什么](docs/system-design/website-architecture/分布式.md)
+- [8 张图读懂大型网站技术架构](docs/system-design/website-architecture/8%20张图读懂大型网站技术架构.md)
+- [【面试精选】关于大型网站系统架构你不得不懂的10个问题](docs/system-design/website-architecture/【面试精选】关于大型网站系统架构你不得不懂的10个问题.md)
-### ZooKeeper
+## 面试指南
-* [可能是把 ZooKeeper 概念讲的最清楚的一篇文章](https://github.com/Snailclimb/Java_Guide/blob/master/主流框架/ZooKeeper.md)
-* [ZooKeeper 数据模型和常见命令了解一下,速度收藏!](https://github.com/Snailclimb/Java_Guide/blob/master/主流框架/ZooKeeper数据模型和常见命令.md)
-
-## :floppy_disk: 数据存储
+### 备战面试
-### MySQL
+* [【备战面试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)
-* [MySQL 学习与面试](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/MySQL.md)
-* [【思维导图-索引篇】搞定数据库索引就是这么简单](https://github.com/Snailclimb/Java_Guide/blob/master/数据存储/MySQL%20Index.md)
+### 常见面试题总结
-### Redis
+* [第一周(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/collection/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) (主要内容是几道面试常问的多线程基础题。)
-* [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: 架构
+- [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)
-* [一文读懂分布式应该学什么](https://github.com/Snailclimb/Java_Guide/blob/master/架构/分布式.md)
-* [8 张图读懂大型网站技术架构](https://github.com/Snailclimb/JavaGuide/blob/master/架构/8%20张图读懂大型网站技术架构.md)
-* [【面试精选】关于大型网站系统架构你不得不懂的10个问题](https://github.com/Snailclimb/JavaGuide/blob/master/架构/【面试精选】关于大型网站系统架构你不得不懂的10个问题.md)
+## 工具
-## :musical_note: 面试必备
+### Git
-### 备战面试
+* [Git入门](docs/tools/Git.md)
-* [【备战面试1】程序员的简历就该这样写](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/程序员的简历之道.md)
-* [【备战面试2】初出茅庐的程序员该如何准备面试?](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/interviewPrepare.md)
-* [【备战面试3】Java程序员必备书单](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/books.md)
-* [【备战面试4】美团面试常见问题总结(附详解答案)](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/美团面试常见问题总结.md)
+### Docker
+* [Docker 入门](docs/tools/Docker.md)
+* [一文搞懂 Docker 镜像的常用操作!](docs/tools/Docker-Image.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) (主要内容是几道面试常问的多线程基础题。)
+- [Java程序员必备书单](docs/data/java-recommended-books.md)
-### Java学习/面试开源仓库推荐
+### Github榜单
-* [盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k](https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/JavaInterviewGithub.md)
+- [Java 项目月榜单](docs/github-trending/JavaGithubTrending.md)
-## :art: 闲谈
+***
-* [选择技术方向都要考虑哪些因素](https://github.com/Snailclimb/Java-Guide/blob/master/其他/选择技术方向都要考虑哪些因素.md)
-* [结束了我短暂的秋招,说点自己的感受](https://github.com/Snailclimb/JavaGuide/blob/master/%E5%85%B6%E4%BB%96/2018%20%E7%A7%8B%E6%8B%9B.md)
-* [这7个问题,可能大部分Java程序员都比较关心吧!](https://github.com/Snailclimb/JavaGuide/blob/master/%E9%9D%A2%E8%AF%95%E5%BF%85%E5%A4%87/java%20programmer%20need%20know.md)
-* [【2018总结】即使平凡,也要热爱自己的生活](https://github.com/Snailclimb/JavaGuide/blob/master/%E5%85%B6%E4%BB%96/2018%20summary.md)
+## 待办
-***
+- [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 总结(---正在进行中---)
+- [ ] 数据结构总结重构(---正在进行中---)
-## :envelope: 说明
+## 说明
### 介绍
@@ -201,7 +255,9 @@
也是你学习和复习 Java 知识不错的实践;
* **对于非 Java 初学者来说:** 本文档更适合回顾知识,准备面试,搞清面试应该把重心放在那些问题上。要搞清楚这个道理:提前知道那些面试常见,不是为了背下来应付面试,而是为了让你可以更有针对的学习重点。
-本文档 Markdown 格式参考:[Github Markdown格式](https://guides.github.com/features/mastering-markdown/),表情素材来自:[EMOJI CHEAT SHEET](https://www.webpagefx.com/tools/emoji-cheat-sheet/)。
+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/#/)
### 关于转载
@@ -210,24 +266,22 @@
### 如何对该开源文档进行贡献
1. 笔记内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。
-2. 很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。(**对于不错的原创文章我根据你的选择给予现金奖励、付费专栏或者书籍进行奖励!快提 pr 给我投稿吧!**)
+2. 很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。
3. 现有的知识点难免存在不完善或者错误,所以你可以对已有知识点的修改/补充。
### 为什么要做这个开源文档?
初始想法源于自己的个人那一段比较迷茫的学习经历。主要目的是为了通过这个开源平台来帮助一些在学习 Java 或者面试过程中遇到问题的小伙伴。
-### 联系我
+### 投稿
-如果大家需要与我交流,可以扫描下方二维码添加我的微信获取关注[我的公众号](#公众号):
+由于我个人能力有限,很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。大家也可以对自己的文章进行自荐,对于不错的文章不仅可以成功在本仓库展示出来更可以获得作者送出的 50 元左右的任意书籍进行奖励(当然你也可以直接折现50元)。
-
-
-### Java并发编程专栏
+### 联系我
-微信扫描下方二维码,购买之后我会将自己得到的24元返现都还给你,减轻各位的学习成本!
+添加我的微信备注“Github”,回复关键字 **“加群”** 即可入群。
-
+
### Contributor
@@ -235,9 +289,13 @@
+
+
+
+
@@ -259,9 +317,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
### 公众号
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。我是 ThoughtWorks 准入职Java工程师。专注Java知识分享!开源 Java 学习指南——JavaGuide(12k+ Star)的作者。公众号多篇文章被各大技术社区转载。公众号后台回复关键字“1”可以领取一份我精选的Java资源哦!可以扫描下方二维码或者通过微信的搜一搜搜索ID:“Java_Guide”即可。
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
+
+**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
+
+**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..f2bcbca1ffb
--- /dev/null
+++ b/docs/HomePage.md
@@ -0,0 +1,204 @@
+点击订阅[Java面试进阶指南](https://xiaozhuanlan.com/javainterview?rel=javaguide)(专为Java面试方向准备)。[为什么要弄这个专栏?](https://shimo.im/./9BJjNsNg7S4dCnz3/)
+
+Java 学习/面试指南
+
+
+
+
+
+## Java
+
+### 基础
+
+* [Java 基础知识回顾](./java/Java基础知识.md)
+* [J2EE 基础知识回顾](./java/J2EE基础知识.md)
+
+### 容器
+
+* [常见面试题](./java/collection/Java集合框架常见面试题.md)
+* [ArrayList 源码学习](./java/collection/ArrayList.md)
+* [LinkedList 源码学习](./java/collection/LinkedList.md)
+* [HashMap(JDK1.8)源码学习](./java/collection/HashMap.md)
+
+### 并发
+
+* [Java 并发基础常见面试题总结](./java/Multithread/JavaConcurrencyBasicsCommonInterviewQuestionsSummary.md)
+* [Java 并发进阶常见面试题总结](./java/Multithread/JavaConcurrencyAdvancedCommonInterviewQuestions.md)
+* [并发容器总结](./java/Multithread/并发容器总结.md)
+* [乐观锁与悲观锁](./essential-content-for-interview/面试必备之乐观锁与悲观锁.md)
+* [JUC 中的 Atomic 原子类总结](./java/Multithread/Atomic.md)
+* [AQS 原理以及 AQS 同步组件总结](./java/Multithread/AQS.md)
+
+### JVM
+
+* [一 Java内存区域](./java/jvm/Java内存区域.md)
+* [二 JVM垃圾回收](./java/jvm/JVM垃圾回收.md)
+* [三 JDK 监控和故障处理工具](./java/jvm/JDK监控和故障处理工具总结.md)
+* [四 类文件结构](./java/jvm/类文件结构.md)
+* [五 类加载过程](./java/jvm/类加载过程.md)
+* [六 类加载器](./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/Spring.md)
+- [Spring中bean的作用域与生命周期](./system-design/framework/spring/SpringBean.md)
+- [SpringMVC 工作原理详解](./system-design/framework/spring/SpringMVC-Principle.md)
+- [Spring中都用到了那些设计模式?](./system-design/framework/spring/Spring-Design-Patterns.md)
+
+#### ZooKeeper
+
+- [ZooKeeper 相关概念总结](./system-design/framework/ZooKeeper.md)
+- [ZooKeeper 数据模型和常见命令](./system-design/framework/ZooKeeper数据模型和常见命令.md)
+
+### 数据通信
+
+- [数据通信(RESTful、RPC、消息队列)相关知识点总结](./system-design/data-communication/summary.md)
+- [Dubbo 总结:关于 Dubbo 的重要知识点](./system-design/data-communication/dubbo.md)
+- [消息队列总结](./system-design/data-communication/message-queue.md)
+- [RabbitMQ 入门](./system-design/data-communication/RabbitMQ.md)
+- [RocketMQ的几个简单问题与答案](./system-design/data-communication/RocketMQ-Questions.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/collection/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..c85c1b74f2c 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,53 @@ 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 String replaceSpace(String[] strs) {
+
+ // 如果检查值不合法及就返回空串
+ if (!checkStrs(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 checkStrs(String[] strs) {
+ if (strs != null) {
+ // 遍历strs检查元素值
+ for (int i = 0; i < strs.length; i++) {
+ if (strs[i] == null || strs[i].length() == 0) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
- }
- //测试
- public static void main(String[] args) {
- String[] strs = { "customer", "car", "cat" };
- System.out.println(Main.replaceSpace(strs));//c
- }
+ // 测试
+ 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 92%
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 9889644f39c..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,19 +165,19 @@ 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+树的最主要原因。
+ 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)
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 86%
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 27b82c8bc70..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如何为表字段添加索引???
diff --git "a/\346\225\260\346\215\256\345\255\230\345\202\250/MySQL.md" b/docs/database/MySQL.md
similarity index 94%
rename from "\346\225\260\346\215\256\345\255\230\345\202\250/MySQL.md"
rename to docs/database/MySQL.md
index 44eb02aaa9d..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)
-
-
-> ## 常见问题总结
+## 常见问题总结
- ### ①存储引擎
@@ -134,7 +137,7 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去
当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
- 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内。;
+ 1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
2. **读/写分离:** 经典的数据库拆分方案,主库负责写,从库负责读;
3 . **垂直分区:**
@@ -143,7 +146,7 @@ Java面试通关手册(Java学习指南,欢迎Star,会一直完善下去
**简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。

- **垂直拆分的优点:** 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
+ **垂直拆分的优点:** 可以使得列数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
**垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
@@ -156,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..f079ad77593
--- /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 5732c156825..d5682dcc094 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 设置过期时间
@@ -147,11 +147,11 @@ Redis中有个设置时间过期的功能,即对存储在 redis 数据库中
- **惰性删除** :定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,也是够懒的哈!
-但是仅仅通过设置过期时间还是有问题的。我们想一下:如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致redis内存块耗尽了。怎么解决这个问题呢?
+但是仅仅通过设置过期时间还是有问题的。我们想一下:如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除,此时会怎么样?如果大量过期key堆积在内存里,导致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,25 @@ 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-eviction**:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
+4.0版本后增加以下两种:
+
+7. **volatile-lfu**:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
+8. **allkeys-lfu**:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key
+
+
**备注: 关于 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 +188,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 +208,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 +263,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 +279,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 99%
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"
index b1742f2fbf9..86a15ff6faf 100644
--- "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"
@@ -28,7 +28,7 @@ end
算法很易懂,起 5 个 master 节点,分布在不同的机房尽量保证可用性。为了获得锁,client 会进行如下操作:
-1. 得到当前的时间,微妙单位
+1. 得到当前的时间,微秒单位
2. 尝试顺序地在 5 个实例上申请锁,当然需要使用相同的 key 和 random value,这里一个 client 需要合理设置与 master 节点沟通的 timeout 大小,避免长时间和一个 fail 了的节点浪费时间
3. 当 client 在大于等于 3 个 master 上成功申请到锁的时候,且它会计算申请锁消耗了多少时间,这部分消耗的时间采用获得锁的当下时间减去第一步获得的时间戳得到,如果锁的持续时长(lock validity time)比流逝的时间多的话,那么锁就真正获取到了。
4. 如果锁申请到了,那么锁真正的 lock validity time 应该是 origin(lock validity time) - 申请锁期间流逝的时间
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 4ca58dbfff6..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中方法参数的使用情况:
-- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型》
+- 一个方法不能修改一个基本数据类型的参数(即数值型或布尔型)。
- 一个方法可以改变一个对象参数的状态。
- 一个方法不能让对象参数引用一个新的对象。
@@ -247,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 426498cb2d9..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,10 @@ 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 69%
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 3cb02d73d5b..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会把该线程放 入等待队列(waiting 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类
@@ -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/\351\235\242\350\257\225\345\277\205\345\244\207/JavaInterviewGithub.md" b/docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md
similarity index 100%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/JavaInterviewGithub.md"
rename to docs/essential-content-for-interview/PreparingForInterview/JavaInterviewLibrary.md
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/java programmer need know.md" b/docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md
similarity index 81%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/java programmer need know.md"
rename to docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md
index ef111f4cf15..d515693722e 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/java programmer need know.md"
+++ b/docs/essential-content-for-interview/PreparingForInterview/JavaProgrammerNeedKnow.md
@@ -1,4 +1,4 @@
- 身边的朋友或者公众号的粉丝很多人都向我询问过:“我是双非/三本/专科学校的,我有机会进入大厂吗?”、“非计算机专业的学生能学好吗?”、“如何学习Java?”、“Java学习该学那些东西?”、“我该如何准备Java面试?”......这些方面的问题。我会根据自己的一点经验对大部分人关心的这些问题进行答疑解惑。现在又刚好赶上考研结束,这篇文章也算是给考研结束准备往Java后端方向发展的朋友们指名一条学习之路。道理懂了如果没有实际行动,那这篇文章对你或许没有任何意义。
+ 身边的朋友或者公众号的粉丝很多人都向我询问过:“我是双非/三本/专科学校的,我有机会进入大厂吗?”、“非计算机专业的学生能学好吗?”、“如何学习Java?”、“Java学习该学哪些东西?”、“我该如何准备Java面试?”......这些方面的问题。我会根据自己的一点经验对大部分人关心的这些问题进行答疑解惑。现在又刚好赶上考研结束,这篇文章也算是给考研结束准备往Java后端方向发展的朋友们指明一条学习之路。道理懂了如果没有实际行动,那这篇文章对你或许没有任何意义。
### Question1:我是双非/三本/专科学校的,我有机会进入大厂吗?
@@ -6,7 +6,7 @@
首先,我觉得学校歧视很正常,真的太正常了,如果要抱怨的话,你只能抱怨自己没有进入名校。但是,千万不要动不动说自己学校差,动不动拿自己学校当做自己进不了大厂的借口,学历只是筛选简历的很多标准中的一个而已,如果你够优秀,简历够丰富,你也一样可以和名校同学一起同台竞争。
- 企业HR肯定是更喜欢高学历的人,毕竟985,211优秀人才比例肯定比普通学校高很多,HR团队肯定会优先在这些学校里选。这就好比相亲,你是愿意在很多优秀的人中选一个优秀的,还是愿意在很多普通的人中选一个优秀的呢?
+ 企业HR肯定是更喜欢高学历的人,毕竟985、211优秀人才比例肯定比普通学校高很多,HR团队肯定会优先在这些学校里选。这就好比相亲,你是愿意在很多优秀的人中选一个优秀的,还是愿意在很多普通的人中选一个优秀的呢?
双非本科甚至是二本、三本甚至是专科的同学也有很多进入大厂的,不过比率相比于名校的低很多而已。从大厂招聘的结果上看,高学历人才的数量占据大头,那些成功进入BAT、美团,京东,网易等大厂的双非本科甚至是二本、三本甚至是专科的同学往往是因为具备丰富的项目经历或者在某个含金量比较高的竞赛比如ACM中取得了不错的成绩。**一部分学历不突出但能力出众的面试者能够进入大厂并不是说明学历不重要,而是学历的软肋能够通过其他的优势来弥补。** 所以,如果你的学校不够好而你自己又想去大厂的话,建议你可以从这几点来做:**①尽量在面试前最好有一个可以拿的出手的项目;②有实习条件的话,尽早出去实习,实习经历也会是你的简历的一个亮点(有能力在大厂实习最佳!);③参加一些含金量比较高的比赛,拿不拿得到名次没关系,重在锻炼。**
@@ -17,7 +17,7 @@
我觉得我们不应该因为自己的专业给自己划界限或者贴标签,说实话,很多科班的同学可能并不如你,你以为科班的同学就会认真听讲吗?还不是几乎全靠自己课下自学!不过如果你是非科班的话,你想要学好,那么注定就要舍弃自己本专业的一些学习时间,这是无可厚非的。
- 建议非科班的同学,首先要打好计算机基础知识基础:①计算机网络、②操作系统、③数据机构与算法,我个人觉得这3个对你最重要。这些东西就像是内功,对你以后的长远发展非常有用。当然,如果你想要进大厂的话,这些知识也是一定会被问到的。另外,“一定学好数据机构与算法!一定学好数据机构与算法!一定学好数据机构与算法!”,重要的东西说3遍。
+ 建议非科班的同学,首先要打好计算机基础知识基础:①计算机网络、②操作系统、③数据机构与算法,我个人觉得这3个对你最重要。这些东西就像是内功,对你以后的长远发展非常有用。当然,如果你想要进大厂的话,这些知识也是一定会被问到的。另外,“一定学好数据结构与算法!一定学好数据结构与算法!一定学好数据结构与算法!”,重要的东西说3遍。
@@ -31,12 +31,12 @@
下面是我总结的一些准备面试的Tips以及面试必备的注意事项:
-1. **准备一份自己的自我介绍,面试的时候根据面试对象适当进行修改**(突出重点,突出自己的优势在哪里,切忌流水账);
+1. **准备一份自己的自我介绍,面试的时候根据面试对象适当进行修改**(突出重点,突出自己的优势在哪里,切忌流水账);
2. **注意随身带上自己的成绩单和简历复印件;** (有的公司在面试前都会让你交一份成绩单和简历当做面试中的参考。)
3. **如果需要笔试就提前刷一些笔试题,大部分在线笔试的类型是选择题+编程题,有的还会有简答题。**(平时空闲时间多的可以刷一下笔试题目(牛客网上有很多),但是不要只刷面试题,不动手code,程序员不是为了考试而存在的。)另外,注意抓重点,因为题目太多了,但是有很多题目几乎次次遇到,像这样的题目一定要搞定。
-4. **提前准备技术面试。** 搞清楚自己面试中可能涉及哪些知识点、那些知识点是重点。面试中哪些问题会被经常问到、自己改如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
+4. **提前准备技术面试。** 搞清楚自己面试中可能涉及哪些知识点、哪些知识点是重点。面试中哪些问题会被经常问到、自己该如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
5. **面试之前做好定向复习。** 也就是专门针对你要面试的公司来复习。比如你在面试之前可以在网上找找有没有你要面试的公司的面经。
-6. **准备好自己的项目介绍。** 如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:①对项目整体设计的一个感受(面试官可能会让你画系统的架构图;②在这个项目中你负责了什么、做了什么、担任了什么角色;③ 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用;④项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+6. **准备好自己的项目介绍。** 如果有项目的话,技术面试第一步,面试官一般都是让你自己介绍一下你的项目。你可以从下面几个方向来考虑:①对项目整体设计的一个感受(面试官可能会让你画系统的架构图);②在这个项目中你负责了什么、做了什么、担任了什么角色;③ 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用;④项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用 redis 做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
7. **面试之后记得复盘。** 面试遭遇失败是很正常的事情,所以善于总结自己的失败原因才是最重要的。如果失败,不要灰心;如果通过,切勿狂喜。
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/interviewPrepare.md" b/docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md
similarity index 83%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/interviewPrepare.md"
rename to docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md
index c99ca1c156e..1ae36a35734 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/interviewPrepare.md"
+++ b/docs/essential-content-for-interview/PreparingForInterview/interviewPrepare.md
@@ -1,8 +1,22 @@
-这是【备战春招/秋招系列】的第二篇文章,主要是简单地介绍如何去准备面试。
-
不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个“有章可循”说的意思只是说应对技术面试是可以提前准备。 我其实特别不喜欢那种临近考试就提前背啊记啊各种题的行为,非常反对!我觉得这种方法特别极端,而且在稍有一点经验的面试官面前是根本没有用的。建议大家还是一步一个脚印踏踏实实地走。
-### 1 如何获取大厂面试机会?
+
+
+- [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 如何获取大厂面试机会?
**在讲如何获取大厂面试机会之前,先来给大家科普/对比一下两个校招非常常见的概念——春招和秋招。**
@@ -24,7 +38,7 @@
除了这些方法,我也遇到过这样的经历:有些大公司的一些部门可能暂时没招够人,然后如果你的亲戚或者朋友刚好在这个公司,而你正好又在寻求offer,那么面试机会基本上是有了,而且这种面试的难度好像一般还普遍比其他正规面试低很多。
-### 2 面试前的准备
+## 2 面试前的准备
### 2.1 准备自己的自我介绍
@@ -57,11 +71,11 @@
1. 对项目整体设计的一个感受(面试官可能会让你画系统的架构图)
2. 在这个项目中你负责了什么、做了什么、担任了什么角色
3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
-4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
+4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
### 2.7 提前准备技术面试
-搞清楚自己面试中可能涉及哪些知识点、那些知识点是重点。面试中哪些问题会被经常问到、自己改如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
+搞清楚自己面试中可能涉及哪些知识点、哪些知识点是重点。面试中哪些问题会被经常问到、自己该如何回答。(强烈不推荐背题,第一:通过背这种方式你能记住多少?能记住多久?第二:背题的方式的学习很难坚持下去!)
### 2.7 面试之前做好定向复习
@@ -69,6 +83,6 @@
举个栗子:在我面试 ThoughtWorks 的前几天我就在网上找了一些关于 ThoughtWorks 的技术面的一些文章。然后知道了 ThoughtWorks 的技术面会让我们在之前做的作业的基础上增加一个或两个功能,所以我提前一天就把我之前做的程序重新重构了一下。然后在技术面的时候,简单的改了几行代码之后写个测试就完事了。如果没有提前准备,我觉得 20 分钟我很大几率会完不成这项任务。
-# 3 面试之后复盘
+## 3 面试之后复盘
-如果失败,不要灰心;如果通过,切勿狂喜。面试和工作实际上是两回事,可能很多面试未通过的人,工作能力比你强的多,反之亦然。我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
\ No newline at end of file
+如果失败,不要灰心;如果通过,切勿狂喜。面试和工作实际上是两回事,可能很多面试未通过的人,工作能力比你强的多,反之亦然。我个人觉得面试也像是一场全新的征程,失败和胜利都是平常之事。所以,劝各位不要因为面试失败而灰心、丧失斗志。也不要因为面试通过而沾沾自喜,等待你的将是更美好的未来,继续加油!
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/\351\235\242\350\257\225\345\277\205\345\244\207/\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"
similarity index 56%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\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"
rename to "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"
index d07fa52a7e7..f0627de96e2 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/\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"
@@ -1,21 +1,43 @@
-# 程序员的简历就该这样写
+
-### 1 前言
-一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情况下,写出一份好的简历也是一项很棒的能力。
+- [程序员简历就该这样写](#程序员简历就该这样写)
+ - [为什么说简历很重要?](#为什么说简历很重要)
+ - [先从面试前来说](#先从面试前来说)
+ - [再从面试中来说](#再从面试中来说)
+ - [下面这几点你必须知道](#下面这几点你必须知道)
+ - [必须了解的两大法则](#必须了解的两大法则)
+ - [STAR法则(Situation Task Action Result)](#star法则situation-task-action-result)
+ - [FAB 法则(Feature Advantage Benefit)](#fab-法则feature-advantage-benefit)
+ - [项目经历怎么写?](#项目经历怎么写)
+ - [专业技能该怎么写?](#专业技能该怎么写)
+ - [排版注意事项](#排版注意事项)
+ - [其他的一些小tips](#其他的一些小tips)
+ - [推荐的工具/网站](#推荐的工具网站)
-### 2 为什么说简历很重要?
+
-#### 2.1 先从面试前来说
+# 程序员简历就该这样写
-假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR就会决定你这一关是Fail还是Pass。
+本篇文章除了教大家用Markdown如何写一份程序员专属的简历,后面还会给大家推荐一些不错的用来写Markdown简历的软件或者网站,以及如何优雅的将Markdown格式转变为PDF格式或者其他格式。
-假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。
+推荐大家使用Markdown语法写简历,然后再将Markdown格式转换为PDF格式后进行简历投递。
+
+如果你对Markdown语法不太了解的话,可以花半个小时简单看一下Markdown语法说明: http://www.markdown.cn 。
+
+## 为什么说简历很重要?
+
+一份好的简历可以在整个申请面试以及面试过程中起到非常好的作用。 在不夸大自己能力的情况下,写出一份好的简历也是一项很棒的能力。为什么说简历很重要呢?
+
+### 先从面试前来说
+
+- 假如你是网申,你的简历必然会经过HR的筛选,一张简历HR可能也就花费10秒钟看一下,然后HR就会决定你这一关是Fail还是Pass。
+- 假如你是内推,如果你的简历没有什么优势的话,就算是内推你的人再用心,也无能为力。
另外,就算你通过了筛选,后面的面试中,面试官也会根据你的简历来判断你究竟是否值得他花费很多时间去面试。
所以,简历就像是我们的一个门面一样,它在很大程度上决定了你能否进入到下一轮的面试中。
-#### 2.2 再从面试中来说
+### 再从面试中来说
我发现大家比较喜欢看面经 ,这点无可厚非,但是大部分面经都没告诉你很多问题都是在特定条件下才问的。举个简单的例子:一般情况下你的简历上注明你会的东西才会被问到(Java、数据结构、网络、算法这些基础是每个人必问的),比如写了你会 redis,那面试官就很大概率会问你 redis 的一些问题。比如:redis的常见数据类型及应用场景、redis是单线程为什么还这么快、 redis 和 memcached 的区别、redis 内存淘汰机制等等。
@@ -23,17 +45,16 @@
面试和工作是两回事,聪明的人会把面试官往自己擅长的领域领,其他人则被面试官牵着鼻子走。虽说面试和工作是两回事,但是你要想要获得自己满意的 offer ,你自身的实力必须要强。
-### 3 下面这几点你必须知道
+## 下面这几点你必须知道
-1. 大部分公司的HR都说我们不看重学历(骗你的!),但是如果你的学校不出众的话,很难在一堆简历中脱颖而出,除非你的简历上有特别的亮点,比如:某某大厂的实习经历、获得了某某大赛的奖等等。
+1. 大部分公司的HR都说我们不看重学历(骗你的!),但是如果你的学校不出众的话,很难在一堆简历中脱颖而出,除非你的简历上有特别的亮点,比如:某某大厂的实习经历、获得了某某大赛的奖等等。
2. **大部分应届生找工作的硬伤是没有工作经验或实习经历,所以如果你是应届生就不要错过秋招和春招。一旦错过,你后面就极大可能会面临社招,这个时候没有工作经验的你可能就会面临各种碰壁,导致找不到一个好的工作**
3. **写在简历上的东西一定要慎重,这是面试官大量提问的地方;**
-4. **将自己的项目经历完美的展示出来非常重要。**
-
-### 4 必须了解的两大法则
+4. **将自己的项目经历完美的展示出来非常重要。**
+## 必须了解的两大法则
-**①STAR法则(Situation Task Action Result):**
+### STAR法则(Situation Task Action Result)
- **Situation:** 事情是在什么情况下发生;
- **Task::** 你是如何明确你的任务的;
@@ -42,14 +63,7 @@
简而言之,STAR法则,就是一种讲述自己故事的方式,或者说,是一个清晰、条理的作文模板。不管是什么,合理熟练运用此法则,可以轻松的对面试官描述事物的逻辑方式,表现出自己分析阐述问题的清晰性、条理性和逻辑性。
-下面这段内容摘自百度百科,我觉得写的非常不错:
-
-> STAR法则,500强面试题回答时的技巧法则,备受面试者成功者和500强HR的推崇。
-由于这个法则被广泛应用于面试问题的回答,尽管我们还在写简历阶段,但是,写简历时能把面试的问题就想好,会使自己更加主动和自信,做到简历,面试关联性,逻辑性强,不至于在一个月后去面试,却把简历里的东西都忘掉了(更何况有些朋友会稍微夸大简历内容)
-在我们写简历时,每个人都要写上自己的工作经历,活动经历,想必每一个同学,都会起码花上半天甚至更长的时间去搜寻脑海里所有有关的经历,争取找出最好的东西写在简历上。
-但是此时,我们要注意了,简历上的任何一个信息点都有可能成为日后面试时的重点提问对象,所以说,不能只管写上让自己感觉最牛的经历就完事了,要想到今后,在面试中,你所写的经历万一被面试官问到,你真的能回答得流利,顺畅,且能通过这段经历,证明自己正是适合这个职位的人吗?
-
-**②FAB 法则(Feature Advantage Benefit):**
+### FAB 法则(Feature Advantage Benefit)
- **Feature:** 是什么;
- **Advantage:** 比别人好在哪些地方;
@@ -57,7 +71,7 @@
简单来说,这个法则主要是让你的面试官知道你的优势、招了你之后对公司有什么帮助。
-### 5 项目经历怎么写?
+## 项目经历怎么写?
简历上有一两个项目经历很正常,但是真正能把项目经历很好的展示给面试官的非常少。对于项目经历大家可以考虑从如下几点来写:
@@ -66,7 +80,8 @@
3. 从这个项目中你学会了那些东西,使用到了那些技术,学会了那些新技术的使用
4. 另外项目描述中,最好可以体现自己的综合素质,比如你是如何协调项目组成员协同开发的或者在遇到某一个棘手的问题的时候你是如何解决的又或者说你在这个项目用了什么技术实现了什么功能比如:用redis做缓存提高访问速度和并发量、使用消息队列削峰和降流等等。
-### 6 专业技能该怎么写?
+## 专业技能该怎么写?
+
先问一下你自己会什么,然后看看你意向的公司需要什么。一般HR可能并不太懂技术,所以他在筛选简历的时候可能就盯着你专业技能的关键词来看。对于公司有要求而你不会的技能,你可以花几天时间学习一下,然后在简历上可以写上自己了解这个技能。比如你可以这样写(下面这部分内容摘自我的简历,大家可以根据自己的情况做一些修改和完善):
- 计算机网络、数据结构、算法、操作系统等课内基础知识:掌握
@@ -79,28 +94,28 @@
- Zookeeper: 掌握
- 常见消息队列: 掌握
- Linux:掌握
-- MySQL常见优化手段:掌握
+- MySQL常见优化手段:掌握
- Spring Boot +Spring Cloud +Docker:了解
- Hadoop 生态相关技术中的 HDFS、Storm、MapReduce、Hive、Hbase :了解
- Python 基础、一些常见第三方库比如OpenCV、wxpy、wordcloud、matplotlib:熟悉
-### 7 开源程序员Markdown格式简历模板分享
+## 排版注意事项
-分享一个Github上开源的程序员简历模板。包括PHP程序员简历模板、iOS程序员简历模板、Android程序员简历模板、Web前端程序员简历模板、Java程序员简历模板、C/C++程序员简历模板、NodeJS程序员简历模板、架构师简历模板以及通用程序员简历模板 。
-Github地址:[https://github.com/geekcompany/ResumeSample](https://github.com/geekcompany/ResumeSample)
+1. 尽量简洁,不要太花里胡哨;
+2. 一些技术名词不要弄错了大小写比如MySQL不要写成mysql,Java不要写成Java。这个在我看来还是比较忌讳的,所以一定要注意这个细节;
+3. 中文和数字英文之间加上空格的话看起来会舒服一点;
+## 其他的一些小tips
-我的下面这篇文章讲了如何写一份Markdown格式的简历,另外,文中还提到了一种实现 Markdown 格式到PDF、HTML、JPEG这几种格式的转换方法。
-
-[手把手教你用Markdown写一份高质量的简历](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484347&idx=1&sn=a986ea7e199871999a5257bd3ed78be1&chksm=fd9855dacaefdccc2c5d5f8f79c4aa1b608ad5b42936bccaefb99a850a2e6e8e2e910e1b3153&token=719595858&lang=zh_CN#rd)
+1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。
+2. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。
+3. 如果自己的Github比较活跃的话,写上去也会为你加分很多。
+4. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容
+5. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。
+6. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。
+7. 简历最后最好能加上:“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的你会很有礼貌。
-### 8 其他的一些小tips
+## 推荐的工具/网站
-1. 尽量避免主观表述,少一点语义模糊的形容词,尽量要简洁明了,逻辑结构清晰。
-2. 注意排版(不需要花花绿绿的),尽量使用Markdown语法。
-3. 如果自己有博客或者个人技术栈点的话,写上去会为你加分很多。
-4. 如果自己的Github比较活跃的话,写上去也会为你加分很多。
-5. 注意简历真实性,一定不要写自己不会的东西,或者带有欺骗性的内容
-6. 项目经历建议以时间倒序排序,另外项目经历不在于多,而在于有亮点。
-7. 如果内容过多的话,不需要非把内容压缩到一页,保持排版干净整洁就可以了。
-8. 简历最后最好能加上:“感谢您花时间阅读我的简历,期待能有机会和您共事。”这句话,显的你会很有礼貌。
+- 冷熊简历(MarkDown在线简历工具,可在线预览、编辑和生成PDF):
+- Typora+[Java程序员简历模板](https://github.com/geekcompany/ResumeSample/blob/master/java.md)
diff --git "a/\351\235\242\350\257\225\345\277\205\345\244\207/\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"
similarity index 92%
rename from "\351\235\242\350\257\225\345\277\205\345\244\207/\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"
rename to "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"
index 422d9402f12..46996cdb3e9 100644
--- "a/\351\235\242\350\257\225\345\277\205\345\244\207/\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"
@@ -78,7 +78,7 @@
## 1. `System.out.println(3|9)`输出什么?
-正确答案:11.
+正确答案:11。
**考察知识点:&和&&;|和||**
@@ -110,10 +110,10 @@ 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:低.
+1. **从地址栏显示来说**:forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器。浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址。redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址。所以地址栏显示的是新的URL。
+2. **从数据共享来说**:forward:转发页面和转发到的页面可以共享request里面的数据。redirect:不能共享数据。
+3. **从运用地方来说**:forward:一般用于用户登陆的时候,根据角色转发到相应的模块。redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等。
+4. **从效率来说**:forward:高。redirect:低。
## 3. 在浏览器中输入url地址到显示主页的过程,整个过程会使用哪些协议
@@ -159,7 +159,7 @@ request.getRequestDispatcher("login_success.jsp").forward(request, response);
第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己接收正常,对方发送正常
-第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送接收正常
+第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常
所以三次握手就能确认双发收发功能都正常,缺一不可。
@@ -238,7 +238,7 @@ HTTP响应报文主要由状态行、响应头部、响应正文3部分组成
1. 避免 where 子句中对字段施加函数,这会造成无法命中索引。
2. 在使用InnoDB时使用与业务无关的自增主键作为主键,即使用逻辑主键,而不要使用业务主键。
3. 将打算加索引的列设置为 NOT NULL ,否则将导致引擎放弃使用索引而进行全表扫描
-4. 删除长期未使用的索引,不用的索引的存在会造成不必要的性能损耗 MySQL 5.7 可以通过查询 sys 库的 chema_unused_indexes 视图来查询哪些索引从未被使用
+4. 删除长期未使用的索引,不用的索引的存在会造成不必要的性能损耗 MySQL 5.7 可以通过查询 sys 库的 schema_unused_indexes 视图来查询哪些索引从未被使用
5. 在使用 limit offset 查询缓慢时,可以借助索引来提高性能
**Mysql索引主要使用的哪两种数据结构?**
@@ -382,7 +382,7 @@ TransactionDefinition 接口中定义了五个表示隔离级别的常量:

-客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler-> HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象->前端控制器 DispatcherServlet 渲染数据(Model)->将得到视图对象返回给用户
+客户端发送请求-> 前端控制器 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)
@@ -390,7 +390,7 @@ TransactionDefinition 接口中定义了五个表示隔离级别的常量:
过了秋招挺长一段时间了,说实话我自己也忘了如何简要概括 Spring AOP IOC 实现原理,就在网上找了一个较为简洁的答案,下面分享给各位。
-**IOC:** 控制反转也叫依赖注入。IOC利用java反射机制,AOP利用代理模式。IOC 概念看似很抽象,但是很容易理解。说简单点就是将对象交给容器管理,你只需要在spring配置文件中配置对应的bean以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类。
+**IOC:** 控制反转也叫依赖注入。IOC利用java反射机制,AOP利用代理模式。IOC 概念看似很抽象,但是很容易理解。说简单点就是将对象交给容器管理,你只需要在spring配置文件中配置对应的bean以及设置相关的属性,让spring容器来生成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置文件中配置的bean都初始化好,然后在你需要调用的时候,就把它已经初始化好的那些bean分配给你需要调用这些bean的类。
**AOP:** 面向切面编程。(Aspect-Oriented Programming) 。AOP可以说是对OOP的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。实现AOP的技术,主要分为两大类:一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码,属于静态代理。
@@ -421,7 +421,7 @@ TransactionDefinition 接口中定义了五个表示隔离级别的常量:
> **先来简单说一下分布式服务:**
-目前使用比较多的用来构建**SOA(Service Oriented Architecture面向服务体系结构)**的**分布式服务框架**是阿里巴巴开源的**Dubbo**.如果想深入了解Dubbo的可以看我写的关于Dubbo的这一篇文章:**《高性能优秀的服务框架-dubbo介绍》**:[https://juejin.im/post/5acadeb1f265da2375072f9c](https://juejin.im/post/5acadeb1f265da2375072f9c)
+目前使用比较多的用来构建**SOA(Service Oriented Architecture面向服务体系结构)**的**分布式服务框架**是阿里巴巴开源的**Dubbo**。如果想深入了解Dubbo的可以看我写的关于Dubbo的这一篇文章:**《高性能优秀的服务框架-dubbo介绍》**:[https://juejin.im/post/5acadeb1f265da2375072f9c](https://juejin.im/post/5acadeb1f265da2375072f9c)
> **再来谈我们的分布式消息队列:**
@@ -464,7 +464,7 @@ TransactionDefinition 接口中定义了五个表示隔离级别的常量:
### 1.4 关于消息队列其他一些常见的问题展望
-1. 引入消息队列之后如何保证高可用性
+1. 引入消息队列之后如何保证高可用性?
2. 如何保证消息不被重复消费呢?
3. 如何保证消息的可靠性传输(如何处理消息丢失的问题)?
4. 我该怎么保证从消息队列里拿到的数据按顺序执行?
@@ -478,7 +478,7 @@ TransactionDefinition 接口中定义了五个表示隔离级别的常量:
### 2.1 两者的对比
1. **count运算上的区别:** 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需要消耗多少资源的。而对于InnoDB来说,则没有这种缓存
-2. **是否支持事务和崩溃后的安全恢复:** MyISAM 强调的是性能,每次查询具有原子性,其执行数度比InnoDB类型更快,但是不提供事务支持。但是InnoDB 提供事务支持事务,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
+2. **是否支持事务和崩溃后的安全恢复:** MyISAM 强调的是性能,每次查询具有原子性,其执行速度比InnoDB类型更快,但是不提供事务支持。但是 InnoDB 提供事务支持,外部键等高级数据库功能。 具有事务(commit)、回滚(rollback)和崩溃修复能力(crash recovery capabilities)的事务安全(transaction-safe (ACID compliant))型表。
3. **是否支持外键:** MyISAM不支持,而InnoDB支持。
@@ -495,8 +495,8 @@ MyISAM更适合读密集的表,而InnoDB更适合写密集的的表。 在数
- **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) `方法)。
+- **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接口**
@@ -508,7 +508,7 @@ public interface RandomAccess {
查看源码我们发现实际上 RandomAccess 接口中什么都没有定义。所以,在我看来 RandomAccess 接口不过是一个标识罢了。标识什么? 标识实现这个接口的类具有随机访问功能。
-在binarySearch()方法中,它要判断传入的list 是否RamdomAccess的实例,如果是,调用indexedBinarySearch()方法,如果不是,那么调用iteratorBinarySearch()方法
+在 binarySearch() 方法中,它要判断传入的 list 是否RamdomAccess的实例,如果是,调用 indexedBinarySearch() 方法,如果不是,那么调用 iteratorBinarySearch() 方法
```java
public static
@@ -520,7 +520,7 @@ public interface RandomAccess {
}
```
-ArraysList 实现了 RandomAccess 接口, 而 LinkedList 没有实现。为什么呢?我觉得还是和底层数据结构有关!ArraysList 底层是数组,而 LinkedList 底层是链表。数组天然支持随机访问,时间复杂度为 O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问。,ArraysList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能。 RandomAccess 接口只是标识,并不是说 ArraysList 实现 RandomAccess 接口才具有快速随机访问功能的!
+ArraysList 实现了 RandomAccess 接口, 而 LinkedList 没有实现。为什么呢?我觉得还是和底层数据结构有关!ArraysList 底层是数组,而 LinkedList 底层是链表。数组天然支持随机访问,时间复杂度为 O(1) ,所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n) ,所以不支持快速随机访问。,ArraysList 实现了 RandomAccess 接口,就表明了他具有快速随机访问功能。 RandomAccess 接口只是标识,并不是说 ArraysList 实现 RandomAccess 接口才具有快速随机访问功能的!
@@ -614,9 +614,9 @@ TreeMap、TreeSet以及JDK1.8之后的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。
+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 没有这样的机制。
@@ -688,7 +688,7 @@ hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返
#### 1.2.3 hashCode()与equals()的相关规定
1. 如果两个对象相等,则hashcode一定也是相同的
-2. 两个对象相等,对两个对象分别调用equals方法都返回true
+2. 两个对象相等,对两个对象分别调用equals方法都返回true
3. 两个对象有相同的hashcode值,它们也不一定是相等的
4. **因此,equals方法被覆盖过,则hashCode方法也必须被覆盖**
5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
@@ -737,7 +737,7 @@ public class test1 {
**说明:**
-- String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
+- 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 这俩兄弟在一般只要面试中问到集合相关的问题就一定会被问到,所以各位务必引起重视!
@@ -749,13 +749,13 @@ public class test1 {
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,竞争会越来越激烈效率越低。
+- **实现线程安全的方式(重要):** ① **在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:
+Hashtable:

JDK1.7的ConcurrentHashMap:
@@ -772,7 +772,7 @@ Node: 链表节点):
**ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成**。
-Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。
+Segment 实现了 ReentrantLock,所以 Segment 是一种可重入锁,扮演锁的角色。HashEntry 用于存储键值对数据。
```java
static class Segment extends ReentrantLock implements Serializable {
@@ -787,29 +787,29 @@ ConcurrentHashMap取消了Segment分段锁,采用CAS和synchronized来保证
synchronized只锁定当前链表或红黑二叉树的首节点,这样只要hash不冲突,就不会产生并发,效率又提升N倍。
-## 3 谈谈 synchronized 和 ReenTrantLock 的区别
+## 3 谈谈 synchronized 和 ReentrantLock 的区别
**① 两者都是可重入锁**
两者都是可重入锁。“可重入锁”概念是:自己可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果不可锁重入的话,就会造成死锁。同一个线程每次获取锁,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
-**② synchronized 依赖于 JVM 而 ReenTrantLock 依赖于 API**
+**② synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API**
-synchronized 是依赖于 JVM 实现的,前面我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。ReenTrantLock 是 JDK 层面实现的(也就是 API 层面,需要 lock() 和 unlock 方法配合 try/finally 语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。
+synchronized 是依赖于 JVM 实现的,前面我们也讲到了 虚拟机团队在 JDK1.6 为 synchronized 关键字进行了很多优化,但是这些优化都是在虚拟机层面实现的,并没有直接暴露给我们。ReentrantLock 是 JDK 层面实现的(也就是 API 层面,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成),所以我们可以通过查看它的源代码,来看它是如何实现的。
-**③ ReenTrantLock 比 synchronized 增加了一些高级功能**
+**③ ReentrantLock 比 synchronized 增加了一些高级功能**
-相比synchronized,ReenTrantLock增加了一些高级功能。主要来说主要有三点:**①等待可中断;②可实现公平锁;③可实现选择性通知(锁可以绑定多个条件)**
+相比synchronized,ReentrantLock增加了一些高级功能。主要来说主要有三点:**①等待可中断;②可实现公平锁;③可实现选择性通知(锁可以绑定多个条件)**
-- **ReenTrantLock提供了一种能够中断等待锁的线程的机制**,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
-- **ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。** ReenTrantLock默认情况是非公平的,可以通过 ReenTrantLock类的`ReentrantLock(boolean fair)`构造方法来制定是否是公平的。
+- **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是一个不错的选择。
+如果你想使用上述功能,那么选择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操作。
+在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 线程池了解吗?
@@ -837,9 +837,9 @@ synchronized 是依赖于 JVM 实现的,前面我们也讲到了 虚拟机团
#### 各种线程池的适用场景介绍
- **FixedThreadPool:** 适用于为了满足资源管理需求,而需要限制当前线程数量的应用场景。它适用于负载比较重的服务器;
-- **SingleThreadExecutor:** 适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景。
+- **SingleThreadExecutor:** 适用于需要保证顺序地执行各个任务并且在任意时间点,不会有多个线程是活动的应用场景;
- **CachedThreadPool:** 适用于执行很多的短期异步任务的小程序,或者是负载较轻的服务器;
-- **ScheduledThreadPoolExecutor:** 适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程的数量的应用场景,
+- **ScheduledThreadPoolExecutor:** 适用于需要多个后台执行周期任务,同时为了满足资源管理需求而需要限制后台线程的数量的应用场景;
- **SingleThreadScheduledExecutor:** 适用于需要单个后台线程执行周期任务,同时保证顺序地执行各个任务的应用场景。
### 4.3 创建的线程池的方式
@@ -903,7 +903,7 @@ Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(I
谈到反向代理,就不得不提一下正向代理。无论是正向代理,还是反向代理,说到底,就是代理模式的衍生版本罢了
-- **正向代理:**某些情况下,代理我们用户去访问服务器,需要用户手动的设置代理服务器的ip和端口号。正向代理比较常见的一个例子就是 VPN了。
+- **正向代理:**某些情况下,代理我们用户去访问服务器,需要用户手动的设置代理服务器的ip和端口号。正向代理比较常见的一个例子就是 VPN 了。
- **反向代理:** 是用来代理服务器的,代理我们要访问的目标服务器。代理服务器接受请求,然后将请求转发给内部网络的服务器,并将从服务器上得到的结果返回给客户端,此时代理服务器对外就表现为一个服务器。
通过下面两幅图,大家应该更好理解(图源:http://blog.720ui.com/2016/nginx_action_05_proxy/):
@@ -920,7 +920,7 @@ Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(I
Nginx支持的weight轮询(默认)、ip_hash、fair、url_hash这四种负载均衡调度算法,感兴趣的可以自行查阅。
-负载均衡相比于反向代理更侧重的时将请求分担到多台服务器上去,所以谈论负载均衡只有在提供某服务的服务器大于两台时才有意义。
+负载均衡相比于反向代理更侧重的是将请求分担到多台服务器上去,所以谈论负载均衡只有在提供某服务的服务器大于两台时才有意义。
#### 动静分离
@@ -945,6 +945,6 @@ Nginx 有以下5个优点:
> 这部分内容参考极客时间—[Nginx核心知识100讲的内容](https://time.geekbang.org/course/intro/138?code=AycjiiQk6uQRxnVJzBupFkrGkvZlmYELPRsZbWzaAHE=)。
- Nginx 二进制可执行文件:由各模块源码编译出一个文件
-- Nginx.conf 配置文件:控制Nginx 行为
+- nginx.conf 配置文件:控制Nginx 行为
- acess.log 访问日志: 记录每一条HTTP请求信息
-- error.log 错误日志:定位问题
+- 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/BIO,NIO,AIO summary.md" b/docs/java/BIO-NIO-AIO.md
similarity index 99%
rename from "Java\347\233\270\345\205\263/BIO,NIO,AIO summary.md"
rename to docs/java/BIO-NIO-AIO.md
index c5ec6dddd04..b1e101d0539 100644
--- "a/Java\347\233\270\345\205\263/BIO,NIO,AIO summary.md"
+++ b/docs/java/BIO-NIO-AIO.md
@@ -42,7 +42,7 @@
- **阻塞:** 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
- **非阻塞:** 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
-举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在哪里傻等着水开(**同步阻塞**)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(**同步非阻塞**)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(**异步非阻塞**)。
+举个生活中简单的例子,你妈妈让你烧水,小时候你比较笨啊,在那里傻等着水开(**同步阻塞**)。等你稍微再长大一点,你知道每次烧水的空隙可以去干点其他事,然后只需要时不时来看看水开了没有(**同步非阻塞**)。后来,你们家用上了水开了会发出声音的壶,这样你就只需要听到响声后就知道水开了,在这期间你可以随便干自己的事情,你需要去倒水了(**异步非阻塞**)。
## 1. BIO (Blocking I/O)
@@ -73,7 +73,7 @@ BIO通信(一请求一应答)模型图如下(图源网络,原出处不明)
采用线程池和任务队列可以实现一种叫做伪异步的 I/O 通信框架,它的模型图如上图所示。当有新的客户端接入时,将客户端的 Socket 封装成一个Task(该任务实现java.lang.Runnable接口)投递到后端的线程池中进行处理,JDK 的线程池维护一个消息队列和 N 个活跃线程,对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。
-伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。不过因为它的底层任然是同步阻塞的BIO模型,因此无法从根本上解决问题。
+伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。不过因为它的底层仍然是同步阻塞的BIO模型,因此无法从根本上解决问题。
### 1.3 代码示例
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