diff --git a/.gitattributes b/.gitattributes
index 2ab2d3c5962..2f2cad2e13a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,4 @@
* text=auto
*.js linguist-language=java
*.css linguist-language=java
-*.html linguist-language=java
+*.html linguist-language=java
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 37cac6147d8..2dc9c784aa8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,38 +1,4 @@
-.gradle
-/build/
-/**/build/
-
-### STS ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-.sts4-cache
-
-### IntelliJ IDEA ###
-.idea
-*.iws
-*.iml
-*.ipr
-/out/
-/**/out/
-.shelf/
-.ideaDataSources/
-dataSources/
-
-### NetBeans ###
-/nbproject/private/
-/nbbuild/
-/dist/
-/nbdist/
-/.nb-gradle/
-/node_modules/
-
-### OS ###
-.DS_Store
-.Ds_Store´
/node_modules
-
-
+/package-lock.json
+/dist
+.DS_Store
diff --git a/.nojekyll b/.nojekyll
old mode 100644
new mode 100755
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index 261eeb9e9f8..00000000000
--- a/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
diff --git a/README.md b/README.md
old mode 100644
new mode 100755
index cf0186707a9..f8e670983e3
--- a/README.md
+++ b/README.md
@@ -1,438 +1,367 @@
-👉 [免费送阿里云服务器!双11白嫖阿里云2核2g服务器一年(这个服务器平时的价格是 1020/年)!速度上车!!!朋友们!我找阿里云的朋友要的专属福利(顺便帮他完成KPI)。点击这个链接,可以了解如何参与以及活动的相关说明。](https://t.1yb.co/Ewon)
-
-👉 如果你不知道该学习什么的话,请看 [Java 学习线路图是怎样的?]( https://zhuanlan.zhihu.com/p/379041500) (原创不易,欢迎点赞,精简版学习路线正在路上),这是 2021 最新最完善的 Java 学习路线!另外,[我的朋友整理了一份消息队列常见面试题,需要的小伙伴可以点击领取!](http://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100025985&idx=1&sn=681af486050fabbeea27fa1c3bec5d65&chksm=4ea1e94a79d6605c72f280b5268100c6e96c6ab1dc9a0178b33e25a72ff5f4eac3dcb56fa44f#rd)。
-
-👉 推荐 [在线阅读](https://snailclimb.gitee.io/javaguide) (Github 访问速度比较慢可能会导致部分图片无法刷新出来)
-
-👉 书单已经被移动到 [awesome-cs](https://github.com/CodingDocs/awesome-cs) 这个仓库。
-
-👉 [朋友开源的面试八股文系列](https://github.com/csguide-dabai/interview-guide)。
-
-> 1. **介绍**:关于 JavaGuide 的相关介绍请看:[关于 JavaGuide 的一些说明](https://www.yuque.com/snailclimb/dr6cvl/mr44yt) 。
-> 2. **贡献指南** :欢迎参与 [JavaGuide的维护工作](https://github.com/Snailclimb/JavaGuide/issues/1235),这是一件非常有意义的事情。
-> 3. **PDF版本** : [《JavaGuide 面试突击版》PDF 版本](#公众号) 。
-> 4. **图解计算机基础** :[图解计算机基础 PDF 下载](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd) 。
-> 5. **知识星球** : 简历指导/Java学习/面试指导/面试小册。欢迎加入[我的知识星球](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) 。
-> 6. **面试专版** :准备面试的小伙伴可以考虑面试专版:[《Java面试进阶指北 》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7) (质量很高,专为面试打造,星球用户免费)
-> 7. **转载须知** :以下所有文章如非文首说明皆为我(Guide哥)的原创,转载在文首注明出处,如发现恶意抄袭/搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!⛽️
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Sponsor
-
-
-
-
-
-
-
-
-
-
-
-
-## Java
-
-### 基础
-
-**知识点/面试题** : (必看:+1: )
-
-1. **[Java 基础知识](docs/java/basis/Java基础知识.md)**
-2. [Java 基础知识疑难点/易错点](docs/java/basis/Java基础知识疑难点.md)
-
-**重要知识点详解:**
-
-1. [枚举](docs/java/basis/用好Java中的枚举真的没有那么简单.md) (很重要的一个数据结构,用好枚举真的没有那么简单!)
-2. [Java 常见关键字总结:final、static、this、super!](docs/java/basis/Java常见关键字总结.md)
-3. [什么是反射机制?反射机制的应用场景有哪些?](docs/java/basis/反射机制.md)
-4. [代理模式详解:静态代理+JDK/CGLIB 动态代理实战](docs/java/basis/代理模式详解.md)
-5. [常见的 IO 模型有哪些?Java 中的 BIO、NIO、AIO 有啥区别?](docs/java/basis/IO模型.md)
-
-### 容器
-
-1. **[Java 容器常见问题总结](docs/java/collection/Java集合框架常见面试题.md)** (必看 :+1:)
-2. **源码分析** :[ArrayList 源码+扩容机制分析](docs/java/collection/ArrayList源码+扩容机制分析.md) 、[LinkedList 源码](docs/java/collection/LinkedList源码分析.md) 、[HashMap(JDK1.8)源码+底层数据结构分析]() 、[ConcurrentHashMap 源码+底层数据结构分析](docs/java/collection/ConcurrentHashMap源码+底层数据结构分析.md)
-3. [Java 容器使用注意事项总结](docs/java/collection/Java集合使用注意事项总结.md)
-
-### 并发
-
-**知识点/面试题:** (必看 :+1:)
-
-1. **[Java 并发基础常见面试题总结](docs/java/multi-thread/Java并发基础常见面试题总结.md)**
-2. **[Java 并发进阶常见面试题总结](docs/java/multi-thread/Java并发进阶常见面试题总结.md)**
-
-**重要知识点详解:**
-
-1. **线程池**:[Java 线程池学习总结](./docs/java/multi-thread/java线程池学习总结.md)、[拿来即用的线程池最佳实践](./docs/java/multi-thread/拿来即用的线程池最佳实践.md)
-2. [ ThreadLocal 关键字解析](docs/java/multi-thread/万字详解ThreadLocal关键字.md)
-3. [并发容器总结](docs/java/multi-thread/并发容器总结.md)
-4. [JUC 中的 Atomic 原子类总结](docs/java/multi-thread/Atomic原子类总结.md)
-5. [AQS 原理以及 AQS 同步组件总结](docs/java/multi-thread/AQS原理以及AQS同步组件总结.md)
-6. [CompletableFuture入门](docs/java/multi-thread/CompletableFuture入门.md)
-
-### JVM (必看 :+1:)
-
-JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html) 和周志明老师的[《深入理解Java虚拟机(第3版)》](https://book.douban.com/subject/34907497/) (强烈建议阅读多遍!)。
-
-1. **[Java 内存区域](docs/java/jvm/Java内存区域.md)**
-2. **[JVM 垃圾回收](docs/java/jvm/JVM垃圾回收.md)**
-3. [JDK 监控和故障处理工具](docs/java/jvm/JDK监控和故障处理工具总结.md)
-4. [类文件结构](docs/java/jvm/类文件结构.md)
-5. **[类加载过程](docs/java/jvm/类加载过程.md)**
-6. [类加载器](docs/java/jvm/类加载器.md)
-7. **[【待完成】最重要的 JVM 参数指南(翻译完善了一半)](docs/java/jvm/最重要的JVM参数指南.md)**
-9. **[【加餐】大白话带你认识 JVM](docs/java/jvm/[加餐]大白话带你认识JVM.md)**
-
-### 新特性
-
-1. **Java 8** :[Java 8 新特性总结](docs/java/new-features/Java8新特性总结.md)、[Java8常用新特性总结](docs/java/new-features/java8-common-new-features.md) 、[Java 8 学习资源推荐](docs/java/new-features/Java8教程推荐.md)、[Java8 forEach 指南](docs/java/new-features/Java8foreach指南.md)
-2. **Java9~Java15** : [一文带你看遍 JDK9~15 的重要新特性!](./docs/java/new-features/java新特性总结.md)
-
-### 小技巧
-
-1. [JAD 反编译](docs/java/tips/JAD反编译tricks.md)
-2. [手把手教你定位常见 Java 性能问题](./docs/java/tips/locate-performance-problems/手把手教你定位常见Java性能问题.md)
-
-## 计算机基础
-
-👉 **[图解计算机基础 PDF 下载](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd)** 。
-
-### 操作系统
-
-1. [操作系统常见问题总结!](docs/cs-basics/operating-system/basis.md)
-2. [后端程序员必备的 Linux 基础知识总结](docs/cs-basics/operating-system/linux.md)
-3. [Shell 编程入门](docs/cs-basics/operating-system/Shell.md)
-
-### 网络
-
-1. [计算机网络常见面试题](docs/cs-basics/network/计算机网络.md)
-2. [计算机网络基础知识总结](docs/cs-basics/network/计算机网络知识总结.md)
-
-### 数据结构
-
-**图解数据结构:**
-
-1. [线性数据结构 :数组、链表、栈、队列](docs/cs-basics/data-structure/线性数据结构.md)
-2. [图](docs/cs-basics/data-structure/图.md)
-3. [堆](docs/cs-basics/data-structure/堆.md)
-4. [树](docs/cs-basics/data-structure/树.md) :重点关注[红黑树](docs/cs-basics/data-structure/红黑树.md)、B-,B+,B*树、LSM树
-
-其他常用数据结构 :
-
-1. [布隆过滤器](docs/cs-basics/data-structure/bloom-filter.md)
-
-### 算法
-
-算法这部分内容非常重要,如果你不知道如何学习算法的话,可以看下我写的:
-
-- [算法学习书籍+资源推荐](https://www.zhihu.com/question/323359308/answer/1545320858) 。
-- [如何刷Leetcode?](https://www.zhihu.com/question/31092580/answer/1534887374)
-
-**常见算法问题总结** :
-
-- [几道常见的字符串算法题总结 ](docs/cs-basics/algorithms/几道常见的字符串算法题.md)
-- [几道常见的链表算法题总结 ](docs/cs-basics/algorithms/几道常见的链表算法题.md)
-- [剑指 offer 部分编程题](docs/cs-basics/algorithms/剑指offer部分编程题.md)
-
-另外,[GeeksforGeeks]( https://www.geeksforgeeks.org/fundamentals-of-algorithms/) 这个网站总结了常见的算法 ,比较全面系统。
-
-## 数据库
-
-### MySQL
-
-**总结:**
-
-1. [数据库基础知识总结](docs/database/数据库基础知识.md)
-2. **[MySQL知识点总结](docs/database/mysql/MySQL总结.md)** (必看 :+1:)
-3. [阿里巴巴开发手册数据库部分的一些最佳实践](docs/database/mysql/阿里巴巴开发手册数据库部分的一些最佳实践.md)
-4. [一千行 MySQL 学习笔记](docs/database/mysql/一千行MySQL学习笔记.md)
-5. [MySQL 高性能优化规范建议](docs/database/mysql/MySQL高性能优化规范建议.md)
-
-**重要知识点:**
-
-1. [MySQL数据库索引总结](docs/database/mysql/MySQL数据库索引.md)
-2. [事务隔离级别(图文详解)](docs/database/mysql/事务隔离级别(图文详解).md)
-3. [MySQL三大日志(binlog、redo log和undo log)详解](docs/database/mysql/MySQL三大日志.md)
-4. [InnoDB存储引擎对MVCC的实现](docs/database/mysql/InnoDB对MVCC的实现.md)
-5. [一条 SQL 语句在 MySQL 中如何执行的?](docs/database/mysql/一条sql语句在mysql中如何执行的.md)
-6. [字符集详解:为什么不建议在MySQL中使用 utf8 ?](docs/database/字符集.md)
-7. [关于数据库中如何存储时间的一点思考](docs/database/mysql/关于数据库存储时间的一点思考.md)
-
-### Redis
-
-2. [Redis 常见问题总结](docs/database/Redis/redis-all.md)
-3. [面试/工作必备!3种常用的缓存读写策略!](docs/database/Redis/3种常用的缓存读写策略.md)
-
-## 搜索引擎
-
-用于提高搜索效率,功能和浏览器搜索引擎类似。比较常见的搜索引擎是 Elasticsearch(推荐) 和 Solr。
-
-## 系统设计
-
-### 系统设计必备基础
-
-#### RESTful API
-
-我们在进行后端开发的时候,主要的工作就是为前端或者其他后端服务提供 API 比如查询用户数据的 API 。RESTful API 是一种基于 REST 构建的 API,它是一种被设计的更好使用的 API。
-
-相关阅读:[RestFul API 简明教程](docs/system-design/coding-way/RESTfulAPI简明教程.md)
-
-#### 命名
-
-编程过程中,一定要重视命名。因为好的命名即是注释,别人一看到你的命名就知道你的变量、方法或者类是做什么的!
-
-相关阅读: [Java 命名之道](docs/system-design/naming.md) 。
-
-### 常用框架
-
-如果你没有接触过 Java Web 开发的话,可以先看一下我总结的 [《J2EE 基础知识》](docs/java/J2EE基础知识.md) 。虽然,这篇文章中的很多内容已经淘汰,但是可以让你对 Java 后台技术发展有更深的认识。
-
-#### Spring/SpringBoot (必看 :+1:)
-
-**知识点/面试题:**
-
-1. **[Spring 常见问题总结](docs/system-design/framework/spring/Spring常见问题总结.md)**
-2. **[SpringBoot 入门指南](https://github.com/Snailclimb/springboot-guide)**
-
-**重要知识点详解:**
-
-1. **[Spring/Spring Boot 常用注解总结!安排!](./docs/system-design/framework/spring/SpringBoot+Spring常用注解总结.md)**
-2. **[Spring 事务总结](docs/system-design/framework/spring/Spring事务总结.md)**
-3. [Spring 中都用到了那些设计模式?](docs/system-design/framework/spring/Spring-Design-Patterns.md)
-4. **[SpringBoot 自动装配原理?”](https://www.cnblogs.com/javaguide/p/springboot-auto-config.html)**
-
-#### MyBatis
-
-- [MyBatis 常见面试题总结](docs/system-design/framework/mybatis/mybatis-interview.md)
-
-#### Netty (必看 :+1:)
-
-1. [剖析面试最常见问题之 Netty(上)](https://xiaozhuanlan.com/topic/4028536971)
-2. [剖析面试最常见问题之 Netty(下)](https://xiaozhuanlan.com/topic/3985146207)
-
-#### ZooKeeper
-
-> 前两篇文章可能有内容重合部分,推荐都看一遍。
-
-1. [【入门】ZooKeeper 相关概念总结](docs/system-design/distributed-system/zookeeper/zookeeper-intro.md)
-2. [【进阶】ZooKeeper 相关概念总结](docs/system-design/distributed-system/zookeeper/zookeeper-plus.md)
-3. [【实战】ZooKeeper 实战](docs/system-design/distributed-system/zookeeper/zookeeper-in-action.md)
-
-### 安全
-
-#### 认证授权
-
-**[《认证授权基础》](docs/system-design/authority-certification/basis-of-authority-certification.md)** 这篇文章中我会介绍认证授权常见概念: **Authentication**,**Authorization** 以及 **Cookie**、**Session**、Token、**OAuth 2**、**SSO** 。如果你不清楚这些概念的话,建议好好阅读一下这篇文章。
-
-- **JWT** :JWT(JSON Web Token)是一种身份认证的方式,JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。相关阅读:
- - [JWT 优缺点分析以及常见问题解决方案](docs/system-design/authority-certification/JWT优缺点分析以及常见问题解决方案.md)
- - [适合初学者入门 Spring Security With JWT 的 Demo](https://github.com/Snailclimb/spring-security-jwt-guide)
-
-- **SSO(单点登录)** :**SSO(Single Sign On)** 即单点登录说的是用户登陆多个子系统的其中一个就有权访问与其相关的其他系统。举个例子我们在登陆了京东金融之后,我们同时也成功登陆京东的京东超市、京东家电等子系统。相关阅读:[**SSO 单点登录看这篇就够了!**](docs/system-design/authority-certification/SSO单点登录看这一篇就够了.md)
-
-#### 数据脱敏
-
-数据脱敏说的就是我们根据特定的规则对敏感信息数据进行变形,比如我们把手机号、身份证号某些位数使用 * 来代替。
-
-### 定时任务
-
-最近有朋友问到定时任务相关的问题。于是,我简单写了一篇文章总结一下定时任务的一些概念以及一些常见的定时任务技术选型:[《Java定时任务大揭秘》](./docs/system-design/Java定时任务大揭秘.md)
-
-### 分布式
-
-#### CAP 理论和 BASE 理论
-
-CAP 也就是 Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性) 这三个单词首字母组合。关于 CAP 的详细解读请看:[《CAP理论解读》](docs/system-design/distributed-system/CAP理论.md)。
-
-**BASE** 是 **Basically Available(基本可用)** 、**Soft-state(软状态)** 和 **Eventually Consistent(最终一致性)** 三个短语的缩写。BASE 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。关于 BASE 的详细解读请看:[《BASE理论解读》](docs/system-design/distributed-system/BASE理论.md)。
-
-#### Paxos 算法和 Raft 算法
-
-**Paxos 算法**诞生于 1990 年,这是一种解决分布式系统一致性的经典算法 。但是,由于 Paxos 算法非常难以理解和实现,不断有人尝试简化这一算法。到了2013 年才诞生了一个比 Paxos 算法更易理解和实现的分布式一致性算法—**Raft 算法**。
-
-#### RPC
-
-RPC 让调用远程服务调用像调用本地方法那样简单。
-
-Dubbo 是一款国产的 RPC 框架,由阿里开源。相关阅读:
-
-- [Dubbo 常见问题总结](docs/system-design/distributed-system/rpc/Dubbo.md)
-- [服务之间的调用为啥不直接用 HTTP 而用 RPC?](docs/system-design/distributed-system/rpc/服务之间的调用为啥不直接用HTTP而用RPC.md)
-
-#### API 网关
-
-网关主要用于请求转发、安全认证、协议转换、容灾。
-
-相关阅读:
-
-- [为什么要网关?你知道有哪些常见的网关系统?](docs/system-design/distributed-system/api-gateway/api网关入门.md)
-- [百亿规模API网关服务Shepherd的设计与实现](https://tech.meituan.com/2021/05/20/shepherd-api-gateway.html)
-
-#### 分布式 id
-
-在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。比如数据量太大之后,往往需要对数据进行分库分表,分库分表后需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 显然不能满足需求。相关阅读:[为什么要分布式 id ?分布式 id 生成方案有哪些?](docs/system-design/distributed/分布式ID.md)
-
-#### 分布式事务
-
-**分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。**
-
-简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
-
-### 微服务
-
-1. [ 大白话入门 Spring Cloud](docs/system-design/micro-service/spring-cloud.md)
-2. [微服务/分布式大厂真实面试问题解答](https://xiaozhuanlan.com/topic/2895047136)
-
-### 高性能
-
-#### 消息队列
-
-消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](docs/system-design/distributed-system/message-queue/message-queue.md)。
-
-1. **RabbitMQ** : [RabbitMQ 入门](docs/system-design/distributed-system/message-queue/RabbitMQ入门看这一篇就够了.md)
-2. **RocketMQ** : [RocketMQ 入门](docs/system-design/distributed-system/message-queue/RocketMQ.md)、[RocketMQ 的几个简单问题与答案](docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md)
-3. **Kafka** :[Kafka 常见问题总结](docs/system-design/distributed-system/message-queue/Kafka常见面试题总结.md)
-
-#### 读写分离&分库分表
-
-读写分离主要是为了将数据库的读和写操作分不到不同的数据库节点上。主服务器负责写,从服务器负责读。另外,一主一从或者一主多从都可以。
-
-读写分离可以大幅提高读性能,小幅提高写的性能。因此,读写分离更适合单机并发读请求比较多的场景。
-
-分库分表是为了解决由于库、表数据量过大,而导致数据库性能持续下降的问题。
-
-常见的分库分表工具有:`sharding-jdbc`(当当)、`TSharding`(蘑菇街)、`MyCAT`(基于 Cobar)、`Cobar`(阿里巴巴)...。 推荐使用 `sharding-jdbc`。 因为,`sharding-jdbc` 是一款轻量级 `Java` 框架,以 `jar` 包形式提供服务,不要我们做额外的运维工作,并且兼容性也很好。
-
-相关阅读: [读写分离&分库分表常见问题总结](docs/system-design/读写分离&分库分表.md)
-
-#### 负载均衡
-
-负载均衡系统通常用于将任务比如用户请求处理分配到多个服务器处理以提高网站、应用或者数据库的性能和可靠性。
-
-常见的负载均衡系统包括 3 种:
-
-1. **DNS 负载均衡** :一般用来实现地理级别的均衡。
-2. **硬件负载均衡** : 通过单独的硬件设备比如 F5 来实现负载均衡功能(硬件的价格一般很贵)。
-3. **软件负载均衡** :通过负载均衡软件比如 Nginx 来实现负载均衡功能。
-
-### 高可用
-
-高可用描述的是一个系统在大部分时间都是可用的,可以为我们提供服务的。高可用代表系统即使在发生硬件故障或者系统升级的时候,服务仍然是可用的 。
-
-相关阅读: **《[如何设计一个高可用系统?要考虑哪些地方?](docs/system-design/high-availability/如何设计一个高可用系统要考虑哪些地方.md)》** 。
-
-#### 限流
-
-限流是从用户访问压力的角度来考虑如何应对系统故障。
-
-限流为了对服务端的接口接受请求的频率进行限制,防止服务挂掉。比如某一接口的请求限制为 100 个每秒, 对超过限制的请求放弃处理或者放到队列中等待处理。限流可以有效应对突发请求过多。相关阅读:[限流算法有哪些?](docs/system-design/high-availability/limit-request.md)
-
-#### 降级
-
-降级是从系统功能优先级的角度考虑如何应对系统故障。
-
-服务降级指的是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
-
-#### 熔断
-
-熔断和降级是两个比较容易混淆的概念,两者的含义并不相同。
-
-降级的目的在于应对系统自身的故障,而熔断的目的在于应对当前系统依赖的外部系统或者第三方系统的故障。
-
-#### 排队
-
-另类的一种限流,类比于现实世界的排队。玩过英雄联盟的小伙伴应该有体会,每次一有活动,就要经历一波排队才能进入游戏。
-
-#### 集群
-
-相同的服务部署多份,避免单点故障。
-
-#### 超时和重试机制
-
-**一旦用户的请求超过某个时间得不到响应就结束此次请求并抛出异常。** 如果不进行超时设置可能会导致请求响应速度慢,甚至导致请求堆积进而让系统无法在处理请求。
-
-另外,重试的次数一般设为 3 次,再多次的重试没有好处,反而会加重服务器压力(部分场景使用失败重试机制会不太适合)。
-
-#### 灾备设计和异地多活
-
-**灾备** = 容灾+备份。
-
-- **备份** : 将系统所产生的的所有重要数据多备份几份。
-- **容灾** : 在异地建立两个完全相同的系统。当某个地方的系统突然挂掉,整个应用系统可以切换到另一个,这样系统就可以正常提供服务了。
-
-**异地多活** 描述的是将服务部署在异地并且服务同时对外提供服务。和传统的灾备设计的最主要区别在于“多活”,即所有站点都是同时在对外提供服务的。异地多活是为了应对突发状况比如火灾、地震等自然或者认为灾害。
-
-相关阅读:
-
-- [搞懂异地多活,看这篇就够了](https://mp.weixin.qq.com/s/T6mMDdtTfBuIiEowCpqu6Q)
-- [四步构建异地多活](https://mp.weixin.qq.com/s/hMD-IS__4JE5_nQhYPYSTg)
-- [《从零开始学架构》— 28 | 业务高可用的保障:异地多活架构](http://gk.link/a/10pKZ)
-
-### 大型网站架构
-
-- [8 张图读懂大型网站技术架构](docs/system-design/website-architecture/8%20张图读懂大型网站技术架构.md)
-- [关于大型网站系统架构你不得不懂的 10 个问题](docs/system-design/website-architecture/关于大型网站系统架构你不得不懂的10个问题.md)
-
-## 工具
-
-2. **Git** :[Git 入门](docs/tools/Git.md)
-3. **Github** : [Github小技巧](docs/tools/Github技巧.md)
-4. **Docker** : [Docker 基本概念解读](docs/tools/Docker.md) 、[Docker从入门到上手干事](docs/tools/Docker从入门到实战.md)
-5. **IDEA** :[IntelliJ IDEA 使用指南 | 必备插件推荐 | 插件开发入门 | 重构小技巧 | 源码阅读技巧](https://github.com/CodingDocs/awesome-idea-tutorial)。
-
-## Java 学习常见问题汇总
-
-1. [2021最新 Java 学习路线!凎!](https://www.zhihu.com/question/56110328/answer/869069586)
-2. [Java 培训四个月能学会吗?](docs/questions/java-training-4-month.md)
-3. [新手学习 Java,有哪些 Java 相关的博客,专栏,和技术学习网站推荐?](docs/questions/java-learning-website-blog.md)
-4. [Java 还是大数据,你需要了解这些东西!](docs/questions/java-big-data.md)
-
----
-
-## 其他
-
-### 贡献者
-
-[你可以点此链接查看JavaGuide的所有贡献者。](https://github.com/Snailclimb/JavaGuide/graphs/contributors) 感谢你们让 JavaGuide 变得更好!如果你们来到武汉一定要找我,我请你们吃饭玩耍。
-
-*悄悄话:JavaGuide 会不定时为贡献者们送福利。*
-
-### 待办
-
-- [ ] 计算机网络知识点完善
-- [ ] 分布式常见理论和算法总结完善
-
-### 捐赠支持
-
-项目的发展离不开你的支持,如果 JavaGuide 帮助到了你找到自己满意的 offer,请作者喝杯咖啡吧 ☕ 后续会继续完善更新!加油!
-
-[点击捐赠支持作者](https://www.yuque.com/snailclimb/dr6cvl/mr44yt#vu3ok)
-
-### 联系我
-
-
-
-整理了一份各个技术的学习路线,需要的小伙伴加我微信:“**JavaGuide1996**”备注“**Github-学习路线**”即可!
-
-
-
-### 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号“**JavaGuide**”。
-
-**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V4.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可领取!
-
-
+👏 重大更新!!!重磅!
+
+- JavaGuide 在线阅读版(新版,推荐👍):https://javaguide.cn/
+- JavaGuide 在线阅读版(老版):https://snailclimb.gitee.io/javaguide/#/
+
+👉 [朋友开源的面试八股文系列](https://github.com/csguide-dabai/interview-guide)。
+
+> 1. **介绍**:关于 JavaGuide 的相关介绍请看:[关于 JavaGuide 的一些说明](https://www.yuque.com/snailclimb/dr6cvl/mr44yt) 。
+> 2. **贡献指南** :欢迎参与 [JavaGuide的维护工作](https://github.com/Snailclimb/JavaGuide/issues/1235),这是一件非常有意义的事情。
+> 3. **PDF版本** : [《JavaGuide 面试突击版》PDF 版本](#公众号) 。
+> 4. **图解计算机基础** :[图解计算机基础 PDF 下载](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd) 。
+> 5. **知识星球** : 简历指导/Java学习/面试指导/面试小册。欢迎加入[我的知识星球](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) 。
+> 6. **面试专版** :准备面试的小伙伴可以考虑面试专版:[《Java面试进阶指北 》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7) (质量很高,专为面试打造,星球用户免费)
+> 7. **转载须知** :以下所有文章如非文首说明皆为我(Guide哥)的原创,转载在文首注明出处,如发现恶意抄袭/搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!⛽️
+
+
+
+
+
+
+
+
+
+
+
+
+Sponsor
+
+
+
+
+
+
+
+
+
+
+
+
+## Java
+
+### 基础
+
+**知识点/面试题** : (必看:+1: ):[Java 基础知识点/面试题总结](docs/java/basis/java基础知识总结.md)
+
+**重要知识点详解:**
+
+- [什么是反射机制?反射机制的应用场景有哪些?](docs/java/basis/反射机制详解.md)
+- [代理模式详解:静态代理+JDK/CGLIB 动态代理实战](docs/java/basis/代理模式详解.md)
+- [常见的 IO 模型有哪些?Java 中的 BIO、NIO、AIO 有啥区别?](docs/java/basis/java基础知识总结)
+
+### 集合
+
+1. **[Java 集合常见问题总结](docs/java/collection/java集合框架基础知识&面试题总结.md)** (必看 :+1:)
+2. [Java 容器使用注意事项总结](docs/java/collection/java集合使用注意事项总结.md)
+3. **源码分析** :[ArrayList 源码+扩容机制分析](docs/java/collection/arraylist-source-code.md) 、[HashMap(JDK1.8)源码+底层数据结构分析](docs/java/collection/hashmap-source-code.md) 、[ConcurrentHashMap 源码+底层数据结构分析](docs/java/collection/concurrent-hash-map-source-code.md)
+
+### 并发
+
+**知识点/面试题:** (必看 :+1:)
+
+1. **[Java 并发基础常见面试题总结](docs/java/concurrent/java并发基础常见面试题总结.md)**
+2. **[Java 并发进阶常见面试题总结](docs/java/concurrent/java并发进阶常见面试题总结.md)**
+
+**重要知识点详解:**
+
+1. **线程池**:[Java 线程池学习总结](./docs/java/concurrent/java线程池学习总结.md)、[拿来即用的 Java 线程池最佳实践](./docs/java/concurrent/拿来即用的java线程池最佳实践.md)
+2. [ThreadLocal 关键字解析](docs/java/concurrent/threadlocal.md)
+3. [Java 并发容器总结](docs/java/concurrent/并发容器总结.md)
+4. [Atomic 原子类总结](docs/java/concurrent/atomic原子类总结.md)
+5. [AQS 原理以及 AQS 同步组件总结](docs/java/concurrent/aqs原理以及aqs同步组件总结.md)
+6. [CompletableFuture入门](docs/java/concurrent/completablefuture-intro.md)
+
+### JVM (必看 :+1:)
+
+JVM 这部分内容主要参考 [JVM 虚拟机规范-Java8 ](https://docs.oracle.com/javase/specs/jvms/se8/html/index.html) 和周志明老师的[《深入理解Java虚拟机(第3版)》](https://book.douban.com/subject/34907497/) (强烈建议阅读多遍!)。
+
+1. **[Java 内存区域](docs/java/jvm/内存区域.md)**
+2. **[JVM 垃圾回收](docs/java/jvm/jvm垃圾回收.md)**
+3. [JDK 监控和故障处理工具](docs/java/jvm/jdk监控和故障处理工具总结.md)
+4. [类文件结构](docs/java/jvm/类文件结构.md)
+5. **[类加载过程](docs/java/jvm/类加载过程.md)**
+6. [类加载器](docs/java/jvm/类加载器.md)
+7. **[【待完成】最重要的 JVM 参数总结(翻译完善了一半)](docs/java/jvm/jvm参数指南.md)**
+9. **[【加餐】大白话带你认识 JVM](docs/java/jvm/[加餐]大白话带你认识jvm.md)**
+
+### 新特性
+
+1. **Java 8** :[Java 8 新特性总结](docs/java/new-features/Java8新特性总结.md)、[Java8常用新特性总结](docs/java/new-features/java8-common-new-features.md)
+2. **Java9~Java15** : [一文带你看遍 JDK9~15 的重要新特性!](./docs/java/new-features/java新特性总结.md)
+
+### 小技巧
+
+1. [JAD 反编译](docs/java/tips/JAD反编译tricks.md)
+2. [手把手教你定位常见 Java 性能问题](./docs/java/tips/locate-performance-problems/手把手教你定位常见Java性能问题.md)
+
+## 计算机基础
+
+👉 **[图解计算机基础 PDF 下载](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd)** 。
+
+### 操作系统
+
+1. [操作系统常见问题总结!](docs/cs-basics/operating-system/basis.md)
+2. [后端程序员必备的 Linux 基础知识总结](docs/cs-basics/operating-system/linux.md)
+3. [Shell 编程入门](docs/cs-basics/operating-system/Shell.md)
+
+### 网络
+
+1. [计算机网络常见面试题](docs/cs-basics/network/计算机网络.md)
+2. [计算机网络基础知识总结](docs/cs-basics/network/计算机网络知识总结.md)
+
+### 数据结构
+
+**图解数据结构:**
+
+1. [线性数据结构 :数组、链表、栈、队列](docs/cs-basics/data-structure/线性数据结构.md)
+2. [图](docs/cs-basics/data-structure/图.md)
+3. [堆](docs/cs-basics/data-structure/堆.md)
+4. [树](docs/cs-basics/data-structure/树.md) :重点关注[红黑树](docs/cs-basics/data-structure/红黑树.md)、B-,B+,B*树、LSM树
+
+其他常用数据结构 :
+
+1. [布隆过滤器](docs/cs-basics/data-structure/bloom-filter.md)
+
+### 算法
+
+算法这部分内容非常重要,如果你不知道如何学习算法的话,可以看下我写的:
+
+- [算法学习书籍+资源推荐](https://www.zhihu.com/question/323359308/answer/1545320858) 。
+- [如何刷Leetcode?](https://www.zhihu.com/question/31092580/answer/1534887374)
+
+**常见算法问题总结** :
+
+- [几道常见的字符串算法题总结 ](docs/cs-basics/algorithms/几道常见的字符串算法题.md)
+- [几道常见的链表算法题总结 ](docs/cs-basics/algorithms/几道常见的链表算法题.md)
+- [剑指 offer 部分编程题](docs/cs-basics/algorithms/剑指offer部分编程题.md)
+
+另外,[GeeksforGeeks]( https://www.geeksforgeeks.org/fundamentals-of-algorithms/) 这个网站总结了常见的算法 ,比较全面系统。
+
+## 数据库
+
+### MySQL
+
+**总结:**
+
+1. [数据库基础知识总结](docs/database/数据库基础知识.md)
+2. **[MySQL知识点总结](docs/database/mysql/mysql知识点&面试题总结.md)** (必看 :+1:)
+4. [一千行 MySQL 学习笔记](docs/database/mysql/a-thousand-lines-of-mysql-study-notes.md)
+5. [MySQL 高性能优化规范建议](docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md)
+
+**重要知识点:**
+
+1. [MySQL数据库索引总结](docs/database/mysql/mysql-index.md)
+2. [事务隔离级别(图文详解)](docs/database/mysql/transaction-isolation-level.md)
+3. [MySQL三大日志(binlog、redo log和undo log)详解](docs/database/mysql/mysql-logs.md)
+4. [InnoDB存储引擎对MVCC的实现](docs/database/mysql/innodb-implementation-of-mvcc.md)
+5. [一条 SQL 语句在 MySQL 中如何被执行的?](docs/database/mysql/how-sql-executed-in-mysql.md)
+6. [字符集详解:为什么不建议在MySQL中使用 utf8 ?](docs/database/字符集.md)
+7. [关于数据库中如何存储时间的一点思考](docs/database/mysql/some-thoughts-on-database-storage-time.md)
+
+### Redis
+
+1. [Redis 常见问题总结](docs/database/redis/redis-all.md)
+2. [3种常用的缓存读写策略](docs/database/redis/3-commonly-used-cache-read-and-write-strategies.md)
+
+## 搜索引擎
+
+用于提高搜索效率,功能和浏览器搜索引擎类似。比较常见的搜索引擎是 Elasticsearch(推荐) 和 Solr。
+
+## 系统设计
+
+### 系统设计必备基础
+
+#### RESTful API
+
+我们在进行后端开发的时候,主要的工作就是为前端或者其他后端服务提供 API 比如查询用户数据的 API 。RESTful API 是一种基于 REST 构建的 API,它是一种被设计的更好使用的 API。
+
+相关阅读:[RestFul API 简明教程](docs/system-design/basis/RESTfulAPI.md)
+
+#### 命名
+
+编程过程中,一定要重视命名。因为好的命名即是注释,别人一看到你的命名就知道你的变量、方法或者类是做什么的!
+
+相关阅读: [Java 命名之道](docs/system-design/naming.md) 。
+
+### 常用框架
+
+如果你没有接触过 Java Web 开发的话,可以先看一下我总结的 [《J2EE 基础知识》](docs/system-design/J2EE基础知识.md) 。虽然,这篇文章中的很多内容已经淘汰,但是可以让你对 Java 后台技术发展有更深的认识。
+
+#### Spring/SpringBoot (必看 :+1:)
+
+**知识点/面试题:**
+
+1. **[Spring 常见问题总结](docs/system-design/framework/spring/Spring常见问题总结.md)**
+2. **[SpringBoot 入门指南](https://github.com/Snailclimb/springboot-guide)**
+
+**重要知识点详解:**
+
+1. **[Spring/Spring Boot 常用注解总结!安排!](./docs/system-design/framework/spring/Spring&SpringBoot常用注解总结.md)**
+2. **[Spring 事务总结](docs/system-design/framework/spring/Spring事务总结.md)**
+3. [Spring 中都用到了那些设计模式?](docs/system-design/framework/spring/Spring设计模式总结.md)
+4. **[SpringBoot 自动装配原理?”](docs/system-design/framework/spring/SpringBoot自动装配原理.md)**
+
+#### MyBatis
+
+[MyBatis 常见面试题总结](docs/system-design/framework/mybatis/mybatis-interview.md)
+
+#### Spring Cloud
+
+[ 大白话入门 Spring Cloud](docs/system-design/framework/springcloud/springcloud-intro.md)
+
+### 安全
+
+#### 认证授权
+
+**[《认证授权基础》](docs/system-design/security/basis-of-authority-certification.md)** 这篇文章中我会介绍认证授权常见概念: **Authentication**,**Authorization** 以及 **Cookie**、**Session**、Token、**OAuth 2**、**SSO** 。如果你不清楚这些概念的话,建议好好阅读一下这篇文章。
+
+- **JWT** :JWT(JSON Web Token)是一种身份认证的方式,JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。相关阅读:
+ - [JWT 优缺点分析以及常见问题解决方案](docs/system-design/security/jwt优缺点分析以及常见问题解决方案.md)
+ - [适合初学者入门 Spring Security With JWT 的 Demo](https://github.com/Snailclimb/spring-security-jwt-guide)
+
+- **SSO(单点登录)** :**SSO(Single Sign On)** 即单点登录说的是用户登陆多个子系统的其中一个就有权访问与其相关的其他系统。举个例子我们在登陆了京东金融之后,我们同时也成功登陆京东的京东超市、京东家电等子系统。相关阅读:[**SSO 单点登录看这篇就够了!**](docs/system-design/security/sso-intro.md)
+
+#### 数据脱敏
+
+数据脱敏说的就是我们根据特定的规则对敏感信息数据进行变形,比如我们把手机号、身份证号某些位数使用 * 来代替。
+
+### 定时任务
+
+最近有朋友问到定时任务相关的问题。于是,我简单写了一篇文章总结一下定时任务的一些概念以及一些常见的定时任务技术选型:[《Java定时任务大揭秘》](./docs/system-design/定时任务.md)
+
+## 分布式
+
+### CAP 理论和 BASE 理论
+
+CAP 也就是 Consistency(一致性)、Availability(可用性)、Partition Tolerance(分区容错性) 这三个单词首字母组合。
+
+**BASE** 是 **Basically Available(基本可用)** 、**Soft-state(软状态)** 和 **Eventually Consistent(最终一致性)** 三个短语的缩写。BASE 理论是对 CAP 中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。
+
+相关阅读:[CAP 理论和 BASE 理论解读](docs/distributed-system/理论&算法/cap&base理论.md)
+
+### Paxos 算法和 Raft 算法
+
+**Paxos 算法**诞生于 1990 年,这是一种解决分布式系统一致性的经典算法 。但是,由于 Paxos 算法非常难以理解和实现,不断有人尝试简化这一算法。到了2013 年才诞生了一个比 Paxos 算法更易理解和实现的分布式一致性算法—**Raft 算法**。
+
+### RPC
+
+RPC 让调用远程服务调用像调用本地方法那样简单。
+
+Dubbo 是一款国产的 RPC 框架,由阿里开源。相关阅读:
+
+- [Dubbo 常见问题总结](docs/distributed-system/rpc/dubbo.md)
+- [服务之间的调用为啥不直接用 HTTP 而用 RPC?](docs/distributed-system/rpc/why-use-rpc.md)
+
+### API 网关
+
+网关主要用于请求转发、安全认证、协议转换、容灾。
+
+相关阅读:
+
+- [为什么要网关?你知道有哪些常见的网关系统?](docs/distributed-system/api-gateway.md)
+- [百亿规模API网关服务Shepherd的设计与实现](https://tech.meituan.com/2021/05/20/shepherd-api-gateway.html)
+
+### 分布式 id
+
+在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识。比如数据量太大之后,往往需要对数据进行分库分表,分库分表后需要有一个唯一 ID 来标识一条数据或消息,数据库的自增 ID 显然不能满足需求。相关阅读:[为什么要分布式 id ?分布式 id 生成方案有哪些?](docs/distributed-system/distributed-id.md)
+
+### 分布式事务
+
+**分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。**
+
+简单的说,就是一次大的操作由不同的小操作组成,这些小的操作分布在不同的服务器上,且属于不同的应用,分布式事务需要保证这些小操作要么全部成功,要么全部失败。本质上来说,分布式事务就是为了保证不同数据库的数据一致性。
+
+### 分布式协调
+
+**ZooKeeper** :
+
+> 前两篇文章可能有内容重合部分,推荐都看一遍。
+
+1. [【入门】ZooKeeper 相关概念总结](docs/distributed-system/分布式协调/zookeeper/zookeeper-intro.md)
+2. [【进阶】ZooKeeper 相关概念总结](docs/distributed-system/分布式协调/zookeeper/zookeeper-plus.md)
+3. [【实战】ZooKeeper 实战](docs/distributed-system/分布式协调/zookeeper/zookeeper-in-action.md)
+
+## 高性能
+
+### 消息队列
+
+消息队列在分布式系统中主要是为了解耦和削峰。相关阅读: [消息队列常见问题总结](docs/high-performance/message-queue/message-queue.md)。
+
+1. **RabbitMQ** : [RabbitMQ 入门](docs/high-performance/message-queue/rabbitmq-intro.md)
+2. **RocketMQ** : [RocketMQ 入门](docs/high-performance/message-queue/rocketmq-intro)、[RocketMQ 的几个简单问题与答案](docs/high-performance/message-queue/rocketmq-questions.md)
+3. **Kafka** :[Kafka 常见问题总结](docs/high-performance/message-queue/kafka知识点&面试题总结.md)
+
+### 读写分离&分库分表
+
+读写分离主要是为了将数据库的读和写操作分不到不同的数据库节点上。主服务器负责写,从服务器负责读。另外,一主一从或者一主多从都可以。
+
+读写分离可以大幅提高读性能,小幅提高写的性能。因此,读写分离更适合单机并发读请求比较多的场景。
+
+分库分表是为了解决由于库、表数据量过大,而导致数据库性能持续下降的问题。
+
+常见的分库分表工具有:`sharding-jdbc`(当当)、`TSharding`(蘑菇街)、`MyCAT`(基于 Cobar)、`Cobar`(阿里巴巴)...。 推荐使用 `sharding-jdbc`。 因为,`sharding-jdbc` 是一款轻量级 `Java` 框架,以 `jar` 包形式提供服务,不要我们做额外的运维工作,并且兼容性也很好。
+
+相关阅读: [读写分离&分库分表常见问题总结](docs/high-performance/读写分离&分库分表.md)
+
+### 负载均衡
+
+负载均衡系统通常用于将任务比如用户请求处理分配到多个服务器处理以提高网站、应用或者数据库的性能和可靠性。
+
+常见的负载均衡系统包括 3 种:
+
+1. **DNS 负载均衡** :一般用来实现地理级别的均衡。
+2. **硬件负载均衡** : 通过单独的硬件设备比如 F5 来实现负载均衡功能(硬件的价格一般很贵)。
+3. **软件负载均衡** :通过负载均衡软件比如 Nginx 来实现负载均衡功能。
+
+## 高可用
+
+高可用描述的是一个系统在大部分时间都是可用的,可以为我们提供服务的。高可用代表系统即使在发生硬件故障或者系统升级的时候,服务仍然是可用的 。
+
+相关阅读: **《[如何设计一个高可用系统?要考虑哪些地方?](docs/high-availability/高可用系统设计.md)》** 。
+
+### 限流
+
+限流是从用户访问压力的角度来考虑如何应对系统故障。
+
+限流为了对服务端的接口接受请求的频率进行限制,防止服务挂掉。比如某一接口的请求限制为 100 个每秒, 对超过限制的请求放弃处理或者放到队列中等待处理。限流可以有效应对突发请求过多。相关阅读:[何为限流?限流算法有哪些?](docs/high-availability/limit-request.md)
+
+### 降级
+
+降级是从系统功能优先级的角度考虑如何应对系统故障。
+
+服务降级指的是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
+
+### 熔断
+
+熔断和降级是两个比较容易混淆的概念,两者的含义并不相同。
+
+降级的目的在于应对系统自身的故障,而熔断的目的在于应对当前系统依赖的外部系统或者第三方系统的故障。
+
+### 排队
+
+另类的一种限流,类比于现实世界的排队。玩过英雄联盟的小伙伴应该有体会,每次一有活动,就要经历一波排队才能进入游戏。
+
+### 集群
+
+相同的服务部署多份,避免单点故障。
+
+### 超时和重试机制
+
+**一旦用户的请求超过某个时间得不到响应就结束此次请求并抛出异常。** 如果不进行超时设置可能会导致请求响应速度慢,甚至导致请求堆积进而让系统无法在处理请求。
+
+另外,重试的次数一般设为 3 次,再多次的重试没有好处,反而会加重服务器压力(部分场景使用失败重试机制会不太适合)。
+
+### 灾备设计和异地多活
+
+**灾备** = 容灾+备份。
+
+- **备份** : 将系统所产生的的所有重要数据多备份几份。
+- **容灾** : 在异地建立两个完全相同的系统。当某个地方的系统突然挂掉,整个应用系统可以切换到另一个,这样系统就可以正常提供服务了。
+
+**异地多活** 描述的是将服务部署在异地并且服务同时对外提供服务。和传统的灾备设计的最主要区别在于“多活”,即所有站点都是同时在对外提供服务的。异地多活是为了应对突发状况比如火灾、地震等自然或者认为灾害。
+
+相关阅读:
+
+- [搞懂异地多活,看这篇就够了](https://mp.weixin.qq.com/s/T6mMDdtTfBuIiEowCpqu6Q)
+- [四步构建异地多活](https://mp.weixin.qq.com/s/hMD-IS__4JE5_nQhYPYSTg)
+- [《从零开始学架构》— 28 | 业务高可用的保障:异地多活架构](http://gk.link/a/10pKZ)
diff --git a/_coverpage.md b/_coverpage.md
deleted file mode 100644
index 7310181ac88..00000000000
--- a/_coverpage.md
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-Java 学习/面试指南
-
-[常用资源](https://shimo.im/docs/MuiACIg1HlYfVxrj/)
-[GitHub]()
-[开始阅读](#java)
-
-
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
new file mode 100644
index 00000000000..b9ce3f6d372
--- /dev/null
+++ b/docs/.vuepress/config.js
@@ -0,0 +1,383 @@
+const { config } = require("vuepress-theme-hope");
+
+module.exports = config({
+ title: "JavaGuide",
+ description: "Java学习&&面试指南",
+ dest: "./dist",
+ head: [
+ [
+ "script",
+ { src: "https://cdn.jsdelivr.net/npm/react/umd/react.production.min.js" },
+ ],
+ [
+ "script",
+ {
+ src: "https://cdn.jsdelivr.net/npm/react-dom/umd/react-dom.production.min.js",
+ },
+ ],
+ ["script", { src: "https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js" }],
+ [
+ "script",
+ { src: "https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js" },
+ ],
+ // 添加百度统计
+ [
+ "script",{},
+ `var _hmt = _hmt || [];
+ (function() {
+ var hm = document.createElement("script");
+ hm.src = "https://hm.baidu.com/hm.js?5dd2e8c97962d57b7b8fea1737c01743";
+ var s = document.getElementsByTagName("script")[0];
+ s.parentNode.insertBefore(hm, s);
+ })();`
+ ]
+ ],
+
+ themeConfig: {
+ logo: "/logo.png",
+ hostname: "https://javaguide.cn/",
+ author: "Guide哥",
+ repo: "https://github.com/Snailclimb/JavaGuide",
+ nav: [
+ { text: "Java面试指南", icon: "java", link: "/", },
+ { text: "Java面试指北", icon: "java", link: "https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7?#%20%E3%80%8A%E3%80%8AJava%E9%9D%A2%E8%AF%95%E8%BF%9B%E9%98%B6%E6%8C%87%E5%8C%97%20%20%E6%89%93%E9%80%A0%E4%B8%AA%E4%BA%BA%E7%9A%84%E6%8A%80%E6%9C%AF%E7%AB%9E%E4%BA%89%E5%8A%9B%E3%80%8B%E3%80%8B", },
+ {
+ text: "Java精选", icon: "file", icon: "java",
+ items: [
+ { text: "Java书单精选", icon: "book", link: "https://gitee.com/SnailClimb/awesome-cs" },
+ { text: "Java学习路线", icon: "luxianchaxun", link: "https://zhuanlan.zhihu.com/p/379041500" },
+ { text: "Java开源项目精选", icon: "git", link: "https://gitee.com/SnailClimb/awesome-java" }
+ ],
+ },
+ { text: "IDEA指南", icon: "intellijidea", link: "/idea-tutorial/", },
+ { text: "开发工具", icon: "Tools", link: "/tools/", },
+ {
+ text: "PDF资源", icon: "pdf",
+ items: [
+ { text: "JavaGuide面试突击版", link: "https://t.1yb.co/Fy1e", },
+ { text: "消息队列常见知识点&面试题总结", link: "https://t.1yb.co/Fy0u", },
+ { text: "图解计算机基础!", link: "https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100021725&idx=1&sn=2db9664ca25363139a81691043e9fd8f&chksm=4ea19a1679d61300d8990f7e43bfc7f476577a81b712cf0f9c6f6552a8b219bc081efddb5c54#rd" }
+ ],
+ },
+ {
+ text: "关于作者", icon: "zuozhe", link: "/about-the-author/"
+ },
+ ],
+ sidebar: {
+ "/about-the-author/": [
+ "internet-addiction-teenager", "feelings-after-one-month-of-induction-training"
+ ],
+ // 应该把更精确的路径放置在前边
+ '/tools/': [
+ {
+ title: "数据库",
+ icon: "database",
+ prefix: "database/",
+ collapsable: false,
+ children: ["CHINER", "DBeaver", "screw"]
+ },
+ {
+ title: "Git",
+ icon: "git",
+ prefix: "git/",
+ collapsable: false,
+ children: ["git-intro", "github技巧"]
+ },
+ {
+ title: "Docker",
+ icon: "docker1",
+ prefix: "docker/",
+ collapsable: false,
+ children: ["docker", "docker从入门到实战"]
+ },
+ ],
+ '/idea-tutorial/':
+ [
+ {
+ title: "IDEA小技巧",
+ icon: "creative",
+ prefix: "idea-tips/",
+ collapsable: false,
+ children: [
+ "idea-refractor-intro",
+ "idea-plug-in-development-intro",
+ "idea-source-code-reading-skills",
+ ]
+ },
+ {
+ title: "IDEA插件推荐",
+ icon: "plugin",
+ collapsable: false,
+ prefix: "idea-plugins/",
+ children: [
+ "shortcut-key", "idea-themes", "improve-code", "interface-beautification",
+ "camel-case", "code-glance", "code-statistic",
+ "git-commit-template", "gson-format", "idea-features-trainer", "jclasslib",
+ "maven-helper", "rest-devlop", "save-actions", "sequence-diagram", "translation",
+ "others"
+ ]
+ },
+ ],
+ // 必须放在最后面
+ '/': [{
+ title: "Java", icon: "java", prefix: "java/",
+ children: [
+ {
+ title: "基础", prefix: "basis/",
+ children: [
+ "java基础知识总结",
+ {
+ title: "重要知识点",
+ children: ["反射机制详解", "代理模式详解", "io模型详解"],
+ },],
+ },
+ {
+ title: "容器", prefix: "collection/",
+ children: [
+ "java集合框架基础知识&面试题总结", "java集合使用注意事项",
+ {
+ title: "源码分析",
+ children: ["arraylist-source-code", "hashmap-source-code", "concurrent-hash-map-source-code"],
+ },],
+ },
+ {
+ title: "并发编程", prefix: "concurrent/",
+ children: [
+ "java并发基础常见面试题总结", "java并发进阶常见面试题总结",
+ {
+ title: "重要知识点",
+ children: ["java线程池学习总结", "并发容器总结", "拿来即用的java线程池最佳实践", "aqs原理以及aqs同步组件总结", "reentrantlock",
+ "atomic原子类总结", "threadlocal", "completablefuture-intro"],
+ },
+ ],
+ },
+ {
+ title: "JVM", prefix: "jvm/",
+ children: ["memory-area", "jvm-garbage-collection", "class-file-structure", "class-loading-process", "classloader", "jvm-parameters-intro", "jvm-intro", "jdk-monitoring-and-troubleshooting-tools"],
+ },
+ {
+ title: "新特性", prefix: "new-features/",
+ children: ["java8-common-new-features", "java8-tutorial-translate", "java新特性总结"],
+ },
+ {
+ title: "小技巧", prefix: "tips/",
+ children: ["locate-performance-problems/手把手教你定位常见Java性能问题", "jad"],
+ },
+ ],
+ },
+ {
+ title: "计算机基础", icon: "computer", prefix: "cs-basics/",
+ children: [
+ {
+ title: "计算机网络", prefix: "network/", icon: "network",
+ children: [
+ "计算机网络常见面试题", "谢希仁老师的《计算机网络》内容总结", "HTTPS中的TLS"
+ ],
+ },
+ {
+ title: "操作系统", prefix: "operating-system/", icon: "caozuoxitong",
+ children: [
+ "操作系统常见面试题&知识点总结", "linux-intro", "shell-intro"
+ ],
+ },
+ {
+ title: "数据结构", prefix: "data-structure/", icon: "people-network-full",
+ children: [
+ "线性数据结构", "图", "堆", "树", "红黑树", "bloom-filter"
+ ],
+ },
+ {
+ title: "算法", prefix: "algorithms/", icon: "suanfaku",
+ children: [
+ "几道常见的字符串算法题", "几道常见的链表算法题", "剑指offer部分编程题"
+ ],
+ },
+ ],
+
+ },
+ {
+ title: "数据库", icon: "database", prefix: "database/",
+ children: [
+ "数据库基础知识",
+ "字符集",
+ {
+ title: "MySQL", prefix: "mysql/",
+ children: [
+ "mysql知识点&面试题总结",
+ "a-thousand-lines-of-mysql-study-notes",
+ "mysql-high-performance-optimization-specification-recommendations",
+ "mysql-index", "mysql-logs", "transaction-isolation-level",
+ "innodb-implementation-of-mvcc", "how-sql-executed-in-mysql",
+ "some-thoughts-on-database-storage-time"
+ ],
+ },
+ {
+ title: "Redis", prefix: "redis/",
+ children: ["redis知识点&面试题总结", "3-commonly-used-cache-read-and-write-strategies"],
+ },
+ ],
+ },
+ {
+ title: "系统设计", icon: "xitongsheji", prefix: "system-design/",
+ children: [
+ {
+ title: "基础", prefix: "basis/", icon: "jibendebasic",
+ children: [
+ "RESTfulAPI",
+ "naming",
+ ],
+ },
+ {
+ title: "常用框架", prefix: "framework/", icon: "framework",
+ children: [{
+ title: "Spring", prefix: "spring/",
+ children: ["Spring常见问题总结", "Spring&SpringBoot常用注解总结", "Spring事务总结", "Spring设计模式总结", "SpringBoot自动装配原理"]
+ },
+ "mybatis/mybatis-interview", "netty",
+ {
+ title: "SpringCloud", prefix: "springcloud/",
+ children: ["springcloud-intro"]
+ },
+ ],
+ },
+ {
+ title: "安全", prefix: "security/", icon: "security-fill",
+ children: ["basis-of-authority-certification", "jwt优缺点分析以及常见问题解决方案", "sso-intro", "数据脱敏"]
+ },
+ "定时任务"
+ ],
+ },
+ {
+ title: "分布式", icon: "distributed-network", prefix: "distributed-system/",
+ children: [
+ {
+ title: "理论&算法", prefix: "理论&算法/",
+ children: ["cap&base理论", "paxos&raft算法"],
+ },
+ "api-gateway", "distributed-id",
+ {
+ title: "rpc", prefix: "rpc/",
+ children: ["dubbo", "why-use-rpc"]
+ },
+ "distributed-transaction",
+ {
+ title: "分布式协调", prefix: "分布式协调/",
+ children: ["zookeeper/zookeeper-intro", "zookeeper/zookeeper-plus", "zookeeper/zookeeper-in-action"]
+ },
+ ],
+ }, {
+ title: "高性能", icon: "gaojixiaozuzhibeifen", prefix: "high-performance/",
+ children: [
+ "读写分离&分库分表", "负载均衡",
+ {
+ title: "消息队列", prefix: "message-queue/",
+ children: ["message-queue", "kafka知识点&面试题总结", "rocketmq-intro", "rocketmq-questions", "rabbitmq-intro"],
+ },
+ ],
+ }, {
+ title: "高可用", icon: "CalendarAvailability-1", prefix: "high-availability/",
+ children: [
+ "高可用系统设计", "limit-request", "降级&熔断", "超时和重试机制", "集群", "灾备设计和异地多活", "性能测试"
+ ],
+ }],
+ },
+ blog: {
+ intro: "/intro/",
+ sidebarDisplay: "mobile",
+ links: {
+ Zhihu: "https://www.zhihu.com/people/javaguide",
+ Github: "https://github.com/Snailclimb",
+ Gitee: "https://gitee.com/SnailClimb",
+ },
+ },
+
+ footer: {
+ display: true,
+ content: '鄂ICP备2020015769号-1 ',
+ },
+
+ copyright: {
+ status: "global",
+ },
+
+ git: {
+ timezone: "Asia/Shanghai",
+ },
+
+ mdEnhance: {
+ enableAll: true,
+ presentation: {
+ plugins: [
+ "highlight",
+ "math",
+ "search",
+ "notes",
+ "zoom",
+ "anything",
+ "audio",
+ "chalkboard",
+ ],
+ },
+ },
+
+ pwa: {
+ favicon: "/favicon.ico",
+ cachePic: true,
+ apple: {
+ icon: "/assets/icon/apple-icon-152.png",
+ statusBarColor: "black",
+ },
+ msTile: {
+ image: "/assets/icon/ms-icon-144.png",
+ color: "#ffffff",
+ },
+ manifest: {
+ icons: [
+ {
+ src: "/assets/icon/chrome-mask-512.png",
+ sizes: "512x512",
+ purpose: "maskable",
+ type: "image/png",
+ },
+ {
+ src: "/assets/icon/chrome-mask-192.png",
+ sizes: "192x192",
+ purpose: "maskable",
+ type: "image/png",
+ },
+ {
+ src: "/assets/icon/chrome-512.png",
+ sizes: "512x512",
+ type: "image/png",
+ },
+ {
+ src: "/assets/icon/chrome-192.png",
+ sizes: "192x192",
+ type: "image/png",
+ },
+ ],
+ shortcuts: [
+ {
+ name: "Guide",
+ short_name: "Guide",
+ url: "/guide/",
+ icons: [
+ {
+ src: "/assets/icon/guide-maskable.png",
+ sizes: "192x192",
+ purpose: "maskable",
+ type: "image/png",
+ },
+ {
+ src: "/assets/icon/guide-monochrome.png",
+ sizes: "192x192",
+ purpose: "monochrome",
+ type: "image/png",
+ },
+ ],
+ },
+ ],
+ },
+ },
+ },
+});
diff --git a/docs/.vuepress/public/assets/icon/apple-icon-152.png b/docs/.vuepress/public/assets/icon/apple-icon-152.png
new file mode 100644
index 00000000000..3eabbeb1dc3
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/apple-icon-152.png differ
diff --git a/docs/.vuepress/public/assets/icon/chrome-192.png b/docs/.vuepress/public/assets/icon/chrome-192.png
new file mode 100644
index 00000000000..851ad3a224d
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/chrome-192.png differ
diff --git a/docs/.vuepress/public/assets/icon/chrome-512.png b/docs/.vuepress/public/assets/icon/chrome-512.png
new file mode 100644
index 00000000000..2fb9f40be37
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/chrome-512.png differ
diff --git a/docs/.vuepress/public/assets/icon/chrome-mask-192.png b/docs/.vuepress/public/assets/icon/chrome-mask-192.png
new file mode 100644
index 00000000000..530977a9e69
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/chrome-mask-192.png differ
diff --git a/docs/.vuepress/public/assets/icon/chrome-mask-512.png b/docs/.vuepress/public/assets/icon/chrome-mask-512.png
new file mode 100644
index 00000000000..a4f90ae484b
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/chrome-mask-512.png differ
diff --git a/docs/.vuepress/public/assets/icon/guide-maskable.png b/docs/.vuepress/public/assets/icon/guide-maskable.png
new file mode 100644
index 00000000000..75449b6098b
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/guide-maskable.png differ
diff --git a/docs/.vuepress/public/assets/icon/guide-monochrome.png b/docs/.vuepress/public/assets/icon/guide-monochrome.png
new file mode 100644
index 00000000000..5b1dc406d6a
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/guide-monochrome.png differ
diff --git a/docs/.vuepress/public/assets/icon/ms-icon-144.png b/docs/.vuepress/public/assets/icon/ms-icon-144.png
new file mode 100644
index 00000000000..24641244228
Binary files /dev/null and b/docs/.vuepress/public/assets/icon/ms-icon-144.png differ
diff --git a/docs/.vuepress/public/favicon.ico b/docs/.vuepress/public/favicon.ico
new file mode 100644
index 00000000000..3a14635ac46
Binary files /dev/null and b/docs/.vuepress/public/favicon.ico differ
diff --git a/docs/.vuepress/public/logo.png b/docs/.vuepress/public/logo.png
new file mode 100644
index 00000000000..7675a8b5aa3
Binary files /dev/null and b/docs/.vuepress/public/logo.png differ
diff --git a/docs/.vuepress/public/logo.svg b/docs/.vuepress/public/logo.svg
new file mode 100644
index 00000000000..fdfe9e6c1ce
--- /dev/null
+++ b/docs/.vuepress/public/logo.svg
@@ -0,0 +1,317 @@
+
+
+
+
diff --git a/docs/.vuepress/public/me.png b/docs/.vuepress/public/me.png
new file mode 100644
index 00000000000..cfa3a6ea375
Binary files /dev/null and b/docs/.vuepress/public/me.png differ
diff --git a/docs/.vuepress/styles/index.styl b/docs/.vuepress/styles/index.styl
new file mode 100644
index 00000000000..e67a4cf0381
--- /dev/null
+++ b/docs/.vuepress/styles/index.styl
@@ -0,0 +1,2 @@
+// import icon
+@import 'http://at.alicdn.com/t/font_2922463_74fu8o5xg3.css'
\ No newline at end of file
diff --git a/docs/about-the-author/feelings-after-one-month-of-induction-training.md b/docs/about-the-author/feelings-after-one-month-of-induction-training.md
new file mode 100644
index 00000000000..9f81220150f
--- /dev/null
+++ b/docs/about-the-author/feelings-after-one-month-of-induction-training.md
@@ -0,0 +1,19 @@
+# 入职培训一个月后的感受
+
+不知不觉已经入职一个多月了,在入职之前我没有在某个公司实习过或者工作过,所以很多东西刚入职工作的我来说还是比较新颖的。学校到职场的转变,带来了角色的转变,其中的差别因人而异。对我而言,在学校的时候课堂上老师课堂上教的东西,自己会根据自己的兴趣选择性接受,甚至很多课程你不想去上的话,还可以逃掉。到了公司就不一样了,公司要求你会的技能你不得不学,除非你不想干了。在学校的时候大部分人编程的目的都是为了通过考试或者找到一份好工作,真正靠自己兴趣支撑起来的很少,到了工作岗位之后我们编程更多的是因为工作的要求,相比于学校的来说会一般会更有挑战而且压力更大。在学校的时候,我们最重要的就是对自己负责,我们不断学习知识去武装自己,但是到了公司之后我们不光要对自己负责,更要对公司负责,毕竟公司出钱请你过来,不是让你一直 on beach 的。
+
+刚来公司的时候,因为公司要求,我换上了 Mac 电脑。由于之前一直用的是 Windows 系统,所以非常不习惯。刚开始用 Mac 系统的时候笨手笨脚,自己会很明显的感觉自己的编程效率降低了至少 3 成。当时内心还是挺不爽的,心里也总是抱怨为什么不直接用 Windows 系统或者 Linux 系统。不过也挺奇怪,大概一个星期之后,自己就开始慢慢适应使用 Mac 进行编程,甚至非常喜欢。我这里不想对比 Mac 和 Windows 编程体验哪一个更好,我觉得还是因人而异,相同价位的 Mac 的配置相比于 Windows确实要被甩几条街。不过 Mac 的编程和使用体验确实不错,当然你也可以选择使用 Linux 进行日常开发,相信一定很不错。 另外,Mac 不能玩一些主流网络游戏,对于一些克制不住自己想玩游戏的朋友是一个不错的选择。
+
+不得不说 ThoughtWorks 的培训机制还是很不错的。应届生入职之后一般都会安排培训,与往年不同的是,今年的培训多了中国本地班(TWU-C)。作为本地班的第一期学员,说句心里话还是很不错。8周的培训,除了工作需要用到的基本技术比如ES6、SpringBoot等等之外,还会增加一些新员工基本技能的培训比如如何高效开会、如何给别人正确的提 Feedback、如何对代码进行重构、如何进行 TDD 等等。培训期间不定期的有活动,比如Weekend Trip、 City Tour、Cake time等等。最后三周还会有一个实际的模拟项目,这个项目基本和我们正式工作的实际项目差不多,我个人感觉很不错。目前这个项目已经正式完成了一个迭代,我觉得在做项目的过程中,收获最大的不是项目中使用的技术,而是如何进行团队合作、如何正确使用 Git 团队协同开发、一个完成的迭代是什么样子的、做项目的过程中可能遇到那些问题、一个项目运作的完整流程等等。
+
+ThoughtWorks 非常提倡分享、提倡帮助他人成长,这一点在公司的这段时间深有感触。培训期间,我们每个人会有一个 Trainer 负责,Trainer 就是日常带我们上课和做项目的同事,一个 Trainer 大概会负责5-6个人。Trainer不定期都会给我们最近表现的 Feedback( 反馈) ,我个人觉得这个并不是这是走走形式,Trainer 们都很负责,很多时候都是在下班之后找我们聊天。同事们也都很热心,如果你遇到问题,向别人询问,其他人如果知道的话一般都会毫无保留的告诉你,如果遇到大部分都不懂的问题,甚至会组织一次技术 Session 分享。上周五我在我们小组内进行了一次关于 Feign 远程调用的技术分享,因为 team 里面大家对这部分知识都不太熟悉,但是后面的项目进展大概率会用到这部分知识。我刚好研究了这部分内容,所以就分享给了组内的其他同事,以便于项目更好的进行。
+
+ 另外,ThoughtWorks 也是一家非常提倡 Feedback( 反馈) 文化的公司,反馈是告诉人们我们对他们的表现的看法以及他们应该如何更好地做到这一点。刚开始我并没有太在意,慢慢地自己确实感觉到正确的进行反馈对他人会有很大的帮助。因为人在做很多事情的时候,会很难发现别人很容易看到的一些小问题。就比如一个很有趣的现象一样,假如我们在做项目的时候没有测试这个角色,如果你完成了自己的模块,并且自己对这个模块测试了很多遍,你发现已经没啥问题了。但是,到了实际使用的时候会很大概率出现你之前从来没有注意的问题。解释这个问题的说法是:每个人的视野或多或少都是有盲点的,这与我们的关注点息息相关。对于自己做的东西,很多地方自己测试很多遍都不会发现,但是如果让其他人帮你进行测试的话,就很大可能会发现很多显而易见的问题。
+
+
+
+工作之后,平时更新公众号、专栏还有维护 Github 的时间变少了。实际上,很多时候下班回来后,都有自己的时间来干自己的事情,但是自己也总是找工作太累或者时间比较零散的接口来推掉了。到了今天,翻看 Github 突然发现 14 天前别人在 Github 上给我提的 pr 我还没有处理。这一点确实是自己没有做好的地方,没有合理安排好自己的时间。实际上自己有很多想写的东西,后面会慢慢将他们提上日程。工作之后,更加发现下班后的几个小时如何度过确实很重要 ,如果你觉得自己没有完成好自己白天该做的工作的话,下班后你可以继续忙白天没有忙完的工作,如果白天的工作对于你游刃有余的话,下班回来之后,你大可去干自己感兴趣的事情,学习自己感兴趣的技术。做任何事情都要基于自身的基础,切不可好高骛远。
+
+工作之后身边也会有很多厉害的人,多从他人身上学习我觉得是每个职场人都应该做的。这一届和我们一起培训的同事中,有一些技术很厉害的,也有一些技术虽然不是那么厉害,但是组织能力以及团队协作能力特别厉害的。有一个特别厉害的同事,在我们还在学 SpringBoot 各种语法的时候,他自己利用业余时间写了一个简化版的 SpringBoot ,涵盖了 Spring 的一些常用注解比如 `@RestController`、`@Autowried`、`@Pathvairable`、`@RestquestParam`等等(已经联系这位同事,想让他开源一下,后面会第一时间同步到公众号,期待一下吧!)。我觉得这位同事对于编程是真的有兴趣,他好像从初中就开始接触编程了,对于各种底层知识也非常感兴趣,自己写过实现过很多比较底层的东西。他的梦想是在 Github 上造一个 20k Star 以上的轮子。我相信以这位同事的能力一定会达成目标的,在这里祝福这位同事,希望他可以尽快实现这个目标。
+
+这是我入职一个多月之后的个人感受,很多地方都是一带而过,后面我会抽时间分享自己在公司或者业余学到的比较有用的知识给各位,希望看过的人都能有所收获。
\ No newline at end of file
diff --git a/docs/about-the-author/internet-addiction-teenager.md b/docs/about-the-author/internet-addiction-teenager.md
new file mode 100644
index 00000000000..52458b4a0c0
--- /dev/null
+++ b/docs/about-the-author/internet-addiction-teenager.md
@@ -0,0 +1,104 @@
+# 我曾经也是网瘾少年
+
+聊到高考,无数人都似乎有很多话说。今天就假借高考的名义,**简单**来聊聊我的求学经历吧!因为我自己的求学经历真的还不算平淡,甚至有点魔幻,所以还是有很多话想要说的。这篇文章大概会从我的初中一直介绍到大学,每一部分我都不会花太多篇幅。实际上,每一段经历我都可以增加很多“有趣”的经历,考虑到篇幅问题,以后有机会再慢慢说吧!
+
+整个初中我都属于有点网瘾少年的状态,不过初三的时候稍微克制一些。到了高二下学期的时候,自己才对游戏没有真的没有那么沉迷了。
+
+另外,关于大学的详细经历我已经在写了。想要知道我是如何从一个普通的不能再普通的少年慢慢成长起来的朋友不要错过~
+
+
+
+**以下所有内容皆是事实,没有任何夸大的地方,稍微有一点点魔幻。**
+
+## 01 刚开始接触电脑
+
+最开始接触电脑是在我五年级的时候,那时候家里没电脑,都是在黑网吧玩的。我现在已经记不清当时是被哥哥还是姐姐带进网吧的了。
+
+起初的时候,自己就是玩玩流行蝴蝶剑、单机摩托之类的单机游戏。但是,也没有到沉迷的地步,只是觉得这东西确实挺好玩的。
+
+
+
+开始有网瘾是在小学毕业的时候,在我玩了一款叫做 **QQ 飞车**的游戏之后(好像是六年级就开始玩了)。我艹,当时真的被这游戏吸引了。**每天上课都幻想自己坐在车里面飘逸,没错,当时就觉得秋名山车神就是我啦!**
+
+我记得,那时候上网还不要身份证,10 元办一张网卡就行了,网费也是一元一小时。但凡,我口袋里有余钱,我都会和我的小伙伴奔跑到网吧一起玩 QQ 飞车。Guide 的青回啊!说到这,我情不自禁地打开自己的 Windows 电脑,下载了 Wegame ,然后下载了 QQ 飞车。
+
+到了初二的时候,就没玩 QQ 飞车了。我的等级也永久定格在了 **120** 级,这个等级在当时那个升级难的一匹的年代,算的上非常高的等级了。
+
+
+
+## 02 初二网瘾爆发
+
+网瘾爆发是在上了初中之后。初二的时候,最为猖狂,自己当时真的是太痴迷 **穿越火线** 了,每天上课都在想像自己拿起枪横扫地方阵营的场景。除了周末在网吧度过之外,我经常每天早上还会起早去玩别人包夜留下的机子,毕竟那时候上学也没什么钱嘛!
+
+
+
+那时候成绩挺差的。这样说吧!我当时在很普通的一个县级市的高中,全年级有 500 来人,我基本都是在 280 名左右。
+
+而且,整个初二我都没有学物理。因为开学不久的一次物理课,物理老师误会我在上课吃东西还狡辩,闪了我一巴掌。从此,我上物理课就睡觉,平常的物理考试就交白卷。那时候心里一直记仇,想着以后自己长大了把这个物理暴打他一顿。
+
+初中时候的觉悟是在初三上学期的时候,当时就突然意识到自己马上就要升高中了。为了让自己能在家附近上学,因为当时我家就在我们当地的二中附近(_附近网吧多是主要原因,哈哈_)。年级前 80 的话基本才有可能考得上二中。**经过努力,初三上学期的第一次月考我直接从 280 多名进不到了年级 50 多名。当时,还因为进步太大,被当做进步之星在讲台上给整个年级做演讲。**那也是我第一次在这么多人面前讲话,挺紧张的,但是挺爽的。
+
+**其实在初三的时候,我的网瘾还是很大。不过,我去玩游戏的前提都是自己把所有任务做完,并且上课听讲也很认真。** 我参加高中提前考试前的一个晚上,我半夜12点乘着妈妈睡着,跑去了网吧玩CF到凌晨 3点多回来。那一次我被抓了现行,到家之后发现妈妈就坐在客厅等我,训斥一顿后,我就保证以后不再晚上偷偷跑出去了(*其实整个初二我通宵了无数次,每个周五晚上都回去通宵*)。
+
+_这里要说明一点:我的智商我自己有自知之明的,属于比较普通的水平吧! 前进很大的主要原因是自己基础还行,特别是英语和物理。英语是因为自己喜欢,加上小学就学了很多初中的英语课程。 物理的话就很奇怪,虽然初二也不怎么听物理课,也不会物理,但是到了初三之后自己就突然开窍了。真的!我现在都感觉很奇怪。然后,到了高中之后,我的英语和物理依然是我最好的两门课。大学的兼职,我出去做家教都是教的高中物理。_
+
+后面,自己阴差阳错参加我们那个县级市的提前招生考试,然后就到了我们当地的二中,也没有参加中考。
+
+## 03 高中生活
+
+上了高中的之后,我上课就偷偷看小说,神印王座、斗罗大陆很多小说都是当时看的。中午和晚上回家之后,就在家里玩几把 DNF,当时家里也买了电脑。没记错的话,到我卸载 DNF 的时候已经练了 4 个满级的号。大量时间投入在游戏和小说上,我成功把自己从学校最好的小班玩到奥赛班,然后再到平行班。有点魔幻吧!
+
+高中觉悟是在高二下学期的时候,当时是真的觉悟了,就突然觉得游戏不香了,觉得 DNF 也不好玩了。我妈妈当时还很诧异,还奇怪地问我:“怎么不玩游戏了?”(*我妈属于不怎么管我玩游戏的,她觉得这东西还是要靠自觉*)。
+
+*当时,自己就感觉这游戏没啥意思了。内心的真实写照是:“我练了再多的满级的DNF账号有啥用啊?以后有钱了,直接氪金不久能很牛逼嘛!” 就突然觉悟了!*
+
+然后,我就开始牟足劲学习。当时,理科平行班大概有 7 个,每次考试都是平行班之间会单独拍一个名次。 后面的话,自己基本每次都能在平行班得第一,并且很多时候都是领先第二名个 30 来分。因为成绩还算亮眼,高三上学期快结束的时候,我就向年级主任申请去了奥赛班。
+
+## 04 高考前的失眠
+
+> **失败之后,不要抱怨外界因素,自始至终实际都是自己的问题,自己不够强大!** 然后,高考前的失眠也是我自己问题,要怪只能怪自己,别的没有任何接口。
+
+我的高考经历其实还蛮坎坷的,毫不夸张的说,高考那今天可能是我到现在为止,经历的最难熬的时候,特别是在晚上。
+
+我在高考那几天晚上都经历了失眠,想睡都睡不着那种痛苦想必很多人或许都体验过。
+
+其实我在之前是从来没有过失眠的经历的。高考前夕,因为害怕自己睡不着,所以,我提前让妈妈去买了几瓶老师推荐的安神补脑液。我到现在还记得这个安神补脑液是敖东牌的。
+
+高考那几天的失眠,我觉得可能和我喝了老师推荐的安神补脑液有关系,又或者是我自己太过于紧张了。因为那几天睡觉总会感觉有很多蚂蚁在身上爬一样,然后还起了一些小痘痘。
+
+然后,这里要格外说明一点,避免引起误导: **睡不着本身就是自身的问题,上述言论并没有责怪这个补脑液的意思。** 另外, 这款安神补脑液我去各个平台都查了一下,发现大家对他的评价都挺好,和我们老师当时推荐的理由差不多。如果大家需要改善睡眠的话,可以咨询相关医生之后尝试一下。
+
+## 05 还算充实的大学生活
+
+高考成绩出来之后,比一本线高了 20 多分。自己挺不满意的,因为比平时考差了太多。加上自己泪点很低,就哭了一上午之后。后面,自我安慰说以后到了大学好好努力也是一样的。然后,我的第一志愿学校就报了长江大学,第一志愿专业就报了计算机专业。
+
+后面,就开始了自己还算充实的大学生活。
+
+大一的时候,满腔热血,对于高考结果的不满意,化作了我每天早起的动力。雷打不动,每天早上 6点左右就出去背英语单词。这也奠定了我后面的四六级都是一次过,并且六级的成绩还算不错。大一那年的暑假,我还去了孝感当了主管,几乎从无到有办了 5 个家教点。不过,其中两个家教点的话,是去年都已经办过的,没有其他几个那么费心。
+
+
+
+大二的时候,加了学校一个偏技术方向的传媒组织(做网站、APP 之类的工作),后面成功当了副站长。在大二的时候,我才开始因为组织需要而接触 Java,不过当时主要学的是安卓开发。
+
+
+
+大三的时候,正式确定自己要用 Java 语言找工作,并且要走 Java 后台(当时感觉安卓后台在求职时长太不吃香了)。我每天都在寝室学习 Java 后台开发,自己看视频,看书,做项目。我的开源项目 JavaGuide 和公众号都是这一年创建的。这一年,我大部分时间都是在寝室学习。带上耳机之后,即使室友在玩游戏或者追剧,都不会对我有什么影响。
+
+我记得当时自己独立做项目的时候,遇到了很多问题。**就很多时候,你看书很容易就明白的东西,等到你实践的时候,总是会遇到一些小问题。我一般都是通过 Google 搜索解决的,用好搜索引擎真的能解决自己 99% 的问题。**
+
+
+
+大四的时候,开始找工作。我是参加的秋招,开始的较晚,基本很多公司都没有 HC 了。这点需要 diss 一下学校了,你其他地方都很好,但是,大四的时候就不要再上课点名了吧!然后,**希望国内的学校尽量能多给学生点机会吧!很多人连春招和秋招都不清楚,毕业了连实习都没实习过。**
+
+## 06 一些心里话
+
+关于大学要努力学习专业知识、多去读书馆这类的鸡汤,Guide 就不多说了。就谈几条自己写这篇文章的时候,想到了一些心理话吧!
+
+1. **不要抱怨学校** :高考之后,不论你是 985、211 还是普通一本,再或者是 二本、三本,都不重要了,好好享受高考之后的生活。如果你觉得自己考的不满意的话,就去复读,没必要天天抱怨,复读的一年在你的人生长河里根本算不了什么的!
+2. **克制** :大学的时候,克制住自己,诱惑太多了。你不去上课,在寝室睡到中午,都没人管你。你的努力不要只是感动自己!追求形式的努力不过是你打得幌子而已。到了社会之后,这个说法依然适用! 说一个真实的发生在我身边的事情吧!高中的时候有一个特别特别特别努力的同班同学,家里的条件也很差,大学之前没有接触过手机和游戏。后来到了大学之后,因为接触了手机还有手机游戏,每天沉迷,不去上课。最后,直接就导致大学没读完就离开了。我听完我的好朋友给我说了之后,非常非常非常诧异!真的太可惜了!
+3. **不要总抱怨自己迷茫,多和优秀的学长学姐沟通交流。**
+4. **不知道做什么的时候,就把手头的事情做好比如你的专业课学习。**
+
+*不论以前的自己是什么样,自己未来变成什么样自己是可以决定的,未来的路也终究还是要自己走。大环境下,大部分人都挺难的,当 996 成为了常态,Life Balance 是不可能的了。我们只能试着寻求一种平衡,试着去热爱自己现在所做的事情。*
+
+**往后余生,爱家人,亦爱自己;好好生活,不忧不恼。**
diff --git a/docs/about-the-author/readme.md b/docs/about-the-author/readme.md
new file mode 100644
index 00000000000..cdf185586d7
--- /dev/null
+++ b/docs/about-the-author/readme.md
@@ -0,0 +1,52 @@
+# 个人介绍 Q&A
+
+大家好,我是 Gudie哥!这篇文章我会通过 Q&A 的形式简单介绍一下我自己。
+
+## 我是什么时候毕业的?
+
+很多老读者应该比较清楚,我是 19 年本科毕业的,刚毕业就去了某家外企“养老”。
+
+我的学校背景是比较差的,高考失利,勉强过了一本线 20 来分,去了荆州的一所很普通的双非一本。不过,还好我没有因为学校而放弃自己,反倒是比身边的同学都要更努力,整个大学还算过的比较充实。
+
+下面这张是当时拍的毕业照:
+
+
+
+## 为什么要做 JavaGuide 这个项目?
+
+我从大二坚持写作,坚持分享让我收获了 30w+ 的读者以及一笔不错的副业收入。
+
+2018 年,我还在读大三的时候,JavaGuide 开源项目&公众号诞生了。很难想到,日后,他们会陪伴我度过这么长的时间。
+
+开源 JavaGuide 初始想法源于自己的个人那一段比较迷茫的学习经历。主要目的是为了通过这个开源平台来帮助一些在学习 Java 以及面试过程中遇到问题的小伙伴。
+
+- **对于 Java 初学者来说:** 本文档倾向于给你提供一个比较详细的学习路径,让你对于 Java 整体的知识体系有一个初步认识。另外,本文的一些文章也是你学习和复习 Java 知识不错的实践;
+- **对于非 Java 初学者来说:** 本文档更适合回顾知识,准备面试,搞清面试应该把重心放在那些问题上。要搞清楚这个道理:提前知道那些面试常见,不是为了背下来应付面试,而是为了让你可以更有针对的学习重点。
+
+## 如何看待 JavaGuide 的 star 数量很多?
+
+[JavaGuide](https://github.com/Snailclimb) 目前已经是 Java 领域 star 数量最多的几个项目之一,登顶过很多次 Github Trending。
+
+不过,这个真心没啥好嘚瑟的。因为,教程类的含金量其实是比较低的,Star 数量比较多主要也是因为受众面比较广,大家觉得不错,点个 star 就相当于收藏了。很多特别优秀的框架,star 数量可能只有几 K。所以,单纯看 star 数量没啥意思,就当看个笑话吧!
+
+维护这个项目的过程中,也被某些人 diss 过:“md 项目,没啥含金量,给国人丢脸!”。
+
+对于说这类话的人,我觉得对我没啥影响,就持续完善,把 JavaGuide 做的更好吧!其实,国外的很多项目也是纯 MD 啊!就比如外国的朋友发起的 awesome 系列、求职面试系列。无需多说,行动自证!凎!
+
+开源非常重要的一点就是协作。如果你开源了一个项目之后,就不再维护,别人给你提交 issue/pr,你都不处理,那开源也没啥意义了!
+
+## 我在大学期间赚了多少钱?
+
+在校期间,我还通过接私活、技术培训、编程竞赛等方式变现 20w+,成功实现“经济独立”。我用自己赚的钱去了重庆、三亚、恩施、青岛等地旅游,还给家里补贴了很多,减轻的父母的负担。
+
+如果你也想通过接私活变现的话,可以在我的公众号后台回复“**接私活**”来了解详细情况。
+
+
+
+## 为什么自称 Guide哥?
+
+可能是因为我的项目名字叫做 JavaGudie ,所以导致有很多人称呼我为 **Guide哥**。
+
+后面,为了读者更方便称呼,我就将自己的笔名改成了 **Guide哥**。
+
+我早期写文章用的笔名是 SnailClimb 。很多人不知道这个名字是啥意思,给大家拆解一下就清楚了。SnailClimb=Snail(蜗牛)+Climb(攀登)。我从小就非常喜欢听周杰伦的歌曲,特别是他的《蜗牛》🐌 这首歌曲,另外,当年我高考发挥的算是比较失常,上了大学之后还算是比较“奋青”,所以,我就给自己起的笔名叫做 SnailClimb ,寓意自己要不断向上攀登,哈哈
diff --git "a/docs/cs-basics/algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\227\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md" "b/docs/cs-basics/algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\227\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
index af63c584c2f..37176650df7 100644
--- "a/docs/cs-basics/algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\227\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
+++ "b/docs/cs-basics/algorithms/\345\207\240\351\201\223\345\270\270\350\247\201\347\232\204\345\255\227\347\254\246\344\270\262\347\256\227\346\263\225\351\242\230.md"
@@ -1,20 +1,4 @@
-
-
-- [说明](#说明)
-- [1. KMP 算法](#1-kmp-算法)
-- [2. 替换空格](#2-替换空格)
-- [3. 最长公共前缀](#3-最长公共前缀)
-- [4. 回文串](#4-回文串)
- - [4.1. 最长回文串](#41-最长回文串)
- - [4.2. 验证回文串](#42-验证回文串)
- - [4.3. 最长回文子串](#43-最长回文子串)
- - [4.4. 最长回文子序列](#44-最长回文子序列)
-- [5. 括号匹配深度](#5-括号匹配深度)
-- [6. 把字符串转换成整数](#6-把字符串转换成整数)
-
-
-
-
+# 几道常见的字符串算法题
> 授权转载!
>
@@ -22,9 +6,6 @@
> - 原文地址:https://www.weiweiblog.cn/13string/
-
-考虑到篇幅问题,我会分两次更新这个内容。本篇文章只是原文的一部分,我在原文的基础上增加了部分内容以及修改了部分代码和注释。另外,我增加了爱奇艺 2018 秋招 Java:`求给定合法括号序列的深度` 这道题。所有代码均编译成功,并带有注释,欢迎各位享用!
-
## 1. KMP 算法
谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(S)中查找一个子串(W)出现的位置。KMP 算法把字符匹配的时间复杂度缩小到 O(m+n) ,而空间复杂度也只有O(m)。因为“暴力搜索”的方法会反复回溯主串,导致效率低下,而KMP算法可以利用已经部分匹配这个有效信息,保持主串上的指针不回溯,通过修改子串的指针,让模式串尽量地移动到有效的位置。
@@ -284,10 +265,7 @@ class Solution {
输出: "bb"
```
-以某个元素为中心,分别计算偶数长度的回文最大长度和奇数长度的回文最大长度。给大家大致花了个草图,不要嫌弃!
-
-
-
+以某个元素为中心,分别计算偶数长度的回文最大长度和奇数长度的回文最大长度。
```java
//https://leetcode-cn.com/problems/longest-palindromic-substring/description/
@@ -401,11 +379,6 @@ class Solution {
2
```
-思路草图:
-
-
-
-
代码如下:
```java
diff --git "a/docs/cs-basics/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" "b/docs/cs-basics/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"
index 7b82436891d..1b64653cd9f 100644
--- "a/docs/cs-basics/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"
+++ "b/docs/cs-basics/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"
@@ -1,29 +1,6 @@
-
-
-- [1. 两数相加](#1-两数相加)
- - [题目描述](#题目描述)
- - [问题分析](#问题分析)
- - [Solution](#solution)
-- [2. 翻转链表](#2-翻转链表)
- - [题目描述](#题目描述-1)
- - [问题分析](#问题分析-1)
- - [Solution](#solution-1)
-- [3. 链表中倒数第k个节点](#3-链表中倒数第k个节点)
- - [题目描述](#题目描述-2)
- - [问题分析](#问题分析-2)
- - [Solution](#solution-2)
-- [4. 删除链表的倒数第N个节点](#4-删除链表的倒数第n个节点)
- - [问题分析](#问题分析-3)
- - [Solution](#solution-3)
-- [5. 合并两个排序的链表](#5-合并两个排序的链表)
- - [题目描述](#题目描述-3)
- - [问题分析](#问题分析-4)
- - [Solution](#solution-4)
-
-
-
-
-# 1. 两数相加
+# 几道常见的链表算法题
+
+## 1. 两数相加
### 题目描述
@@ -92,7 +69,7 @@ public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
}
```
-# 2. 翻转链表
+## 2. 翻转链表
### 题目描述
@@ -180,7 +157,7 @@ public class Solution {
1
```
-# 3. 链表中倒数第k个节点
+## 3. 链表中倒数第k个节点
### 题目描述
@@ -240,7 +217,7 @@ public class Solution {
```
-# 4. 删除链表的倒数第N个节点
+## 4. 删除链表的倒数第N个节点
> Leetcode:给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
@@ -367,7 +344,7 @@ public class Solution {
-# 5. 合并两个排序的链表
+## 5. 合并两个排序的链表
### 题目描述
diff --git "a/docs/cs-basics/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/cs-basics/algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md"
index 9b73888bf07..790422342fc 100644
--- "a/docs/cs-basics/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/cs-basics/algorithms/\345\211\221\346\214\207offer\351\203\250\345\210\206\347\274\226\347\250\213\351\242\230.md"
@@ -1,17 +1,19 @@
-### 一 斐波那契数列
+# 剑指offer部分编程题
-#### **题目描述:**
+## 斐波那契数列
+
+**题目描述:**
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
n<=39
-#### **问题分析:**
+**问题分析:**
可以肯定的是这一题通过递归的方式是肯定能做出来,但是这样会有一个很大的问题,那就是递归大量的重复计算会导致内存溢出。另外可以使用迭代法,用fn1和fn2保存计算过程中的结果,并复用起来。下面我会把两个方法示例代码都给出来并给出两个方法的运行时间对比。
-#### **示例代码:**
+**示例代码:**
-**采用迭代法:**
+采用迭代法:
```java
int Fibonacci(int number) {
@@ -31,7 +33,7 @@ int Fibonacci(int number) {
}
```
-**采用递归:**
+采用递归:
```java
public int Fibonacci(int n) {
@@ -46,27 +48,30 @@ public int Fibonacci(int n) {
}
```
-### 二 跳台阶问题
+## 跳台阶问题
-#### **题目描述:**
+**题目描述:**
一只青蛙一次可以跳上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
-**正常分析法:**
-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);这样子也很好理解变态跳台阶的问题了。
+找规律分析法:
+
+> 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) {
@@ -89,13 +94,13 @@ int jumpFloor(int number) {
}
```
-### 三 变态跳台阶问题
+## 变态跳台阶问题
-#### **题目描述:**
+**题目描述:**
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
-#### **问题分析:**
+**问题分析:**
假设n>=2,第一步有n种跳法:跳1级、跳2级、到跳n级
跳1级,剩下n-1级,则剩下跳法是f(n-1)
@@ -108,7 +113,7 @@ 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) {
@@ -116,25 +121,28 @@ int JumpFloorII(int number) {
}
```
-#### **补充:**
+**补充:**
-**java中有三种移位运算符:**
+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
+int a = 16;
+int b = a << 2;//左移2,等同于16 * 2的2次方,也就是16 * 4
+int c = a >> 2;//右移2,等同于16 / 2的2次方,也就是16 / 4
+```
+
+
+## 二维数组查找
-#### **题目描述:**
+**题目描述:**
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
-#### **问题解析:**
+**问题解析:**
这一道题还是比较简单的,我们需要考虑的是如何做,效率最快。这里有一种很好理解的思路:
@@ -142,7 +150,7 @@ int JumpFloorII(int number) {
> 因此从左下角开始查找,当要查找数字比左下角数字大时。右移
> 要查找数字比左下角数字小时,上移。这样找的速度最快。
-#### **示例代码:**
+**示例代码:**
```java
public boolean Find(int target, int [][] array) {
@@ -163,21 +171,21 @@ public boolean Find(int target, int [][] array) {
}
```
-### 五 替换空格
+## 替换空格
-#### **题目描述:**
+**题目描述:**
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
-#### **问题分析:**
+**问题分析:**
这道题不难,我们可以通过循环判断字符串的字符是否为空格,是的话就利用append()方法添加追加“%20”,否则还是追加原字符。
或者最简单的方法就是利用:replaceAll(String regex,String replacement)方法了,一行代码就可以解决。
-#### **示例代码:**
+**示例代码:**
-**常规做法:**
+常规做法:
```java
public String replaceSpace(StringBuffer str) {
@@ -194,7 +202,7 @@ public String replaceSpace(StringBuffer str) {
}
```
-**一行代码解决:**
+一行代码解决:
```java
public String replaceSpace(StringBuffer str) {
@@ -206,13 +214,13 @@ public String replaceSpace(StringBuffer str) {
}
```
-### 六 数值的整数次方
+## 数值的整数次方
-#### **题目描述:**
+**题目描述:**
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
-#### **问题解析:**
+**问题解析:**
这道题算是比较麻烦和难一点的一个了。我这里采用的是**二分幂**思想,当然也可以采用**快速幂**。
更具剑指offer书中细节,该题的解题思路如下:
@@ -224,7 +232,7 @@ public String replaceSpace(StringBuffer str) {
**时间复杂度**:O(logn)
-#### **示例代码:**
+**示例代码:**
```java
public class Solution {
@@ -289,18 +297,18 @@ public double powerAnother(double base, int exponent) {
}
```
-### 七 调整数组顺序使奇数位于偶数前面
+## 调整数组顺序使奇数位于偶数前面
-#### **题目描述:**
+**题目描述:**
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
-#### **问题解析:**
+**问题解析:**
这道题有挺多种解法的,给大家介绍一种我觉得挺好理解的方法:
我们首先统计奇数的个数假设为n,然后新建一个等长数组,然后通过循环判断原数组中的元素为偶数还是奇数。如果是则从数组下标0的元素开始,把该奇数添加到新数组;如果是偶数则从数组下标为n的元素开始把该偶数添加到新数组中。
-#### **示例代码:**
+**示例代码:**
时间复杂度为O(n),空间复杂度为O(n)的算法
@@ -333,13 +341,13 @@ public class Solution {
}
```
-### 八 链表中倒数第k个节点
+## 链表中倒数第k个节点
-#### **题目描述:**
+**题目描述:**
输入一个链表,输出该链表中倒数第k个结点
-#### **问题分析:**
+**问题分析:**
**一句话概括:**
两个指针一个指针p1先开始跑,指针p1跑到k-1个节点后,另一个节点p2开始跑,当p1跑到最后时,p2所指的指针就是倒数第k个节点。
@@ -347,6 +355,7 @@ public class Solution {
**思想的简单理解:**
前提假设:链表的结点个数(长度)为n。
规律一:要找到倒数第k个结点,需要向前走多少步呢?比如倒数第一个结点,需要走n步,那倒数第二个结点呢?很明显是向前走了n-1步,所以可以找到规律是找到倒数第k个结点,需要向前走n-k+1步。
+
**算法开始:**
1. 设两个都指向head的指针p1和p2,当p1走了k-1步的时候,停下来。p2之前一直不动。
@@ -354,11 +363,11 @@ public class Solution {
3. 当p1走到链表的尾部时,即p1走了n步。由于我们知道p2是在p1走了k-1步才开始动的,也就是说p1和p2永远差k-1步。所以当p1走了n步时,p2走的应该是在n-(k-1)步。即p2走了n-k+1步,此时巧妙的是p2正好指向的是规律一的倒数第k个结点处。
这样是不是很好理解了呢?
-#### **考察内容:**
+**考察内容:**
链表+代码的鲁棒性
-#### **示例代码:**
+**示例代码:**
```java
/*
@@ -401,24 +410,25 @@ public class Solution {
}
```
-### 九 反转链表
+## 反转链表
-#### **题目描述:**
+**题目描述:**
输入一个链表,反转链表后,输出链表的所有元素。
-#### **问题分析:**
+**问题分析:**
链表的很常规的一道题,这一道题思路不算难,但自己实现起来真的可能会感觉无从下手,我是参考了别人的代码。
思路就是我们根据链表的特点,前一个节点指向下一个节点的特点,把后面的节点移到前面来。
就比如下图:我们把1节点和2节点互换位置,然后再将3节点指向2节点,4节点指向3节点,这样以来下面的链表就被反转了。
-
-#### **考察内容:**
+
+
+**考察内容:**
链表+代码的鲁棒性
-#### **示例代码:**
+**示例代码:**
```java
/*
@@ -449,13 +459,13 @@ public class Solution {
}
```
-### 十 合并两个排序的链表
+## 合并两个排序的链表
-#### **题目描述:**
+**题目描述:**
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
-#### **问题分析:**
+**问题分析:**
我们可以这样分析:
@@ -465,13 +475,13 @@ public class Solution {
4. A2再和B2比较。。。。。。。
就这样循环往复就行了,应该还算好理解。
-#### **考察内容:**
+**考察内容:**
链表+代码的鲁棒性
-#### **示例代码:**
+**示例代码:**
-**非递归版本:**
+非递归版本:
```java
/*
@@ -530,7 +540,7 @@ public class Solution {
}
```
-**递归版本:**
+递归版本:
```java
public ListNode Merge(ListNode list1,ListNode list2) {
@@ -550,13 +560,13 @@ public ListNode Merge(ListNode list1,ListNode list2) {
}
```
-### 十一 用两个栈实现队列
+## 用两个栈实现队列
-#### **题目描述:**
+**题目描述:**
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
-#### 问题分析:
+**问题分析:**
先来回顾一下栈和队列的基本特点:
**栈:**后进先出(LIFO)
@@ -566,11 +576,11 @@ public ListNode Merge(ListNode list1,ListNode list2) {
既然题目给了我们两个栈,我们可以这样考虑当push的时候将元素push进stack1,pop的时候我们先把stack1的元素pop到stack2,然后再对stack2执行pop操作,这样就可以保证是先进先出的。(负[pop]负[pop]得正[先进先出])
-#### 考察内容:
+**考察内容:**
队列+栈
-#### 示例代码:
+示例代码:
```java
//左程云的《程序员代码面试指南》的答案
@@ -602,13 +612,13 @@ public class Solution {
}
```
-### 十二 栈的压入,弹出序列
+## 栈的压入,弹出序列
-#### **题目描述:**
+**题目描述:**
输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
-#### **题目分析:**
+**题目分析:**
这道题想了半天没有思路,参考了Alias的答案,他的思路写的也很详细应该很容易看懂。
作者:Alias
@@ -638,11 +648,11 @@ https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106
….
依次执行,最后辅助栈为空。如果不为空说明弹出序列不是该栈的弹出顺序。
-#### **考察内容:**
+**考察内容:**
栈
-#### **示例代码:**
+**示例代码:**
```java
import java.util.ArrayList;
diff --git a/docs/cs-basics/data-structure/bloom-filter.md b/docs/cs-basics/data-structure/bloom-filter.md
index ca6421e202f..d013be7471f 100644
--- a/docs/cs-basics/data-structure/bloom-filter.md
+++ b/docs/cs-basics/data-structure/bloom-filter.md
@@ -1,3 +1,11 @@
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
+# 布隆过滤器
+
海量数据处理以及缓存穿透这两个场景让我认识了 布隆过滤器 ,我查阅了一些资料来了解它,但是很多现成资料并不满足我的需求,所以就决定自己总结一篇关于布隆过滤器的文章。希望通过这篇文章让更多人了解布隆过滤器,并且会实际去使用它!
下面我们将分为几个方面来介绍布隆过滤器:
@@ -9,7 +17,7 @@
5. 利用 Google 开源的 Guava 中自带的布隆过滤器。
6. Redis 中的布隆过滤器。
-### 1.什么是布隆过滤器?
+## 什么是布隆过滤器?
首先,我们需要了解布隆过滤器的概念。
@@ -21,7 +29,7 @@
总结:**一个名叫 Bloom 的人提出了一种来检索元素是否在给定大集合中的数据结构,这种数据结构是高效且性能很好的,但缺点是具有一定的错误识别率和删除难度。并且,理论情况下,添加到集合中的元素越多,误报的可能性就越大。**
-### 2.布隆过滤器的原理介绍
+## 布隆过滤器的原理介绍
**当一个元素加入布隆过滤器中的时候,会进行如下操作:**
@@ -45,12 +53,15 @@
综上,我们可以得出:**布隆过滤器说某个元素存在,小概率会误判。布隆过滤器说某个元素不在,那么这个元素一定不在。**
-### 3.布隆过滤器使用场景
+## 布隆过滤器使用场景
1. 判断给定数据是否存在:比如判断一个数字是否存在于包含大量数字的数字集中(数字集很大,5 亿以上!)、 防止缓存穿透(判断请求的数据是否有效避免直接绕过缓存请求数据库)等等、邮箱的垃圾邮件过滤、黑名单功能等等。
2. 去重:比如爬给定网址的时候对已经爬取过的 URL 去重。
-### 4.通过 Java 编程手动实现布隆过滤器
+
+## 编码实战
+
+### 通过 Java 编程手动实现布隆过滤器
我们上面已经说了布隆过滤器的原理,知道了布隆过滤器的原理之后就可以自己手动实现一个了。
@@ -188,7 +199,7 @@ true
true
```
-### 5.利用 Google 开源的 Guava 中自带的布隆过滤器
+### 利用 Google 开源的 Guava 中自带的布隆过滤器
自己实现的目的主要是为了让自己搞懂布隆过滤器的原理,Guava 中布隆过滤器的实现算是比较权威的,所以实际项目中我们不需要手动实现一个布隆过滤器。
@@ -222,26 +233,26 @@ System.out.println(filter.mightContain(1));
System.out.println(filter.mightContain(2));
```
-在我们的示例中,当`mightContain()` 方法返回 _true_ 时,我们可以 99%确定该元素在过滤器中,当过滤器返回 _false_ 时,我们可以 100%确定该元素不存在于过滤器中。
+在我们的示例中,当 `mightContain()` 方法返回 _true_ 时,我们可以 99%确定该元素在过滤器中,当过滤器返回 _false_ 时,我们可以 100%确定该元素不存在于过滤器中。
**Guava 提供的布隆过滤器的实现还是很不错的(想要详细了解的可以看一下它的源码实现),但是它有一个重大的缺陷就是只能单机使用(另外,容量扩展也不容易),而现在互联网一般都是分布式的场景。为了解决这个问题,我们就需要用到 Redis 中的布隆过滤器了。**
-### 6.Redis 中的布隆过滤器
+## Redis 中的布隆过滤器
-#### 6.1 介绍
+### 介绍
Redis v4.0 之后有了 Module(模块/插件) 功能,Redis Modules 让 Redis 可以使用外部模块扩展其功能 。布隆过滤器就是其中的 Module。详情可以查看 Redis 官方对 Redis Modules 的介绍 :https://redis.io/modules
另外,官网推荐了一个 RedisBloom 作为 Redis 布隆过滤器的 Module,地址:https://github.com/RedisBloom/RedisBloom
其他还有:
-- redis-lua-scaling-bloom-filter(lua 脚本实现):https://github.com/erikdubbelboer/redis-lua-scaling-bloom-filter
-- pyreBloom(Python 中的快速 Redis 布隆过滤器) :https://github.com/seomoz/pyreBloom
-- ......
+* redis-lua-scaling-bloom-filter(lua 脚本实现):https://github.com/erikdubbelboer/redis-lua-scaling-bloom-filter
+* pyreBloom(Python 中的快速 Redis 布隆过滤器) :https://github.com/seomoz/pyreBloom
+* ......
RedisBloom 提供了多种语言的客户端支持,包括:Python、Java、JavaScript 和 PHP。
-#### 6.2 使用 Docker 安装
+### 使用 Docker 安装
如果我们需要体验 Redis 中的布隆过滤器非常简单,通过 Docker 就可以了!我们直接在 Google 搜索 **docker redis bloomfilter** 然后在排除广告的第一条搜素结果就找到了我们想要的答案(这是我平常解决问题的一种方式,分享一下),具体地址:https://hub.docker.com/r/redislabs/rebloom/ (介绍的很详细 )。
@@ -254,7 +265,7 @@ root@21396d02c252:/data# redis-cli
127.0.0.1:6379>
```
-#### 6.3 常用命令一览
+### 常用命令一览
> 注意: key : 布隆过滤器的名称,item : 添加的元素。
@@ -263,11 +274,11 @@ root@21396d02c252:/data# redis-cli
3. **`BF.EXISTS`** : 确定元素是否在布隆过滤器中存在。格式:`BF.EXISTS {key} {item}`。
4. **`BF.MEXISTS`** : 确定一个或者多个元素是否在布隆过滤器中存在格式:`BF.MEXISTS {key} {item} [item ...]`。
-另外,`BF.RESERVE` 命令需要单独介绍一下:
+另外, `BF. RESERVE` 命令需要单独介绍一下:
这个命令的格式如下:
-`BF.RESERVE {key} {error_rate} {capacity} [EXPANSION expansion]`。
+`BF. RESERVE {key} {error_rate} {capacity} [EXPANSION expansion]` 。
下面简单介绍一下每个参数的具体含义:
@@ -277,9 +288,9 @@ root@21396d02c252:/data# redis-cli
可选参数:
-- expansion:如果创建了一个新的子过滤器,则其大小将是当前过滤器的大小乘以`expansion`。默认扩展值为 2。这意味着每个后续子过滤器将是前一个子过滤器的两倍。
+* expansion:如果创建了一个新的子过滤器,则其大小将是当前过滤器的大小乘以`expansion`。默认扩展值为 2。这意味着每个后续子过滤器将是前一个子过滤器的两倍。
-#### 6.4 实际使用
+### 实际使用
```shell
127.0.0.1:6379> BF.ADD myFilter java
diff --git "a/docs/cs-basics/data-structure/\345\233\276.md" "b/docs/cs-basics/data-structure/\345\233\276.md"
index 32123a46018..cb9f55c1f88 100644
--- "a/docs/cs-basics/data-structure/\345\233\276.md"
+++ "b/docs/cs-basics/data-structure/\345\233\276.md"
@@ -1,3 +1,9 @@
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
# 图
> 开头还是求点赞,求转发!原创优质公众号,希望大家能让更多人看到我们的文章。
diff --git "a/docs/cs-basics/data-structure/\345\240\206.md" "b/docs/cs-basics/data-structure/\345\240\206.md"
index 9fe222e0d4f..f86308fafe4 100644
--- "a/docs/cs-basics/data-structure/\345\240\206.md"
+++ "b/docs/cs-basics/data-structure/\345\240\206.md"
@@ -1,3 +1,9 @@
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
# 堆
## 什么是堆
diff --git "a/docs/cs-basics/data-structure/\346\240\221.md" "b/docs/cs-basics/data-structure/\346\240\221.md"
index 010cff991ce..34f7d49dba9 100644
--- "a/docs/cs-basics/data-structure/\346\240\221.md"
+++ "b/docs/cs-basics/data-structure/\346\240\221.md"
@@ -1,3 +1,9 @@
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
# 树
树就是一种类似现实生活中的树的数据结构(倒置的树)。任何一颗非空树只有一个根节点。
diff --git "a/docs/cs-basics/data-structure/\347\272\242\351\273\221\346\240\221.md" "b/docs/cs-basics/data-structure/\347\272\242\351\273\221\346\240\221.md"
index 1f13744fa56..ce18d6e0138 100644
--- "a/docs/cs-basics/data-structure/\347\272\242\351\273\221\346\240\221.md"
+++ "b/docs/cs-basics/data-structure/\347\272\242\351\273\221\346\240\221.md"
@@ -1,3 +1,11 @@
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
+# 红黑树
+
**红黑树特点** :
1. 每个节点非红即黑;
diff --git "a/docs/cs-basics/data-structure/\347\272\277\346\200\247\346\225\260\346\215\256\347\273\223\346\236\204.md" "b/docs/cs-basics/data-structure/\347\272\277\346\200\247\346\225\260\346\215\256\347\273\223\346\236\204.md"
index f00264aa6e5..5a55d496696 100644
--- "a/docs/cs-basics/data-structure/\347\272\277\346\200\247\346\225\260\346\215\256\347\273\223\346\236\204.md"
+++ "b/docs/cs-basics/data-structure/\347\272\277\346\200\247\346\225\260\346\215\256\347\273\223\346\236\204.md"
@@ -1,4 +1,10 @@
-# 线性数据结构
+---
+category: 计算机基础
+tag:
+ - 数据结构
+---
+
+# 线性数据结构 :数组、链表、栈、队列
> 开头还是求点赞,求转发!原创优质公众号,希望大家能让更多人看到我们的文章。
>
@@ -305,6 +311,6 @@ myStack.pop();//报错:java.lang.IllegalArgumentException: Stack is empty.
- **阻塞队列:** 阻塞队列可以看成在队列基础上加了阻塞操作的队列。当队列为空的时候,出队操作阻塞,当队列满的时候,入队操作阻塞。使用阻塞队列我们可以很容易实现“生产者 - 消费者“模型。
- **线程池中的请求/任务队列:** 线程池中没有空闲线程时,新的任务请求线程资源时,线程池该如何处理呢?答案是将这些请求放在队列中,当有空闲线程的时候,会循环中反复从队列中获取任务来执行。队列分为无界队列(基于链表)和有界队列(基于数组)。无界队列的特点就是可以一直入列,除非系统资源耗尽,比如 :`FixedThreadPool` 使用无界队列 `LinkedBlockingQueue`。但是有界队列就不一样了,当队列满的话后面再有任务/请求就会拒绝,在 Java 中的体现就是会抛出`java.util.concurrent.RejectedExecutionException` 异常。
- Linux 内核进程队列(按优先级排队)
-- 现实生活中的派对,播放器上的播放列表;
+- 现实生活中的排队,播放器上的播放列表;
- 消息队列
- 等等......
diff --git "a/docs/cs-basics/network/HTTPS\344\270\255\347\232\204TLS.md" "b/docs/cs-basics/network/HTTPS\344\270\255\347\232\204TLS.md"
index 641d7baf501..f665eb22da4 100644
--- "a/docs/cs-basics/network/HTTPS\344\270\255\347\232\204TLS.md"
+++ "b/docs/cs-basics/network/HTTPS\344\270\255\347\232\204TLS.md"
@@ -1,22 +1,9 @@
-
-
-- [1. SSL 与 TLS](#1-ssl-%E4%B8%8E-tls)
-- [2. 从网络协议的角度理解 HTTPS](#2-%E4%BB%8E%E7%BD%91%E7%BB%9C%E5%8D%8F%E8%AE%AE%E7%9A%84%E8%A7%92%E5%BA%A6%E7%90%86%E8%A7%A3-https)
-- [3. 从密码学的角度理解 HTTPS](#3-%E4%BB%8E%E5%AF%86%E7%A0%81%E5%AD%A6%E7%9A%84%E8%A7%92%E5%BA%A6%E7%90%86%E8%A7%A3-https)
- - [3.1. TLS 工作流程](#31-tls-%E5%B7%A5%E4%BD%9C%E6%B5%81%E7%A8%8B)
- - [3.2. 密码基础](#32-%E5%AF%86%E7%A0%81%E5%9F%BA%E7%A1%80)
- - [3.2.1. 伪随机数生成器](#321-%E4%BC%AA%E9%9A%8F%E6%9C%BA%E6%95%B0%E7%94%9F%E6%88%90%E5%99%A8)
- - [3.2.2. 消息认证码](#322-%E6%B6%88%E6%81%AF%E8%AE%A4%E8%AF%81%E7%A0%81)
- - [3.2.3. 数字签名](#323-%E6%95%B0%E5%AD%97%E7%AD%BE%E5%90%8D)
- - [3.2.4. 公钥密码](#324-%E5%85%AC%E9%92%A5%E5%AF%86%E7%A0%81)
- - [3.2.5. 证书](#325-%E8%AF%81%E4%B9%A6)
- - [3.2.6. 密码小结](#326-%E5%AF%86%E7%A0%81%E5%B0%8F%E7%BB%93)
- - [3.3. TLS 使用的密码技术](#33-tls-%E4%BD%BF%E7%94%A8%E7%9A%84%E5%AF%86%E7%A0%81%E6%8A%80%E6%9C%AF)
- - [3.4. TLS 总结](#34-tls-%E6%80%BB%E7%BB%93)
-- [4. RSA 简单示例](#4-rsa-%E7%AE%80%E5%8D%95%E7%A4%BA%E4%BE%8B)
-- [5. 参考](#5-%E5%8F%82%E8%80%83)
-
-
+---
+title: HTTPS中的TLS
+category: 计算机基础
+tag:
+ - 计算机网络
+---
# 1. SSL 与 TLS
diff --git "a/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md" "b/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
similarity index 93%
rename from "docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md"
rename to "docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
index 69a02be43da..ef63192cb18 100644
--- "a/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md"
+++ "b/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230.md"
@@ -1,4 +1,11 @@
-## 一 OSI 与 TCP/IP 各层的结构与功能,都有哪些协议?
+---
+title: 计算机网络常见面试题
+category: 计算机基础
+tag:
+ - 计算机网络
+---
+
+## 一 OSI 与 TCP/IP 各层的结构与功能, 都有哪些协议?
学习计算机网络时我们一般采用折中的办法,也就是中和 OSI 和 TCP/IP 的优点,采用一种只有五层协议的体系结构,这样既简洁又能将概念阐述清楚。
@@ -67,14 +74,16 @@
### 2.1 TCP 三次握手漫画图解
如下图所示,下面的两个机器人通过 3 次握手确定了对方能正确接收和发送消息(图片来源:《图解 HTTP》)。
+

**简单示意图:**
+

-- 客户端–发送带有 SYN 标志的数据包–一次握手–服务端
-- 服务端–发送带有 SYN/ACK 标志的数据包–二次握手–客户端
-- 客户端–发送带有带有 ACK 标志的数据包–三次握手–服务端
+* 客户端–发送带有 SYN 标志的数据包–一次握手–服务端
+* 服务端–发送带有 SYN/ACK 标志的数据包–二次握手–客户端
+* 客户端–发送带有带有 ACK 标志的数据包–三次握手–服务端
**详细示意图(图片来源不详)**
@@ -104,10 +113,10 @@
断开一个 TCP 连接则需要“四次挥手”:
-- 客户端-发送一个 FIN,用来关闭客户端到服务器的数据传送
-- 服务器-收到这个 FIN,它发回一 个 ACK,确认序号为收到的序号加 1 。和 SYN 一样,一个 FIN 将占用一个序号
-- 服务器-关闭与客户端的连接,发送一个 FIN 给客户端
-- 客户端-发回 ACK 报文确认,并将确认序号设置为收到序号加 1
+* 客户端-发送一个 FIN,用来关闭客户端到服务器的数据传送
+* 服务器-收到这个 FIN,它发回一 个 ACK,确认序号为收到的序号加 1 。和 SYN 一样,一个 FIN 将占用一个序号
+* 服务器-关闭与客户端的连接,发送一个 FIN 给客户端
+* 客户端-发回 ACK 报文确认,并将确认序号设置为收到序号加 1
任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了 TCP 连接。
@@ -115,7 +124,7 @@
上面讲的比较概括,推荐一篇讲的比较细致的文章:[https://blog.csdn.net/qzcsu/article/details/72861891](https://blog.csdn.net/qzcsu/article/details/72861891)
-## 三 TCP,UDP 协议的区别
+## 三 TCP, UDP 协议的区别

@@ -146,12 +155,12 @@ TCP 提供面向连接的服务。在传送数据之前必须先建立连接,
**优缺点:**
-- **优点:** 简单
-- **缺点:** 信道利用率低,等待时间长
+* **优点:** 简单
+* **缺点:** 信道利用率低,等待时间长
**1) 无差错情况:**
-发送方发送分组,接收方在规定时间内收到,并且回复确认.发送方再次发送。
+发送方发送分组, 接收方在规定时间内收到, 并且回复确认. 发送方再次发送。
**2) 出现差错情况(超时重传):**
@@ -159,8 +168,8 @@ TCP 提供面向连接的服务。在传送数据之前必须先建立连接,
**3) 确认丢失和确认迟到**
-- **确认丢失** :确认消息在传输过程丢失。当 A 发送 M1 消息,B 收到后,B 向 A 发送了一个 M1 确认消息,但却在传输过程中丢失。而 A 并不知道,在超时计时过后,A 重传 M1 消息,B 再次收到该消息后采取以下两点措施:1. 丢弃这个重复的 M1 消息,不向上层交付。 2. 向 A 发送确认消息。(不会认为已经发送过了,就不再发送。A 能重传,就证明 B 的确认消息丢失)。
-- **确认迟到** :确认消息在传输过程中迟到。A 发送 M1 消息,B 收到并发送确认。在超时时间内没有收到确认消息,A 重传 M1 消息,B 仍然收到并继续发送确认消息(B 收到了 2 份 M1)。此时 A 收到了 B 第二次发送的确认消息。接着发送其他数据。过了一会,A 收到了 B 第一次发送的对 M1 的确认消息(A 也收到了 2 份确认消息)。处理如下:1. A 收到重复的确认后,直接丢弃。2. B 收到重复的 M1 后,也直接丢弃重复的 M1。
+* **确认丢失** :确认消息在传输过程丢失。当 A 发送 M1 消息,B 收到后,B 向 A 发送了一个 M1 确认消息,但却在传输过程中丢失。而 A 并不知道,在超时计时过后,A 重传 M1 消息,B 再次收到该消息后采取以下两点措施:1. 丢弃这个重复的 M1 消息,不向上层交付。 2. 向 A 发送确认消息。(不会认为已经发送过了,就不再发送。A 能重传,就证明 B 的确认消息丢失)。
+* **确认迟到** :确认消息在传输过程中迟到。A 发送 M1 消息,B 收到并发送确认。在超时时间内没有收到确认消息,A 重传 M1 消息,B 仍然收到并继续发送确认消息(B 收到了 2 份 M1)。此时 A 收到了 B 第二次发送的确认消息。接着发送其他数据。过了一会,A 收到了 B 第一次发送的对 M1 的确认消息(A 也收到了 2 份确认消息)。处理如下:1. A 收到重复的确认后,直接丢弃。2. B 收到重复的 M1 后,也直接丢弃重复的 M1。
#### 连续 ARQ 协议
@@ -168,8 +177,8 @@ TCP 提供面向连接的服务。在传送数据之前必须先建立连接,
**优缺点:**
-- **优点:** 信道利用率高,容易实现,即使确认丢失,也不必重传。
-- **缺点:** 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5 条 消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
+* **优点:** 信道利用率高,容易实现,即使确认丢失,也不必重传。
+* **缺点:** 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5 条 消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
### 4.2 滑动窗口和流量控制
@@ -183,9 +192,9 @@ TCP 提供面向连接的服务。在传送数据之前必须先建立连接,
TCP 的拥塞控制采用了四种算法,即 **慢开始** 、 **拥塞避免** 、**快重传** 和 **快恢复**。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。
-- **慢开始:** 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd 初始值为 1,每经过一个传播轮次,cwnd 加倍。
-- **拥塞避免:** 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送放的 cwnd 加 1.
-- **快重传与快恢复:**
+* **慢开始:** 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd 初始值为 1,每经过一个传播轮次,cwnd 加倍。
+* **拥塞避免:** 拥塞避免算法的思路是让拥塞窗口 cwnd 缓慢增大,即每经过一个往返时间 RTT 就把发送放的 cwnd 加 1.
+* **快重传与快恢复:**
在 TCP/IP 中,快速重传和恢复(fast retransmit and recovery,FRR)是一种拥塞控制算法,它能快速恢复丢失的数据包。没有 FRR,如果数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。有了 FRR,如果接收机接收到一个不按顺序的数据段,它会立即给发送机发送一个重复确认。如果发送机接收到三个重复确认,它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。有了 FRR,就不会因为重传时要求的暂停被耽误。 当有单独的数据包丢失时,快速重传和恢复(FRR)能最有效地工作。当有多个数据信息包在某一段很短的时间内丢失时,它则不能很有效地工作。
## 五 在浏览器中输入 url 地址 ->> 显示主页的过程(面试常客)
@@ -196,9 +205,9 @@ TCP 的拥塞控制采用了四种算法,即 **慢开始** 、 **拥塞避免*
图解(图片来源:《图解 HTTP》):
-
+
-> 上图有一个错误,请注意,是 OSPF 不是 OPSF。 OSPF(Open Shortest Path First,ospf)开放最短路径优先协议,是由 Internet 工程任务组开发的路由选择协议
+> 上图有一个错误,请注意,是 OSPF 不是 OPSF。 OSPF(Open Shortest Path First,ospf)开放最短路径优先协议, 是由 Internet 工程任务组开发的路由选择协议
总体来说分为以下几个过程:
@@ -211,7 +220,7 @@ TCP 的拥塞控制采用了四种算法,即 **慢开始** 、 **拥塞避免*
具体可以参考下面这篇文章:
-- [https://segmentfault.com/a/1190000006879700](https://segmentfault.com/a/1190000006879700)
+* [https://segmentfault.com/a/1190000006879700](https://segmentfault.com/a/1190000006879700)
## 六 状态码
@@ -225,7 +234,7 @@ TCP 的拥塞控制采用了四种算法,即 **慢开始** 、 **拥塞避免*

-## 八 HTTP 长连接,短连接
+## 八 HTTP 长连接, 短连接
在 HTTP/1.0 中默认使用短连接。也就是说,客户端和服务器每进行一次 HTTP 操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个 HTML 或其他类型的 Web 页中包含有其他的 Web 资源(如 JavaScript 文件、图像文件、CSS 文件等),每遇到这样一个 Web 资源,浏览器就会重新建立一个 HTTP 会话。
@@ -241,7 +250,7 @@ Connection:keep-alive
—— [《HTTP 长连接、短连接究竟是什么?》](https://www.cnblogs.com/gotodsp/p/6366163.html)
-## 九 HTTP 是不保存状态的协议,如何保存用户状态?
+## 九 HTTP 是不保存状态的协议, 如何保存用户状态?
HTTP 是一种不保存状态,即无状态(stateless)协议。也就是说 HTTP 协议自身不对请求和响应之间的通信状态进行保存。那么我们保存用户状态呢?Session 机制的存在就是为了解决这个问题,Session 的主要作用就是通过服务端记录用户的状态。典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了(一般情况下,服务器会在一定时间内保存这个 Session,过了时间限制,就会销毁这个 Session)。
@@ -253,7 +262,7 @@ HTTP 是一种不保存状态,即无状态(stateless)协议。也就是说

-## 十 Cookie 的作用是什么?和 Session 有什么区别?
+## 十 Cookie 的作用是什么? 和 Session 有什么区别?
Cookie 和 Session 都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。
@@ -276,8 +285,8 @@ HTTP1.0 最早在网页中使用是在 1996 年,那个时候只是使用一些
## 十二 URI 和 URL 的区别是什么?
-- URI(Uniform Resource Identifier) 是统一资源标志符,可以唯一标识一个资源。
-- URL(Uniform Resource Locator) 是统一资源定位符,可以提供该资源的路径。它是一种具体的 URI,即 URL 可以用来标识一个资源,而且还指明了如何 locate 这个资源。
+* URI(Uniform Resource Identifier) 是统一资源标志符,可以唯一标识一个资源。
+* URL(Uniform Resource Locator) 是统一资源定位符,可以提供该资源的路径。它是一种具体的 URI,即 URL 可以用来标识一个资源,而且还指明了如何 locate 这个资源。
URI 的作用像身份证号一样,URL 的作用更像家庭住址一样。URL 是一种具体的 URI,它不仅唯一标识资源,而且还提供了定位该资源的信息。
@@ -294,7 +303,7 @@ URI 的作用像身份证号一样,URL 的作用更像家庭住址一样。URL
## 参考
-- [https://blog.csdn.net/qq_16209077/article/details/52718250](https://blog.csdn.net/qq_16209077/article/details/52718250)
-- [https://blog.csdn.net/zixiaomuwu/article/details/60965466](https://blog.csdn.net/zixiaomuwu/article/details/60965466)
-- [https://blog.csdn.net/turn\_\_back/article/details/73743641](https://blog.csdn.net/turn__back/article/details/73743641)
--
+* [https://blog.csdn.net/qq_16209077/article/details/52718250](https://blog.csdn.net/qq_16209077/article/details/52718250)
+* [https://blog.csdn.net/zixiaomuwu/article/details/60965466](https://blog.csdn.net/zixiaomuwu/article/details/60965466)
+* [https://blog.csdn.net/turn\_\_back/article/details/73743641](https://blog.csdn.net/turn__back/article/details/73743641)
+*
diff --git "a/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\237\245\350\257\206\346\200\273\347\273\223.md" "b/docs/cs-basics/network/\350\260\242\345\270\214\344\273\201\350\200\201\345\270\210\347\232\204\343\200\212\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\343\200\213\345\206\205\345\256\271\346\200\273\347\273\223.md"
similarity index 92%
rename from "docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\237\245\350\257\206\346\200\273\347\273\223.md"
rename to "docs/cs-basics/network/\350\260\242\345\270\214\344\273\201\350\200\201\345\270\210\347\232\204\343\200\212\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\343\200\213\345\206\205\345\256\271\346\200\273\347\273\223.md"
index 7d0db60ac65..df0b07537fd 100644
--- "a/docs/cs-basics/network/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\347\237\245\350\257\206\346\200\273\347\273\223.md"
+++ "b/docs/cs-basics/network/\350\260\242\345\270\214\344\273\201\350\200\201\345\270\210\347\232\204\343\200\212\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234\343\200\213\345\206\205\345\256\271\346\200\273\347\273\223.md"
@@ -1,3 +1,11 @@
+---
+title: 谢希仁老师的《计算机网络》内容总结
+category: 计算机基础
+tag:
+ - 计算机网络
+---
+
+
本文是我在大二学习计算机网络期间整理, 大部分内容都来自于谢希仁老师的《计算机网络》这本书。
为了内容更容易理解,我对之前的整理进行了一波重构,并配上了一些相关的示意图便于理解。
@@ -133,19 +141,19 @@
1. **物理层的主要任务就是确定与传输媒体接口有关的一些特性,如机械特性,电气特性,功能特性,过程特性。**
2. 一个数据通信系统可划分为三大部分,即源系统,传输系统,目的系统。源系统包括源点(或源站,信源)和发送器,目的系统包括接收器和终点。
-3. **通信的目的是传送消息。如话音,文字,图像等都是消息,数据是运送消息的实体。信号则是数据的电器或电磁的表现。**
+3. **通信的目的是传送消息。如话音,文字,图像等都是消息,数据是运送消息的实体。信号则是数据的电气或电磁的表现。**
4. 根据信号中代表消息的参数的取值方式不同,信号可分为模拟信号(或连续信号)和数字信号(或离散信号)。在使用时间域(简称时域)的波形表示数字信号时,代表不同离散数值的基本波形称为码元。
5. 根据双方信息交互的方式,通信可划分为单向通信(或单工通信),双向交替通信(或半双工通信),双向同时通信(全双工通信)。
6. 来自信源的信号称为基带信号。信号要在信道上传输就要经过调制。调制有基带调制和带通调制之分。最基本的带通调制方法有调幅,调频和调相。还有更复杂的调制方法,如正交振幅调制。
7. 要提高数据在信道上的传递速率,可以使用更好的传输媒体,或使用先进的调制技术。但数据传输速率不可能任意被提高。
8. 传输媒体可分为两大类,即导引型传输媒体(双绞线,同轴电缆,光纤)和非导引型传输媒体(无线,红外,大气激光)。
-9. 了有效利用光纤资源,在光纤干线和用户之间广泛使用无源光网络 PON。无源光网络无需配备电源,其长期运营成本和管理成本都很低。最流行的无源光网络是以太网无源光网络 EPON 和吉比特无源光网络 GPON。
+9. 为了有效利用光纤资源,在光纤干线和用户之间广泛使用无源光网络 PON。无源光网络无需配备电源,其长期运营成本和管理成本都很低。最流行的无源光网络是以太网无源光网络 EPON 和吉比特无源光网络 GPON。
### 2.3. 补充
#### 2.3.1. 物理层主要做啥?
-物理层主要做的事情就是 **透明地传送比特流**。也可以将物理层的主要任务描述为确定与传输媒体的接口的一些特性,即:机械特性(接口所用接线器的一些物理属性如形状尺寸),电气特性(接口电缆的各条线上出现的电压的范围),功能特性(某条线上出现的某一电平的电压的意义),过程特性(对于不同功能能的各种可能事件的出现顺序)。
+物理层主要做的事情就是 **透明地传送比特流**。也可以将物理层的主要任务描述为确定与传输媒体的接口的一些特性,即:机械特性(接口所用接线器的一些物理属性如形状和尺寸),电气特性(接口电缆的各条线上出现的电压的范围),功能特性(某条线上出现的某一电平的电压的意义),过程特性(对于不同功能的各种可能事件的出现顺序)。
**物理层考虑的是怎样才能在连接各种计算机的传输媒体上传输数据比特流,而不是指具体的传输媒体。** 现有的计算机网络中的硬件设备和传输媒体的种类非常繁多,而且通信手段也有许多不同的方式。物理层的作用正是尽可能地屏蔽掉这些传输媒体和通信手段的差异,使物理层上面的数据链路层感觉不到这些差异,这样就可以使数据链路层只考虑完成本层的协议和服务,而不必考虑网络的具体传输媒体和通信手段是什么。
@@ -159,7 +167,7 @@
#### 2.3.3. 几种常用的宽带接入技术,主要是 ADSL 和 FTTx
-用户到互联网的宽带接入方法有非对称数字用户线 ADSL(用数字技术对现有的模拟电话线进行改造,而不需要重新布线。ASDL 的快速版本是甚高速数字用户线 VDSL。),光纤同轴混合网 HFC(是在目前覆盖范围很广的有线电视网的基础上开发的一种居民宽带接入网)和 FTTx(即光纤到······)。
+用户到互联网的宽带接入方法有非对称数字用户线 ADSL(用数字技术对现有的模拟电话线进行改造,而不需要重新布线。ADSL 的快速版本是甚高速数字用户线 VDSL。),光纤同轴混合网 HFC(是在目前覆盖范围很广的有线电视网的基础上开发的一种居民宽带接入网)和 FTTx(即光纤到······)。
## 3. 数据链路层(Data Link Layer)
@@ -175,7 +183,7 @@
6. **误码率 BER(Bit Error Rate )** :在一段时间内,传输错误的比特占所传输比特总数的比率。
7. **PPP(Point-to-Point Protocol )** :点对点协议。即用户计算机和 ISP 进行通信时所使用的数据链路层协议。以下是 PPP 帧的示意图:

-8. **MAC 地址(Media Access Control 或者 Medium Access Control)** :意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在 OSI 模型中,第三层网络层负责 IP 地址,第二层数据链路层则负责 MAC 地址。因此一个主机会有一个 MAC 地址,而每个网络位置会有一个专属于它的 IP 地址 。地址是识别某个系统的重要标识符,“名字指出我们所要寻找的资源,地址指出资源所在的地方,路由告诉我们如何到达该处。
+8. **MAC 地址(Media Access Control 或者 Medium Access Control)** :意译为媒体访问控制,或称为物理地址、硬件地址,用来定义网络设备的位置。在 OSI 模型中,第三层网络层负责 IP 地址,第二层数据链路层则负责 MAC 地址。因此一个主机会有一个 MAC 地址,而每个网络位置会有一个专属于它的 IP 地址 。地址是识别某个系统的重要标识符,“名字指出我们所要寻找的资源,地址指出资源所在的地方,路由告诉我们如何到达该处。”

@@ -184,7 +192,7 @@
### 3.2. 重要知识点总结
-1. 链路是从一个结点到相邻节点的一段物理链路,数据链路则在链路的基础上增加了一些必要的硬件(如网络适配器)和软件(如协议的实现)
+1. 链路是从一个结点到相邻结点的一段物理链路,数据链路则在链路的基础上增加了一些必要的硬件(如网络适配器)和软件(如协议的实现)
2. 数据链路层使用的主要是**点对点信道**和**广播信道**两种。
3. 数据链路层传输的协议数据单元是帧。数据链路层的三个基本问题是:**封装成帧**,**透明传输**和**差错检测**
4. **循环冗余检验 CRC** 是一种检错方法,而帧检验序列 FCS 是添加在数据后面的冗余码
@@ -193,7 +201,7 @@
7. **局域网的优点是:具有广播功能,从一个站点可方便地访问全网;便于系统的扩展和逐渐演变;提高了系统的可靠性,可用性和生存性。**
8. 计算机与外接局域网通信需要通过通信适配器(或网络适配器),它又称为网络接口卡或网卡。**计算器的硬件地址就在适配器的 ROM 中**。
9. 以太网采用的无连接的工作方式,对发送的数据帧不进行编号,也不要求对方发回确认。目的站收到有差错帧就把它丢掉,其他什么也不做
-10. 以太网采用的协议是具有冲突检测的**载波监听多点接入 CSMA/CD**。协议的特点是:**发送前先监听,边发送边监听,一旦发现总线上出现了碰撞,就立即停止发送。然后按照退避算法等待一段随机时间后再次发送。** 因此,每一个站点在自己发送数据之后的一小段时间内,存在这遭遇碰撞的可能性。以太网上的各站点平等的争用以太网信道
+10. 以太网采用的协议是具有冲突检测的**载波监听多点接入 CSMA/CD**。协议的特点是:**发送前先监听,边发送边监听,一旦发现总线上出现了碰撞,就立即停止发送。然后按照退避算法等待一段随机时间后再次发送。** 因此,每一个站点在自己发送数据之后的一小段时间内,存在着遭遇碰撞的可能性。以太网上的各站点平等地争用以太网信道
11. 以太网的适配器具有过滤功能,它只接收单播帧,广播帧和多播帧。
12. 使用集线器可以在物理层扩展以太网(扩展后的以太网仍然是一个网络)
@@ -225,9 +233,9 @@
2. 在互联网的交付有两种,一是在本网络直接交付不用经过路由器,另一种是和其他网络的间接交付,至少经过一个路由器,但最后一次一定是直接交付
3. 分类的 IP 地址由网络号字段(指明网络)和主机号字段(指明主机)组成。网络号字段最前面的类别指明 IP 地址的类别。IP 地址是一种分等级的地址结构。IP 地址管理机构分配 IP 地址时只分配网络号,主机号由得到该网络号的单位自行分配。路由器根据目的主机所连接的网络号来转发分组。一个路由器至少连接到两个网络,所以一个路由器至少应当有两个不同的 IP 地址
4. IP 数据报分为首部和数据两部分。首部的前一部分是固定长度,共 20 字节,是所有 IP 数据包必须具有的(源地址,目的地址,总长度等重要地段都固定在首部)。一些长度可变的可选字段固定在首部的后面。IP 首部中的生存时间给出了 IP 数据报在互联网中所能经过的最大路由器数。可防止 IP 数据报在互联网中无限制的兜圈子。
-5. **地址解析协议 ARP 把 IP 地址解析为硬件地址。ARP 的高速缓存可以大大减少网络上的通信量。因为这样可以使主机下次再与同样地址的主机通信时,可以直接从高速缓存中找到所需要的硬件地址而不需要再去广播方式发送 ARP 请求分组**
-6. 无分类域间路由选择 CIDR 是解决目前 IP 地址紧缺的一个好办法。CIDR 记法把 IP 地址后面加上斜线“/”,然后写上前缀所所占的位数。前缀(或网络前缀用来指明网络),前缀后面的部分是后缀,用来指明主机。CIDR 把前缀都相同的连续的 IP 地址组成一个“CIDR 地址块”,IP 地址分配都以 CIDR 地址块为单位。
-7. 网际控制报文协议是 IP 层的协议。ICMP 报文作为 IP 数据报的数据,加上首部后组成 IP 数据报发送出去。使用 ICMP 数据报并不是为了实现可靠传输。ICMP 允许主机或路由器报告差错情况和提供有关异常情况的报告。ICMP 报文的种类有两种 ICMP 差错报告报文和 ICMP 询问报文。
+5. **地址解析协议 ARP 把 IP 地址解析为硬件地址。ARP 的高速缓存可以大大减少网络上的通信量。因为这样可以使主机下次再与同样地址的主机通信时,可以直接从高速缓存中找到所需要的硬件地址而不需要再去以广播方式发送 ARP 请求分组**
+6. 无分类域间路由选择 CIDR 是解决目前 IP 地址紧缺的一个好办法。CIDR 记法在 IP 地址后面加上斜线“/”,然后写上前缀所占的位数。前缀(或网络前缀)用来指明网络,前缀后面的部分是后缀,用来指明主机。CIDR 把前缀都相同的连续的 IP 地址组成一个“CIDR 地址块”,IP 地址分配都以 CIDR 地址块为单位。
+7. 网际控制报文协议是 IP 层的协议。ICMP 报文作为 IP 数据报的数据,加上首部后组成 IP 数据报发送出去。使用 ICMP 数据报并不是为了实现可靠传输。ICMP 允许主机或路由器报告差错情况和提供有关异常情况的报告。ICMP 报文的种类有两种,即 ICMP 差错报告报文和 ICMP 询问报文。
8. **要解决 IP 地址耗尽的问题,最根本的办法是采用具有更大地址空间的新版本 IP 协议-IPv6。** IPv6 所带来的变化有 ① 更大的地址空间(采用 128 位地址)② 灵活的首部格式 ③ 改进的选项 ④ 支持即插即用 ⑤ 支持资源的预分配 ⑥IPv6 的首部改为 8 字节对齐。
9. **虚拟专用网络 VPN 利用公用的互联网作为本机构专用网之间的通信载体。VPN 内使用互联网的专用地址。一个 VPN 至少要有一个路由器具有合法的全球 IP 地址,这样才能和本系统的另一个 VPN 通过互联网进行通信。所有通过互联网传送的数据都需要加密。**
10. MPLS 的特点是:① 支持面向连接的服务质量 ② 支持流量工程,平衡网络负载 ③ 有效的支持虚拟专用网 VPN。MPLS 在入口节点给每一个 IP 数据报打上固定长度的“标记”,然后根据标记在第二层(链路层)用硬件进行转发(在标记交换路由器中进行标记交换),因而转发速率大大加快。
@@ -240,13 +248,13 @@
1. **进程(process)** :指计算机中正在运行的程序实体。
2. **应用进程互相通信** :一台主机的进程和另一台主机中的一个进程交换数据的过程(另外注意通信真正的端点不是主机而是主机中的进程,也就是说端到端的通信是应用进程之间的通信)。
-3. **传输层的复用与分用** :复用指发送方不同的进程都可以通过统一个运输层协议传送数据。分用指接收方的运输层在剥去报文的首部后能把这些数据正确的交付到目的应用进程。
+3. **传输层的复用与分用** :复用指发送方不同的进程都可以通过同一个运输层协议传送数据。分用指接收方的运输层在剥去报文的首部后能把这些数据正确的交付到目的应用进程。
4. **TCP(Transmission Control Protocol)** :传输控制协议。
5. **UDP(User Datagram Protocol)** :用户数据报协议。

-6. **端口(port)** :端口的目的是为了确认对方机器是那个进程在于自己进行交互,比如 MSN 和 QQ 的端口不同,如果没有端口就可能出现 QQ 进程和 MSN 交互错误。端口又称协议端口号。
+6. **端口(port)** :端口的目的是为了确认对方机器的哪个进程在与自己进行交互,比如 MSN 和 QQ 的端口不同,如果没有端口就可能出现 QQ 进程和 MSN 交互错误。端口又称协议端口号。
7. **停止等待协议(stop-and-wait)** :指发送方每发送完一个分组就停止发送,等待对方确认,在收到确认之后在发送下一个分组。
8. **流量控制** : 就是让发送方的发送速率不要太快,既要让接收方来得及接收,也不要使网络发生拥塞。
9. **拥塞控制** :防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。
@@ -256,16 +264,16 @@
1. **运输层提供应用进程之间的逻辑通信,也就是说,运输层之间的通信并不是真正在两个运输层之间直接传输数据。运输层向应用层屏蔽了下面网络的细节(如网络拓补,所采用的路由选择协议等),它使应用进程之间看起来好像两个运输层实体之间有一条端到端的逻辑通信信道。**
2. **网络层为主机提供逻辑通信,而运输层为应用进程之间提供端到端的逻辑通信。**
3. 运输层的两个重要协议是用户数据报协议 UDP 和传输控制协议 TCP。按照 OSI 的术语,两个对等运输实体在通信时传送的数据单位叫做运输协议数据单元 TPDU(Transport Protocol Data Unit)。但在 TCP/IP 体系中,则根据所使用的协议是 TCP 或 UDP,分别称之为 TCP 报文段或 UDP 用户数据报。
-4. **UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 确是一种最有效的工作方式。 TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务,这一难以避免增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。**
-5. 硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层各种协议进程与运输实体进行层间交互的一种地址。UDP 和 TCP 的首部格式中都有源端口和目的端口这两个重要字段。当运输层收到 IP 层交上来的运输层报文时,就能够 根据其首部中的目的端口号把数据交付应用层的目的应用层。(两个进程之间进行通信不光要知道对方 IP 地址而且要知道对方的端口号(为了找到对方计算机中的应用进程))
+4. **UDP 在传送数据之前不需要先建立连接,远地主机在收到 UDP 报文后,不需要给出任何确认。虽然 UDP 不提供可靠交付,但在某些情况下 UDP 确是一种最有效的工作方式。 TCP 提供面向连接的服务。在传送数据之前必须先建立连接,数据传送结束后要释放连接。TCP 不提供广播或多播服务。由于 TCP 要提供可靠的,面向连接的传输服务,难以避免地增加了许多开销,如确认,流量控制,计时器以及连接管理等。这不仅使协议数据单元的首部增大很多,还要占用许多处理机资源。**
+5. 硬件端口是不同硬件设备进行交互的接口,而软件端口是应用层各种协议进程与运输实体进行层间交互的一种地址。UDP 和 TCP 的首部格式中都有源端口和目的端口这两个重要字段。当运输层收到 IP 层交上来的运输层报文时,就能够根据其首部中的目的端口号把数据交付应用层的目的应用层。(两个进程之间进行通信不光要知道对方 IP 地址而且要知道对方的端口号(为了找到对方计算机中的应用进程))
6. 运输层用一个 16 位端口号标志一个端口。端口号只有本地意义,它只是为了标志计算机应用层中的各个进程在和运输层交互时的层间接口。在互联网的不同计算机中,相同的端口号是没有关联的。协议端口号简称端口。虽然通信的终点是应用进程,但只要把所发送的报文交到目的主机的某个合适端口,剩下的工作(最后交付目的进程)就由 TCP 和 UDP 来完成。
-7. 运输层的端口号分为服务器端使用的端口号(0~1023 指派给熟知端口,1024~49151 是登记端口号)和客户端暂时使用的端口号(49152~65535)
+7. 运输层的端口号分为服务器端使用的端口号(0˜1023 指派给熟知端口,1024˜49151 是登记端口号)和客户端暂时使用的端口号(49152˜65535)
8. **UDP 的主要特点是 ① 无连接 ② 尽最大努力交付 ③ 面向报文 ④ 无拥塞控制 ⑤ 支持一对一,一对多,多对一和多对多的交互通信 ⑥ 首部开销小(只有四个字段:源端口,目的端口,长度和检验和)**
9. **TCP 的主要特点是 ① 面向连接 ② 每一条 TCP 连接只能是一对一的 ③ 提供可靠交付 ④ 提供全双工通信 ⑤ 面向字节流**
-10. **TCP 用主机的 IP 地址加上主机上的端口号作为 TCP 连接的端点。这样的端点就叫做套接字(socket)或插口。套接字用(IP 地址:端口号)来表示。每一条 TCP 连接唯一被通信两端的两个端点所确定。**
+10. **TCP 用主机的 IP 地址加上主机上的端口号作为 TCP 连接的端点。这样的端点就叫做套接字(socket)或插口。套接字用(IP 地址:端口号)来表示。每一条 TCP 连接唯一地被通信两端的两个端点所确定。**
11. 停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
12. 为了提高传输效率,发送方可以不使用低效率的停止等待协议,而是采用流水线传输。流水线传输就是发送方可连续发送多个分组,不必每发完一个分组就停下来等待对方确认。这样可使信道上一直有数据不间断的在传送。这种传输方式可以明显提高信道利用率。
-13. 停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重转时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为自动重传请求 ARQ。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。连续 ARQ 协议可提高信道利用率。发送维持一个发送窗口,凡位于发送窗口内的分组可连续发送出去,而不需要等待对方确认。接收方一般采用累积确认,对按序到达的最后一个分组发送确认,表明到这个分组位置的所有分组都已经正确收到了。
+13. 停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重传时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为自动重传请求 ARQ。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。连续 ARQ 协议可提高信道利用率。发送维持一个发送窗口,凡位于发送窗口内的分组可连续发送出去,而不需要等待对方确认。接收方一般采用累积确认,对按序到达的最后一个分组发送确认,表明到这个分组位置的所有分组都已经正确收到了。
14. TCP 报文段的前 20 个字节是固定的,后面有 4n 字节是根据需要增加的选项。因此,TCP 首部的最小长度是 20 字节。
15. **TCP 使用滑动窗口机制。发送窗口里面的序号表示允许发送的序号。发送窗口后沿的后面部分表示已发送且已收到确认,而发送窗口前沿的前面部分表示不允许发送。发送窗口后沿的变化情况有两种可能,即不动(没有收到新的确认)和前移(收到了新的确认)。发送窗口的前沿通常是不断向前移动的。一般来说,我们总是希望数据传输更快一些。但如果发送方把数据发送的过快,接收方就可能来不及接收,这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收。**
16. 在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞。拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点通信量的控制,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便使接收端来得及接收。
@@ -297,7 +305,7 @@
https://www.seobility.net/en/wiki/HTTP_headers
-2. **文件传输协议(FTP)** :FTP 是 File TransferProtocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于 Internet 上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的 FTP 应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在 FTP 的使用当中,用户经常遇到两个概念:"下载"(Download)和"上传"(Upload)。 "下载"文件就是从远程主机拷贝文件至自己的计算机上;"上传"文件就是将文件从自己的计算机中拷贝至远程主机上。用 Internet 语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。
+2. **文件传输协议(FTP)** :FTP 是 File Transfer Protocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于 Internet 上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的 FTP 应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在 FTP 的使用当中,用户经常遇到两个概念:"下载"(Download)和"上传"(Upload)。 "下载"文件就是从远程主机拷贝文件至自己的计算机上;"上传"文件就是将文件从自己的计算机中拷贝至远程主机上。用 Internet 语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。

@@ -332,7 +340,7 @@ HTTP 协议的本质就是一种浏览器与服务器之间约定好的通信格
### 6.2. 重要知识点总结
-1. 文件传输协议(FTP)使用 TCP 可靠的运输服务。FTP 使用客户服务器方式。一个 FTP 服务器进程可以同时为多个用户提供服务。在进进行文件传输时,FTP 的客户和服务器之间要先建立两个并行的 TCP 连接:控制连接和数据连接。实际用于传输文件的是数据连接。
+1. 文件传输协议(FTP)使用 TCP 可靠的运输服务。FTP 使用客户服务器方式。一个 FTP 服务器进程可以同时为多个用户提供服务。在进行文件传输时,FTP 的客户和服务器之间要先建立两个并行的 TCP 连接:控制连接和数据连接。实际用于传输文件的是数据连接。
2. 万维网客户程序与服务器之间进行交互使用的协议是超文本传输协议 HTTP。HTTP 使用 TCP 连接进行可靠传输。但 HTTP 本身是无连接、无状态的。HTTP/1.1 协议使用了持续连接(分为非流水线方式和流水线方式)
3. 电子邮件把邮件发送到收件人使用的邮件服务器,并放在其中的收件人邮箱中,收件人可随时上网到自己使用的邮件服务器读取,相当于电子邮箱。
4. 一个电子邮件系统有三个重要组成构件:用户代理、邮件服务器、邮件协议(包括邮件发送协议,如 SMTP,和邮件读取协议,如 POP3 和 IMAP)。用户代理和邮件服务器都要运行这些协议。
diff --git a/docs/cs-basics/operating-system/linux.md b/docs/cs-basics/operating-system/linux-intro.md
similarity index 90%
rename from docs/cs-basics/operating-system/linux.md
rename to docs/cs-basics/operating-system/linux-intro.md
index 87d4f9370eb..723cd9b7e88 100644
--- a/docs/cs-basics/operating-system/linux.md
+++ b/docs/cs-basics/operating-system/linux-intro.md
@@ -1,45 +1,12 @@
-点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java 面试突击》以及 Java 工程师必备学习资源。
-
-
-
-
-
-
-- [1. 从认识操作系统开始](#1-从认识操作系统开始)
- - [1.1. 操作系统简介](#11-操作系统简介)
- - [1.2. 操作系统简单分类](#12-操作系统简单分类)
- - [1.2.1. Windows](#121-windows)
- - [1.2.2. Unix](#122-unix)
- - [1.2.3. Linux](#123-linux)
- - [1.2.4. Mac OS](#124-mac-os)
- - [1.3. 操作系统的内核(Kernel)](#13-操作系统的内核kernel)
- - [1.4. 中央处理器(CPU,Central Processing Unit)](#14-中央处理器cpucentral-processing-unit)
- - [1.5. CPU vs Kernel(内核)](#15-cpu-vs-kernel内核)
- - [1.6. 系统调用](#16-系统调用)
-- [2. 初探 Linux](#2-初探-linux)
- - [2.1. Linux 简介](#21-linux-简介)
- - [2.2. Linux 诞生](#22-linux-诞生)
- - [2.3. 常见 Linux 发行版本有哪些?](#23-常见-linux-发行版本有哪些)
-- [3. Linux 文件系统概览](#3-linux-文件系统概览)
- - [3.1. Linux 文件系统简介](#31-linux-文件系统简介)
- - [3.2. inode 介绍](#32-inode-介绍)
- - [3.3. Linux 文件类型](#33-linux-文件类型)
- - [3.4. Linux 目录树](#34-linux-目录树)
-- [4. Linux 基本命令](#4-linux-基本命令)
- - [4.1. 目录切换命令](#41-目录切换命令)
- - [4.2. 目录的操作命令(增删改查)](#42-目录的操作命令增删改查)
- - [4.3. 文件的操作命令(增删改查)](#43-文件的操作命令增删改查)
- - [4.4. 压缩文件的操作命令](#44-压缩文件的操作命令)
- - [4.5. Linux 的权限命令](#45-linux-的权限命令)
- - [4.6. Linux 用户管理](#46-linux-用户管理)
- - [4.7. Linux 系统用户组的管理](#47-linux-系统用户组的管理)
- - [4.8. 其他常用命令](#48-其他常用命令)
-- [5. 公众号](#5-公众号)
-
-
-
-
-今天这篇文章中简单介绍一下一个 Java 程序员必知的 Linux 的一些概念以及常见命令。
+---
+title: 后端程序员必备的 Linux 基础知识总结
+category: 计算机基础
+tag:
+ - 操作系统
+ - Linux
+---
+
+简单介绍一下 Java 程序员必知的 Linux 的一些概念以及常见命令。
_如果文章有任何需要改善和完善的地方,欢迎在评论区指出,共同进步!笔芯!_
@@ -443,13 +410,3 @@ Linux 系统是一个多用户多任务的分时操作系统,任何一个要
- **`shutdown`:** `shutdown -h now`: 指定现在立即关机;`shutdown +5 "System will shutdown after 5 minutes"`:指定 5 分钟后关机,同时送出警告信息给登入用户。
- **`reboot`:** **`reboot`:** 重开机。**`reboot -w`:** 做个重开机的模拟(只有纪录并不会真的重开机)。
-
-## 5. 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V3.0 PDF 版本[公众号](#公众号)后台回复 **"Java 面试突击"** 即可免费领取!
-
-**Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
-
-
diff --git a/docs/cs-basics/operating-system/Shell.md b/docs/cs-basics/operating-system/shell-intro.md
similarity index 91%
rename from docs/cs-basics/operating-system/Shell.md
rename to docs/cs-basics/operating-system/shell-intro.md
index 0a7c15080af..074f7bfbe55 100644
--- a/docs/cs-basics/operating-system/Shell.md
+++ b/docs/cs-basics/operating-system/shell-intro.md
@@ -1,33 +1,10 @@
-
-
-
-- [Shell 编程入门](#shell-编程入门)
- - [走进 Shell 编程的大门](#走进-shell-编程的大门)
- - [为什么要学Shell?](#为什么要学shell)
- - [什么是 Shell?](#什么是-shell)
- - [Shell 编程的 Hello World](#shell-编程的-hello-world)
- - [Shell 变量](#shell-变量)
- - [Shell 编程中的变量介绍](#shell-编程中的变量介绍)
- - [Shell 字符串入门](#shell-字符串入门)
- - [Shell 字符串常见操作](#shell-字符串常见操作)
- - [Shell 数组](#shell-数组)
- - [Shell 基本运算符](#shell-基本运算符)
- - [算数运算符](#算数运算符)
- - [关系运算符](#关系运算符)
- - [逻辑运算符](#逻辑运算符)
- - [布尔运算符](#布尔运算符)
- - [字符串运算符](#字符串运算符)
- - [文件相关运算符](#文件相关运算符)
- - [shell流程控制](#shell流程控制)
- - [if 条件语句](#if-条件语句)
- - [for 循环语句](#for-循环语句)
- - [while 语句](#while-语句)
- - [shell 函数](#shell-函数)
- - [不带参数没有返回值的函数](#不带参数没有返回值的函数)
- - [有返回值的函数](#有返回值的函数)
- - [带参数的函数](#带参数的函数)
-
-
+---
+title: Shell 编程入门
+category: 计算机基础
+tag:
+ - 操作系统
+ - Linux
+---
# Shell 编程入门
diff --git a/docs/cs-basics/operating-system/basis.md "b/docs/cs-basics/operating-system/\346\223\215\344\275\234\347\263\273\347\273\237\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230&\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md"
similarity index 97%
rename from docs/cs-basics/operating-system/basis.md
rename to "docs/cs-basics/operating-system/\346\223\215\344\275\234\347\263\273\347\273\237\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230&\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md"
index f35bef6ebee..db158c68faf 100644
--- a/docs/cs-basics/operating-system/basis.md
+++ "b/docs/cs-basics/operating-system/\346\223\215\344\275\234\347\263\273\347\273\237\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230&\347\237\245\350\257\206\347\202\271\346\200\273\347\273\223.md"
@@ -1,3 +1,10 @@
+---
+title: 操作系统常见面试题总结
+category: 计算机基础
+tag:
+ - 操作系统
+---
+
大家好,我是 Guide 哥!
很多读者抱怨计算操作系统的知识点比较繁杂,自己也没有多少耐心去看,但是面试的时候又经常会遇到。所以,我带着我整理好的操作系统的常见问题来啦!这篇文章总结了一些我觉得比较重要的操作系统相关的问题比如**进程管理**、**内存管理**、**虚拟内存**等等。
@@ -102,7 +109,7 @@
1. **管道/匿名管道(Pipes)** :用于具有亲缘关系的父子进程间或者兄弟进程之间的通信。
1. **有名管道(Names Pipes)** : 匿名管道由于没有名字,只能用于亲缘关系的进程间通信。为了克服这个缺点,提出了有名管道。有名管道严格遵循**先进先出(first in first out)**。有名管道以磁盘文件的方式存在,可以实现本机任意两个进程通信。
1. **信号(Signal)** :信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生;
-1. **消息队列(Message Queuing)** :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。**消息队列克服了信号承载信息量少,管道只能承载无格式字 节流以及缓冲区大小受限等缺。**
+1. **消息队列(Message Queuing)** :消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识。管道和消息队列的通信数据都是先进先出的原则。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即,操作系统重启)或者显式地删除一个消息队列时,该消息队列才会被真正的删除。消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比 FIFO 更有优势。**消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺点。**
1. **信号量(Semaphores)** :信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。这种通信方式主要用于解决与同步相关的问题并避免竞争条件。
1. **共享内存(Shared memory)** :使得多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。可以说这是最有用的进程间通信方式。
1. **套接字(Sockets)** : 此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
@@ -113,9 +120,9 @@
🙋 **我** :线程同步是两个或多个共享关键资源的线程的并发执行。应该同步线程以避免关键的资源使用冲突。操作系统一般有下面三种线程同步的方式:
-1. **互斥量(Mutex)**:采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
-1. **信号量(Semphares)** :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
-1. **事件(Event)** :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较操
+1. **互斥量(Mutex)** :采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
+1. **信号量(Semphares)** :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量。
+1. **事件(Event)** :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便地实现多线程优先级的比较操作。
### 2.5 进程的调度算法
@@ -135,7 +142,7 @@
👨💻**面试官** :**你知道什么是死锁吗?**
-🙋 **我** :多个进程可以竞争有限数量的资源。当一个进程申请资源时,如果这时没有可用资源,那么这个进程进入等待状态。有时,如果所申请的资源被其他等待进程占有,那么该等待进程有可能再也无法改变状态。这种情况成为**死锁**。
+🙋 **我** :多个进程可以竞争有限数量的资源。当一个进程申请资源时,如果这时没有可用资源,那么这个进程进入等待状态。有时,如果所申请的资源被其他等待进程占有,那么该等待进程有可能再也无法改变状态。这种情况称为**死锁**。
### 2.7 死锁的四个条件
@@ -213,7 +220,7 @@
🙋 **我** :
1. **共同点** :
- - 分页机制和分段机制都是为了提高内存利用率,较少内存碎片。
+ - 分页机制和分段机制都是为了提高内存利用率,减少内存碎片。
- 页和段都是离散存储的,所以两者都是离散分配内存的方式。但是,每个页和段中的内存是连续的。
2. **区别** :
- 页的大小是固定的,由操作系统决定;而段的大小不固定,取决于我们当前运行的程序。
diff --git a/docs/database/MySQL Index.md b/docs/database/MySQL Index.md
deleted file mode 100644
index 32d8838886f..00000000000
--- a/docs/database/MySQL Index.md
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
-## Mysql索引主要使用的两种数据结构
-
-### 哈希索引
-
-对于哈希索引来说,底层的数据结构就是哈希表,因此在绝大多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余大部分场景,建议选择BTree索引。
-
-### BTree索引
-
-
-
-## 覆盖索引介绍
-
-### 什么是覆盖索引
-
-如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。我们知道InnoDB存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再查找一次。这样就会比较慢覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!
-
-### 覆盖索引使用实例
-
-现在我创建了索引(username,age),我们执行下面的 sql 语句
-
-```sql
-select username , age from user where username = 'Java' and age = 22
-```
-
-在查询数据的时候:要查询出的列在叶子节点都存在!所以,就不用回表。
-
-## 选择索引和编写利用这些索引的查询的3个原则
-
-1. 单行访问是很慢的。特别是在机械硬盘存储中(SSD的随机I/O要快很多,不过这一点仍然成立)。如果服务器从存储中读取一个数据块只是为了获取其中一行,那么就浪费了很多工作。最好读取的块中能包含尽可能多所需要的行。使用索引可以创建位置引,用以提升效率。
-2. 按顺序访问范围数据是很快的,这有两个原因。第一,顺序 I/O 不需要多次磁盘寻道,所以比随机I/O要快很多(特别是对机械硬盘)。第二,如果服务器能够按需要顺序读取数据,那么就不再需要额外的排序操作,并且GROUPBY查询也无须再做排序和将行按组进行聚合计算了。
-3. 索引覆盖查询是很快的。如果一个索引包含了查询需要的所有列,那么存储引擎就不需要再回表查找行。这避免了大量的单行访问,而上面的第1点已经写明单行访问是很慢的。
-
-## 为什么索引能提高查询速度
-
-> 以下内容整理自:
-> 地址: https://juejin.im/post/5b55b842f265da0f9e589e79
-> 作者 :Java3y
-
-### 先从 MySQL 的基本存储结构说起
-
-MySQL的基本存储结构是页(记录都存在页里边):
-
-
-
-
-
- - **各个数据页可以组成一个双向链表**
- - **每个数据页中的记录又可以组成一个单向链表**
- - 每个数据页都会为存储在它里边儿的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录
- - 以其他列(非主键)作为搜索条件:只能从最小记录开始依次遍历单链表中的每条记录。
-
-所以说,如果我们写select * from user where indexname = 'xxx'这样没有进行任何优化的sql语句,默认会这样做:
-
-1. **定位到记录所在的页:需要遍历双向链表,找到所在的页**
-2. **从所在的页内中查找相应的记录:由于不是根据主键查询,只能遍历所在页的单链表了**
-
-很明显,在数据量很大的情况下这样查找会很慢!这样的时间复杂度为O(n)。
-
-
-### 使用索引之后
-
-索引做了些什么可以让我们查询加快速度呢?其实就是将无序的数据变成有序(相对):
-
-
-
-要找到id为8的记录简要步骤:
-
-
-
-很明显的是:没有用索引我们是需要遍历双向链表来定位对应的页,现在通过 **“目录”** 就可以很快地定位到对应的页上了!(二分查找,时间复杂度近似为O(logn))
-
-其实底层结构就是B+树,B+树作为树的一种实现,能够让我们很快地查找出对应的记录。
-
-## 关于索引其他重要的内容补充
-
-> 以下内容整理自:《Java工程师修炼之道》
-
-
-### 最左前缀原则
-
-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 ; // 无法命中索引
-```
-这里需要注意的是,查询的时候如果两个条件都用上了,但是顺序不同,如 `city= xx and name =xx`,那么现在的查询引擎会自动优化为匹配联合索引的顺序,这样是能够命中索引的。
-
-由于最左前缀原则,在创建联合索引时,索引字段的顺序需要考虑字段值去重之后的个数,较多的放前面。ORDER BY子句也遵循此规则。
-
-### 注意避免冗余索引
-
-冗余索引指的是索引的功能相同,能够命中索引(a, b)就肯定能命中索引(a) ,那么索引(a)就是冗余索引。如(name,city)和(name)这两个索引就是冗余索引,能够命中前者的查询肯定是能够命中后者。在大多数情况下,都应该尽量扩展已有的索引而不是创建新索引。
-
-MySQL 5.7 版本后,可以通过查询 sys 库的 `schema_redundant_indexes` 表来查看冗余索引。
-
diff --git "a/docs/database/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"
deleted file mode 100644
index 2da52eec186..00000000000
--- "a/docs/database/Redis/Redis\346\214\201\344\271\205\345\214\226.md"
+++ /dev/null
@@ -1,111 +0,0 @@
-
-非常感谢《redis实战》真本书,本文大多内容也参考了书中的内容。非常推荐大家看一下《redis实战》这本书,感觉书中的很多理论性东西还是很不错的。
-
-为什么本文的名字要加上春夏秋冬又一春,哈哈 ,这是一部韩国的电影,我感觉电影不错,所以就用在文章名字上了,没有什么特别的含义,然后下面的有些配图也是电影相关镜头。
-
-
-
-**很多时候我们需要持久化数据也就是将内存中的数据写入到硬盘里面,大部分原因是为了之后重用数据(比如重启机器、机器故障之后回复数据),或者是为了防止系统故障而将数据备份到一个远程位置。**
-
-Redis不同于Memcached的很重要一点就是,**Redis支持持久化**,而且支持两种不同的持久化操作。Redis的一种持久化方式叫**快照(snapshotting,RDB)**,另一种方式是**只追加文件(append-only file,AOF)**。这两种方法各有千秋,下面我会详细这两种持久化方法是什么,怎么用,如何选择适合自己的持久化方法。
-
-## 快照(snapshotting)持久化
-
-Redis可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本。Redis创建快照之后,可以对快照进行备份,可以将快照复制到其他服务器从而创建具有相同数据的服务器副本(Redis主从结构,主要用来提高Redis性能),还可以将快照留在原地以便重启服务器的时候使用。
-
-
-
-**快照持久化是Redis默认采用的持久化方式**,在redis.conf配置文件中默认有此下配置:
-
-```
-save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
-
-save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
-
-save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,Redis就会自动触发BGSAVE命令创建快照。
-```
-
-根据配置,快照将被写入dbfilename选项指定的文件里面,并存储在dir选项指定的路径上面。如果在新的快照文件创建完毕之前,Redis、系统或者硬件这三者中的任意一个崩溃了,那么Redis将丢失最近一次创建快照写入的所有数据。
-
-举个例子:假设Redis的上一个快照是2:35开始创建的,并且已经创建成功。下午3:06时,Redis又开始创建新的快照,并且在下午3:08快照创建完毕之前,有35个键进行了更新。如果在下午3:06到3:08期间,系统发生了崩溃,导致Redis无法完成新快照的创建工作,那么Redis将丢失下午2:35之后写入的所有数据。另一方面,如果系统恰好在新的快照文件创建完毕之后崩溃,那么Redis将丢失35个键的更新数据。
-
-**创建快照的办法有如下几种:**
-
-- **BGSAVE命令:** 客户端向Redis发送 **BGSAVE命令** 来创建一个快照。对于支持BGSAVE命令的平台来说(基本上所有平台支持,除了Windows平台),Redis会调用fork来创建一个子进程,然后子进程负责将快照写入硬盘,而父进程则继续处理命令请求。
-- **SAVE命令:** 客户端还可以向Redis发送 **SAVE命令** 来创建一个快照,接到SAVE命令的Redis服务器在快照创建完毕之前不会再响应任何其他命令。SAVE命令不常用,我们通常只会在没有足够内存去执行BGSAVE命令的情况下,又或者即使等待持久化操作执行完毕也无所谓的情况下,才会使用这个命令。
-- **save选项:** 如果用户设置了save选项(一般会默认设置),比如 **save 60 10000**,那么从Redis最近一次创建快照之后开始算起,当“60秒之内有10000次写入”这个条件被满足时,Redis就会自动触发BGSAVE命令。
-- **SHUTDOWN命令:** 当Redis通过SHUTDOWN命令接收到关闭服务器的请求时,或者接收到标准TERM信号时,会执行一个SAVE命令,阻塞所有客户端,不再执行客户端发送的任何命令,并在SAVE命令执行完毕之后关闭服务器。
-- **一个Redis服务器连接到另一个Redis服务器:** 当一个Redis服务器连接到另一个Redis服务器,并向对方发送SYNC命令来开始一次复制操作的时候,如果主服务器目前没有执行BGSAVE操作,或者主服务器并非刚刚执行完BGSAVE操作,那么主服务器就会执行BGSAVE命令
-
-如果系统真的发生崩溃,用户将丢失最近一次生成快照之后更改的所有数据。因此,快照持久化只适用于即使丢失一部分数据也不会造成一些大问题的应用程序。不能接受这个缺点的话,可以考虑AOF持久化。
-
-## **AOF(append-only file)持久化**
-与快照持久化相比,AOF持久化 的实时性更好,因此已成为主流的持久化方案。默认情况下Redis没有开启AOF(append only file)方式的持久化,可以通过appendonly参数开启:
-
-```
-appendonly yes
-```
-
-开启AOF持久化后每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件。AOF文件的保存位置和RDB文件的位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof。
-
-
-
-**在Redis的配置文件中存在三种同步方式,它们分别是:**
-
-```
-appendfsync always #每次有数据修改发生时都会写入AOF文件,这样会严重降低Redis的速度
-appendfsync everysec #每秒钟同步一次,显示地将多个写命令同步到硬盘
-appendfsync no #让操作系统决定何时进行同步
-```
-
-**appendfsync always** 可以实现将数据丢失减到最少,不过这种方式需要对硬盘进行大量的写入而且每次只写入一个命令,十分影响Redis的速度。另外使用固态硬盘的用户谨慎使用appendfsync always选项,因为这会明显降低固态硬盘的使用寿命。
-
-为了兼顾数据和写入性能,用户可以考虑 **appendfsync everysec选项** ,让Redis每秒同步一次AOF文件,Redis性能几乎没受到任何影响。而且这样即使出现系统崩溃,用户最多只会丢失一秒之内产生的数据。当硬盘忙于执行写入操作的时候,Redis还会优雅的放慢自己的速度以便适应硬盘的最大写入速度。
-
-**appendfsync no** 选项一般不推荐,这种方案会使Redis丢失不定量的数据而且如果用户的硬盘处理写入操作的速度不够的话,那么当缓冲区被等待写入的数据填满时,Redis的写入操作将被阻塞,这会导致Redis的请求速度变慢。
-
-**虽然AOF持久化非常灵活地提供了多种不同的选项来满足不同应用程序对数据安全的不同要求,但AOF持久化也有缺陷——AOF文件的体积太大。**
-
-## 重写/压缩AOF
-
-AOF虽然在某个角度可以将数据丢失降低到最小而且对性能影响也很小,但是极端的情况下,体积不断增大的AOF文件很可能会用完硬盘空间。另外,如果AOF体积过大,那么还原操作执行时间就可能会非常长。
-
-为了解决AOF体积过大的问题,用户可以向Redis发送 **BGREWRITEAOF命令** ,这个命令会通过移除AOF文件中的冗余命令来重写(rewrite)AOF文件来减小AOF文件的体积。BGREWRITEAOF命令和BGSAVE创建快照原理十分相似,所以AOF文件重写也需要用到子进程,这样会导致性能问题和内存占用问题,和快照持久化一样。更糟糕的是,如果不加以控制的话,AOF文件的体积可能会比快照文件大好几倍。
-
-**文件重写流程:**
-
-
-和快照持久化可以通过设置save选项来自动执行BGSAVE一样,AOF持久化也可以通过设置
-
-```
-auto-aof-rewrite-percentage
-```
-
-选项和
-
-```
-auto-aof-rewrite-min-size
-```
-
-选项自动执行BGREWRITEAOF命令。举例:假设用户对Redis设置了如下配置选项并且启用了AOF持久化。那么当AOF文件体积大于64mb,并且AOF的体积比上一次重写之后的体积大了至少一倍(100%)的时候,Redis将执行BGREWRITEAOF命令。
-
-```
-auto-aof-rewrite-percentage 100
-auto-aof-rewrite-min-size 64mb
-```
-
-无论是AOF持久化还是快照持久化,将数据持久化到硬盘上都是非常有必要的,但除了进行持久化外,用户还必须对持久化得到的文件进行备份(最好是备份到不同的地方),这样才能尽量避免数据丢失事故发生。如果条件允许的话,最好能将快照文件和重新重写的AOF文件备份到不同的服务器上面。
-
-随着负载量的上升,或者数据的完整性变得越来越重要时,用户可能需要使用到复制特性。
-
-## Redis 4.0 对于持久化机制的优化
-Redis 4.0 开始支持 RDB 和 AOF 的混合持久化(默认关闭,可以通过配置项 `aof-use-rdb-preamble` 开启)。
-
-如果把混合持久化打开,AOF 重写的时候就直接把 RDB 的内容写到 AOF 文件开头。这样做的好处是可以结合 RDB 和 AOF 的优点, 快速加载同时避免丢失过多的数据。当然缺点也是有的, AOF 里面的 RDB 部分就是压缩格式不再是 AOF 格式,可读性较差。
-
-参考:
-
-《Redis实战》
-
-[深入学习Redis(2):持久化](https://www.cnblogs.com/kismetv/p/9137897.html)
-
diff --git "a/docs/database/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"
deleted file mode 100644
index 86a15ff6faf..00000000000
--- "a/docs/database/Redis/Redlock\345\210\206\345\270\203\345\274\217\351\224\201.md"
+++ /dev/null
@@ -1,47 +0,0 @@
-这篇文章主要是对 Redis 官方网站刊登的 [Distributed locks with Redis](https://redis.io/topics/distlock) 部分内容的总结和翻译。
-
-## 什么是 RedLock
-
-Redis 官方站这篇文章提出了一种权威的基于 Redis 实现分布式锁的方式名叫 *Redlock*,此种方式比原先的单节点的方法更安全。它可以保证以下特性:
-
-1. 安全特性:互斥访问,即永远只有一个 client 能拿到锁
-2. 避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区
-3. 容错性:只要大部分 Redis 节点存活就可以正常提供服务
-
-## 怎么在单节点上实现分布式锁
-
-> SET resource_name my_random_value NX PX 30000
-
-主要依靠上述命令,该命令仅当 Key 不存在时(NX保证)set 值,并且设置过期时间 3000ms (PX保证),值 my_random_value 必须是所有 client 和所有锁请求发生期间唯一的,释放锁的逻辑是:
-
-```lua
-if redis.call("get",KEYS[1]) == ARGV[1] then
- return redis.call("del",KEYS[1])
-else
- return 0
-end
-```
-
-上述实现可以避免释放另一个client创建的锁,如果只有 del 命令的话,那么如果 client1 拿到 lock1 之后因为某些操作阻塞了很长时间,此时 Redis 端 lock1 已经过期了并且已经被重新分配给了 client2,那么 client1 此时再去释放这把锁就会造成 client2 原本获取到的锁被 client1 无故释放了,但现在为每个 client 分配一个 unique 的 string 值可以避免这个问题。至于如何去生成这个 unique string,方法很多随意选择一种就行了。
-
-## Redlock 算法
-
-算法很易懂,起 5 个 master 节点,分布在不同的机房尽量保证可用性。为了获得锁,client 会进行如下操作:
-
-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) - 申请锁期间流逝的时间
-5. 如果 client 申请锁失败了,那么它就会在少部分申请成功锁的 master 节点上执行释放锁的操作,重置状态
-
-## 失败重试
-
-如果一个 client 申请锁失败了,那么它需要稍等一会在重试避免多个 client 同时申请锁的情况,最好的情况是一个 client 需要几乎同时向 5 个 master 发起锁申请。另外就是如果 client 申请锁失败了它需要尽快在它曾经申请到锁的 master 上执行 unlock 操作,便于其他 client 获得这把锁,避免这些锁过期造成的时间浪费,当然如果这时候网络分区使得 client 无法联系上这些 master,那么这种浪费就是不得不付出的代价了。
-
-## 放锁
-
-放锁操作很简单,就是依次释放所有节点上的锁就行了
-
-## 性能、崩溃恢复和 fsync
-
-如果我们的节点没有持久化机制,client 从 5 个 master 中的 3 个处获得了锁,然后其中一个重启了,这是注意 **整个环境中又出现了 3 个 master 可供另一个 client 申请同一把锁!** 违反了互斥性。如果我们开启了 AOF 持久化那么情况会稍微好转一些,因为 Redis 的过期机制是语义层面实现的,所以在 server 挂了的时候时间依旧在流逝,重启之后锁状态不会受到污染。但是考虑断电之后呢,AOF部分命令没来得及刷回磁盘直接丢失了,除非我们配置刷回策略为 fsnyc = always,但这会损伤性能。解决这个问题的方法是,当一个节点重启之后,我们规定在 max TTL 期间它是不可用的,这样它就不会干扰原本已经申请到的锁,等到它 crash 前的那部分锁都过期了,环境不存在历史锁了,那么再把这个节点加进来正常工作。
diff --git "a/docs/database/Redis/redis\351\233\206\347\276\244\344\273\245\345\217\212\345\272\224\347\224\250\345\234\272\346\231\257.md" "b/docs/database/Redis/redis\351\233\206\347\276\244\344\273\245\345\217\212\345\272\224\347\224\250\345\234\272\346\231\257.md"
deleted file mode 100644
index cd54f067f2c..00000000000
--- "a/docs/database/Redis/redis\351\233\206\347\276\244\344\273\245\345\217\212\345\272\224\347\224\250\345\234\272\346\231\257.md"
+++ /dev/null
@@ -1,269 +0,0 @@
-相关阅读:
-
-- [史上最全Redis高可用技术解决方案大全](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484850&idx=1&sn=3238360bfa8105cf758dcf7354af2814&chksm=cea24a79f9d5c36fb2399aafa91d7fb2699b5006d8d037fe8aaf2e5577ff20ae322868b04a87&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [Raft协议实战之Redis Sentinel的选举Leader源码解析](http://weizijun.cn/2015/04/30/Raft%E5%8D%8F%E8%AE%AE%E5%AE%9E%E6%88%98%E4%B9%8BRedis%20Sentinel%E7%9A%84%E9%80%89%E4%B8%BELeader%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90/)
-
-目录:
-
-
-
-- [Redis 集群以及应用](#redis-集群以及应用)
- - [集群](#集群)
- - [主从复制](#主从复制)
- - [主从链(拓扑结构)](#主从链拓扑结构)
- - [复制模式](#复制模式)
- - [问题点](#问题点)
- - [哨兵机制](#哨兵机制)
- - [拓扑图](#拓扑图)
- - [节点下线](#节点下线)
- - [Leader选举](#Leader选举)
- - [故障转移](#故障转移)
- - [读写分离](#读写分离)
- - [定时任务](#定时任务)
- - [分布式集群(Cluster)](#分布式集群cluster)
- - [拓扑图](#拓扑图)
- - [通讯](#通讯)
- - [集中式](#集中式)
- - [Gossip](#gossip)
- - [寻址分片](#寻址分片)
- - [hash取模](#hash取模)
- - [一致性hash](#一致性hash)
- - [hash槽](#hash槽)
- - [使用场景](#使用场景)
- - [热点数据](#热点数据)
- - [会话维持 Session](#会话维持-session)
- - [分布式锁 SETNX](#分布式锁-setnx)
- - [表缓存](#表缓存)
- - [消息队列 list](#消息队列-list)
- - [计数器 string](#计数器-string)
- - [缓存设计](#缓存设计)
- - [更新策略](#更新策略)
- - [更新一致性](#更新一致性)
- - [缓存粒度](#缓存粒度)
- - [缓存穿透](#缓存穿透)
- - [解决方案](#解决方案)
- - [缓存雪崩](#缓存雪崩)
- - [出现后应对](#出现后应对)
- - [请求过程](#请求过程)
-
-
-
-# Redis 集群以及应用
-
-## 集群
-
-### 主从复制
-
-#### 主从链(拓扑结构)
-
-
-
-
-
-
-
-#### 复制模式
-- 全量复制:Master 全部同步到 Slave
-- 部分复制:Slave 数据丢失进行备份
-
-#### 问题点
-- 同步故障
- - 复制数据延迟(不一致)
- - 读取过期数据(Slave 不能删除数据)
- - 从节点故障
- - 主节点故障
-- 配置不一致
- - maxmemory 不一致:丢失数据
- - 优化参数不一致:内存不一致.
-- 避免全量复制
- - 选择小主节点(分片)、低峰期间操作.
- - 如果节点运行 id 不匹配(如主节点重启、运行 id 发生变化),此时要执行全量复制,应该配合哨兵和集群解决.
- - 主从复制挤压缓冲区不足产生的问题(网络中断,部分复制无法满足),可增大复制缓冲区( rel_backlog_size 参数).
-- 复制风暴
-
-### 哨兵机制
-
-#### 拓扑图
-
-
-
-#### 节点下线
-
-- 主观下线
- - 即 Sentinel 节点对 Redis 节点失败的偏见,超出超时时间认为 Master 已经宕机。
- - Sentinel 集群的每一个 Sentinel 节点会定时对 Redis 集群的所有节点发心跳包检测节点是否正常。如果一个节点在 `down-after-milliseconds` 时间内没有回复 Sentinel 节点的心跳包,则该 Redis 节点被该 Sentinel 节点主观下线。
-- 客观下线
- - 所有 Sentinel 节点对 Redis 节点失败要达成共识,即超过 quorum 个统一。
- - 当节点被一个 Sentinel 节点记为主观下线时,并不意味着该节点肯定故障了,还需要 Sentinel 集群的其他 Sentinel 节点共同判断为主观下线才行。
- - 该 Sentinel 节点会询问其它 Sentinel 节点,如果 Sentinel 集群中超过 quorum 数量的 Sentinel 节点认为该 Redis 节点主观下线,则该 Redis 客观下线。
-
-#### Leader选举
-
-- 选举出一个 Sentinel 作为 Leader:集群中至少有三个 Sentinel 节点,但只有其中一个节点可完成故障转移.通过以下命令可以进行失败判定或领导者选举。
-- 选举流程
- 1. 每个主观下线的 Sentinel 节点向其他 Sentinel 节点发送命令,要求设置它为领导者.
- 2. 收到命令的 Sentinel 节点如果没有同意通过其他 Sentinel 节点发送的命令,则同意该请求,否则拒绝。
- 3. 如果该 Sentinel 节点发现自己的票数已经超过 Sentinel 集合半数且超过 quorum,则它成为领导者。
- 4. 如果此过程有多个 Sentinel 节点成为领导者,则等待一段时间再重新进行选举。
-
-#### 故障转移
-
-- 转移流程
- 1. Sentinel 选出一个合适的 Slave 作为新的 Master(slaveof no one 命令)。
- 2. 向其余 Slave 发出通知,让它们成为新 Master 的 Slave( parallel-syncs 参数)。
- 3. 等待旧 Master 复活,并使之成为新 Master 的 Slave。
- 4. 向客户端通知 Master 变化。
-- 从 Slave 中选择新 Master 节点的规则(slave 升级成 master 之后)
- 1. 选择 slave-priority 最高的节点。
- 2. 选择复制偏移量最大的节点(同步数据最多)。
- 3. 选择 runId 最小的节点。
-
->Sentinel 集群运行过程中故障转移完成,所有 Sentinel 又会恢复平等。Leader 仅仅是故障转移操作出现的角色。
-
-#### 读写分离
-
-#### 定时任务
-
-- 每 1s 每个 Sentinel 对其他 Sentinel 和 Redis 执行 ping,进行心跳检测。
-- 每 2s 每个 Sentinel 通过 Master 的 Channel 交换信息(pub - sub)。
-- 每 10s 每个 Sentinel 对 Master 和 Slave 执行 info,目的是发现 Slave 节点、确定主从关系。
-
-### 分布式集群(Cluster)
-
-#### 拓扑图
-
-
-
-#### 通讯
-
-##### 集中式
-
-> 将集群元数据(节点信息、故障等等)集中存储在某个节点上。
-- 优势
- 1. 元数据的更新读取具有很强的时效性,元数据修改立即更新
-- 劣势
- 1. 数据集中存储
-
-##### Gossip
-
-
-
-- [Gossip 协议](https://www.jianshu.com/p/8279d6fd65bb)
-
-#### 寻址分片
-
-##### hash取模
-
-- hash(key)%机器数量
-- 问题
- 1. 机器宕机,造成数据丢失,数据读取失败
- 1. 伸缩性
-
-##### 一致性hash
-
-- 
-
-- 问题
- 1. 一致性哈希算法在节点太少时,容易因为节点分布不均匀而造成缓存热点的问题。
- - 解决方案
- - 可以通过引入虚拟节点机制解决:即对每一个节点计算多个 hash,每个计算结果位置都放置一个虚拟节点。这样就实现了数据的均匀分布,负载均衡。
-
-##### hash槽
-
-- CRC16(key)%16384
--
-
-
-## 使用场景
-
-### 热点数据
-
-存取数据优先从 Redis 操作,如果不存在再从文件(例如 MySQL)中操作,从文件操作完后将数据存储到 Redis 中并返回。同时有个定时任务后台定时扫描 Redis 的 key,根据业务规则进行淘汰,防止某些只访问一两次的数据一直存在 Redis 中。
->例如使用 Zset 数据结构,存储 Key 的访问次数/最后访问时间作为 Score,最后做排序,来淘汰那些最少访问的 Key。
-
-如果企业级应用,可以参考:[阿里云的 Redis 混合存储版][1]
-
-### 会话维持 Session
-
-会话维持 Session 场景,即使用 Redis 作为分布式场景下的登录中心存储应用。每次不同的服务在登录的时候,都会去统一的 Redis 去验证 Session 是否正确。但是在微服务场景,一般会考虑 Redis + JWT 做 Oauth2 模块。
->其中 Redis 存储 JWT 的相关信息主要是留出口子,方便以后做统一的防刷接口,或者做登录设备限制等。
-
-### 分布式锁 SETNX
-
-命令格式:`SETNX key value`:当且仅当 key 不存在,将 key 的值设为 value。若给定的 key 已经存在,则 SETNX 不做任何动作。
-
-1. 超时时间设置:获取锁的同时,启动守护线程,使用 expire 进行定时更新超时时间。如果该业务机器宕机,守护线程也挂掉,这样也会自动过期。如果该业务不是宕机,而是真的需要这么久的操作时间,那么增加超时时间在业务上也是可以接受的,但是肯定有个最大的阈值。
-2. 但是为了增加高可用,需要使用多台 Redis,就增加了复杂性,就可以参考 Redlock:[Redlock分布式锁](Redlock分布式锁.md#怎么在单节点上实现分布式锁)
-
-### 表缓存
-
-Redis 缓存表的场景有黑名单、禁言表等。访问频率较高,即读高。根据业务需求,可以使用后台定时任务定时刷新 Redis 的缓存表数据。
-
-### 消息队列 list
-
-主要使用了 List 数据结构。
-List 支持在头部和尾部操作,因此可以实现简单的消息队列。
-1. 发消息:在 List 尾部塞入数据。
-2. 消费消息:在 List 头部拿出数据。
-
-同时可以使用多个 List,来实现多个队列,根据不同的业务消息,塞入不同的 List,来增加吞吐量。
-
-### 计数器 string
-
-主要使用了 INCR、DECR、INCRBY、DECRBY 方法。
-
-INCR key:给 key 的 value 值增加一
-DECR key:给 key 的 value 值减去一
-
-## 缓存设计
-
-### 更新策略
-
-- LRU、LFU、FIFO 算法自动清除:一致性最差,维护成本低。
-- 超时自动清除(key expire):一致性较差,维护成本低。
-- 主动更新:代码层面控制生命周期,一致性最好,维护成本高。
-
-在 Redis 根据在 redis.conf 的参数 `maxmemory` 来做更新淘汰策略:
-1. noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。大多数写命令都会导致占用更多的内存(有极少数会例外, 如 DEL 命令)。
-2. allkeys-lru: 所有 key 通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。
-3. volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。
-4. allkeys-random: 所有key通用; 随机删除一部分 key。
-5. volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。
-6. volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。
-
-### 更新一致性
-
-- 读请求:先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。
-- 写请求:先删除缓存,然后再更新数据库(避免大量地写、却又不经常读的数据导致缓存频繁更新)。
-
-### 缓存粒度
-
-- 通用性:全量属性更好。
-- 占用空间:部分属性更好。
-- 代码维护成本。
-
-### 缓存穿透
-
-> 当大量的请求无命中缓存、直接请求到后端数据库(业务代码的 bug、或恶意攻击),同时后端数据库也没有查询到相应的记录、无法添加缓存。
-> 这种状态会一直维持,流量一直打到存储层上,无法利用缓存、还会给存储层带来巨大压力。
-
-#### 解决方案
-
-1. 请求无法命中缓存、同时数据库记录为空时在缓存添加该 key 的空对象(设置过期时间),缺点是可能会在缓存中添加大量的空值键(比如遭到恶意攻击或爬虫),而且缓存层和存储层数据短期内不一致;
-2. 使用布隆过滤器在缓存层前拦截非法请求、自动为空值添加黑名单(同时可能要为误判的记录添加白名单).但需要考虑布隆过滤器的维护(离线生成/ 实时生成)。
-
-### 缓存雪崩
-
-> 缓存崩溃时请求会直接落到数据库上,很可能由于无法承受大量的并发请求而崩溃,此时如果只重启数据库,或因为缓存重启后没有数据,新的流量进来很快又会把数据库击倒。
-
-#### 出现后应对
-
-- 事前:Redis 高可用,主从 + 哨兵,Redis Cluster,避免全盘崩溃。
-- 事中:本地 ehcache 缓存 + hystrix 限流 & 降级,避免数据库承受太多压力。
-- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。
-
-#### 请求过程
-
-1. 用户请求先访问本地缓存,无命中后再访问 Redis,如果本地缓存和 Redis 都没有再查数据库,并把数据添加到本地缓存和 Redis;
-2. 由于设置了限流,一段时间范围内超出的请求走降级处理(返回默认值,或给出友情提示)。
-
diff --git "a/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" "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"
deleted file mode 100644
index 043df96566d..00000000000
--- "a/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"
+++ /dev/null
@@ -1,91 +0,0 @@
-本文是对 [Martin Kleppmann](https://martin.kleppmann.com/) 的文章 [How to do distributed locking](https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html) 部分内容的翻译和总结,上次写 Redlock 的原因就是看到了 Martin 的这篇文章,写得很好,特此翻译和总结。感兴趣的同学可以翻看原文,相信会收获良多。
-
-开篇作者认为现在 Redis 逐渐被使用到数据管理领域,这个领域需要更强的数据一致性和耐久性,这使得他感到担心,因为这不是 Redis 最初设计的初衷(事实上这也是很多业界程序员的误区,越来越把 Redis 当成数据库在使用),其中基于 Redis 的分布式锁就是令人担心的其一。
-
-Martin 指出首先你要明确你为什么使用分布式锁,为了性能还是正确性?为了帮你区分这二者,在这把锁 fail 了的时候你可以询问自己以下问题:
-1. **要性能的:** 拥有这把锁使得你不会重复劳动(例如一个 job 做了两次),如果这把锁 fail 了,两个节点同时做了这个 Job,那么这个 Job 增加了你的成本。
-2. **要正确性的:** 拥有锁可以防止并发操作污染你的系统或者数据,如果这把锁 fail 了两个节点同时操作了一份数据,结果可能是数据不一致、数据丢失、file 冲突等,会导致严重的后果。
-
-上述二者都是需求锁的正确场景,但是你必须清楚自己是因为什么原因需要分布式锁。
-
-如果你只是为了性能,那没必要用 Redlock,它成本高且复杂,你只用一个 Redis 实例也够了,最多加个从防止主挂了。当然,你使用单节点的 Redis 那么断电或者一些情况下,你会丢失锁,但是你的目的只是加速性能且断电这种事情不会经常发生,这并不是什么大问题。并且如果你使用了单节点 Redis,那么很显然你这个应用需要的锁粒度是很模糊粗糙的,也不会是什么重要的服务。
-
-那么是否 Redlock 对于要求正确性的场景就合适呢?Martin 列举了若干场景证明 Redlock 这种算法是不可靠的。
-
-## 用锁保护资源
-这节里 Martin 先将 Redlock 放在了一边而是仅讨论总体上一个分布式锁是怎么工作的。在分布式环境下,锁比 mutex 这类复杂,因为涉及到不同节点、网络通信并且他们随时可能无征兆的 fail 。
-Martin 假设了一个场景,一个 client 要修改一个文件,它先申请得到锁,然后修改文件写回,放锁。另一个 client 再申请锁 ... 代码流程如下:
-
-```java
-// THIS CODE IS BROKEN
-function writeData(filename, data) {
- var lock = lockService.acquireLock(filename);
- if (!lock) {
- throw 'Failed to acquire lock';
- }
-
- try {
- var file = storage.readFile(filename);
- var updated = updateContents(file, data);
- storage.writeFile(filename, updated);
- } finally {
- lock.release();
- }
-}
-```
-
-可惜即使你的锁服务非常完美,上述代码还是可能跪,下面的流程图会告诉你为什么:
-
-
-
-上述图中,得到锁的 client1 在持有锁的期间 pause 了一段时间,例如 GC 停顿。锁有过期时间(一般叫租约,为了防止某个 client 崩溃之后一直占有锁),但是如果 GC 停顿太长超过了锁租约时间,此时锁已经被另一个 client2 所得到,原先的 client1 还没有感知到锁过期,那么奇怪的结果就会发生,曾经 HBase 就发生过这种 Bug。即使你在 client1 写回之前检查一下锁是否过期也无助于解决这个问题,因为 GC 可能在任何时候发生,即使是你非常不便的时候(在最后的检查与写操作期间)。
-如果你认为自己的程序不会有长时间的 GC 停顿,还有其他原因会导致你的进程 pause。例如进程可能读取尚未进入内存的数据,所以它得到一个 page fault 并且等待 page 被加载进缓存;还有可能你依赖于网络服务;或者其他进程占用 CPU;或者其他人意外发生 SIGSTOP 等。
-
-... .... 这里 Martin 又增加了一节列举各种进程 pause 的例子,为了证明上面的代码是不安全的,无论你的锁服务多完美。
-
-## 使用 Fencing (栅栏)使得锁变安全
-修复问题的方法也很简单:你需要在每次写操作时加入一个 fencing token。这个场景下,fencing token 可以是一个递增的数字(lock service 可以做到),每次有 client 申请锁就递增一次:
-
-
-
-client1 申请锁同时拿到 token33,然后它进入长时间的停顿锁也过期了。client2 得到锁和 token34 写入数据,紧接着 client1 活过来之后尝试写入数据,自身 token33 比 34 小因此写入操作被拒绝。注意这需要存储层来检查 token,但这并不难实现。如果你使用 Zookeeper 作为 lock service 的话那么你可以使用 zxid 作为递增数字。
-但是对于 Redlock 你要知道,没什么生成 fencing token 的方式,并且怎么修改 Redlock 算法使其能产生 fencing token 呢?好像并不那么显而易见。因为产生 token 需要单调递增,除非在单节点 Redis 上完成但是这又没有高可靠性,你好像需要引进一致性协议来让 Redlock 产生可靠的 fencing token。
-
-## 使用时间来解决一致性
-Redlock 无法产生 fencing token 早该成为在需求正确性的场景下弃用它的理由,但还有一些值得讨论的地方。
-
-学术界有个说法,算法对时间不做假设:因为进程可能pause一段时间、数据包可能因为网络延迟延后到达、时钟可能根本就是错的。而可靠的算法依旧要在上述假设下做正确的事情。
-
-对于 failure detector 来说,timeout 只能作为猜测某个节点 fail 的依据,因为网络延迟、本地时钟不正确等其他原因的限制。考虑到 Redis 使用 gettimeofday,而不是单调的时钟,会受到系统时间的影响,可能会突然前进或者后退一段时间,这会导致一个 key 更快或更慢地过期。
-
-可见,Redlock 依赖于许多时间假设,它假设所有 Redis 节点都能对同一个 Key 在其过期前持有差不多的时间、跟过期时间相比网络延迟很小、跟过期时间相比进程 pause 很短。
-
-## 用不可靠的时间打破 Redlock
-这节 Martin 举了个因为时间问题,Redlock 不可靠的例子。
-
-1. client1 从 ABC 三个节点处申请到锁,DE由于网络原因请求没有到达
-2. C节点的时钟往前推了,导致 lock 过期
-3. client2 在CDE处获得了锁,AB由于网络原因请求未到达
-4. 此时 client1 和 client2 都获得了锁
-
-**在 Redlock 官方文档中也提到了这个情况,不过是C崩溃的时候,Redlock 官方本身也是知道 Redlock 算法不是完全可靠的,官方为了解决这种问题建议使用延时启动,相关内容可以看之前的[这篇文章](https://zhuanlan.zhihu.com/p/40915772)。但是 Martin 这里分析得更加全面,指出延时启动不也是依赖于时钟的正确性的么?**
-
-接下来 Martin 又列举了进程 Pause 时而不是时钟不可靠时会发生的问题:
-
-1. client1 从 ABCDE 处获得了锁
-2. 当获得锁的 response 还没到达 client1 时 client1 进入 GC 停顿
-3. 停顿期间锁已经过期了
-4. client2 在 ABCDE 处获得了锁
-5. client1 GC 完成收到了获得锁的 response,此时两个 client 又拿到了同一把锁
-
-**同时长时间的网络延迟也有可能导致同样的问题。**
-
-## Redlock 的同步性假设
-这些例子说明了,仅有在你假设了一个同步性系统模型的基础上,Redlock 才能正常工作,也就是系统能满足以下属性:
-
-1. 网络延时边界,即假设数据包一定能在某个最大延时之内到达
-2. 进程停顿边界,即进程停顿一定在某个最大时间之内
-3. 时钟错误边界,即不会从一个坏的 NTP 服务器处取得时间
-
-## 结论
-Martin 认为 Redlock 实在不是一个好的选择,对于需求性能的分布式锁应用它太重了且成本高;对于需求正确性的应用来说它不够安全。因为它对高危的时钟或者说其他上述列举的情况进行了不可靠的假设,如果你的应用只需要高性能的分布式锁不要求多高的正确性,那么单节点 Redis 够了;如果你的应用想要保住正确性,那么不建议 Redlock,建议使用一个合适的一致性协调系统,例如 Zookeeper,且保证存在 fencing token。
diff --git "a/docs/database/mysql/\344\270\200\345\215\203\350\241\214MySQL\345\255\246\344\271\240\347\254\224\350\256\260.md" b/docs/database/mysql/a-thousand-lines-of-mysql-study-notes.md
similarity index 98%
rename from "docs/database/mysql/\344\270\200\345\215\203\350\241\214MySQL\345\255\246\344\271\240\347\254\224\350\256\260.md"
rename to docs/database/mysql/a-thousand-lines-of-mysql-study-notes.md
index bf8b5e58dac..53350ec5ae7 100644
--- "a/docs/database/mysql/\344\270\200\345\215\203\350\241\214MySQL\345\255\246\344\271\240\347\254\224\350\256\260.md"
+++ b/docs/database/mysql/a-thousand-lines-of-mysql-study-notes.md
@@ -1,35 +1,15 @@
+---
+title: 一千行 MySQL 学习笔记
+category: 数据库
+tag:
+ - MySQL
+---
+
> 原文地址:https://shockerli.net/post/1000-line-mysql-note/ ,JavaGuide 对本文进行了简答排版,新增了目录。
> 作者:格物
非常不错的总结,强烈建议保存下来,需要的时候看一看。
-
-- [基本操作](#基本操作)
-- [数据库操作](#数据库操作)
-- [表的操作](#表的操作)
-- [数据操作](#数据操作)
-- [字符集编码](#字符集编码)
-- [数据类型(列类型)](#数据类型列类型)
-- [列属性(列约束)](#列属性列约束)
-- [建表规范](#建表规范)
-- [SELECT](#select)
-- [UNION](#union)
-- [子查询](#子查询)
-- [连接查询(join)](#连接查询join)
-- [TRUNCATE](#truncate)
-- [备份与还原](#备份与还原)
-- [视图](#视图)
-- [事务(transaction)](#事务transaction)
-- [锁表](#锁表)
-- [触发器](#触发器)
-- [SQL编程](#sql编程)
-- [存储过程](#存储过程)
-- [用户和权限管理](#用户和权限管理)
-- [表维护](#表维护)
-- [杂项](#杂项)
-
-
-
### 基本操作
```mysql
diff --git "a/docs/database/mysql/\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/mysql/how-sql-executed-in-mysql.md
similarity index 90%
rename from "docs/database/mysql/\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"
rename to docs/database/mysql/how-sql-executed-in-mysql.md
index 9798df73c80..07404d0e930 100644
--- "a/docs/database/mysql/\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/mysql/how-sql-executed-in-mysql.md
@@ -1,22 +1,11 @@
-本文来自[木木匠](https://github.com/kinglaw1204)投稿。
-
-
+---
+title: 一条 SQL 语句在 MySQL 中如何被执行的?
+category: 数据库
+tag:
+ - MySQL
+---
-- [一 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-更新语句)
-- [三 总结](#三-总结)
-- [四 参考](#四-参考)
-
-
+本文来自[木木匠](https://github.com/kinglaw1204)投稿。
本篇文章会分析下一个 sql 语句在 MySQL 中的执行流程,包括 sql 的查询在 MySQL 内部会怎么流转,sql 语句的更新是怎么完成的。
@@ -30,13 +19,13 @@
先简单介绍一下下图涉及的一些组件的基本作用帮助大家理解这幅图,在 1.2 节中会详细介绍到这些组件的作用。
-- **连接器:**身份认证和权限相关(登录 MySQL 的时候)。
-- **查询缓存:**执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
+- **连接器:** 身份认证和权限相关(登录 MySQL 的时候)。
+- **查询缓存:** 执行查询语句的时候,会先查询缓存(MySQL 8.0 版本后移除,因为这个功能不太实用)。
- **分析器:** 没有命中缓存的话,SQL 语句就会经过分析器,分析器说白了就是要先看你的 SQL 语句要干嘛,再检查你的 SQL 语句语法是否正确。
-- **优化器:**按照 MySQL 认为最优的方案去执行。
-- **执行器:**执行语句,然后从存储引擎返回数据。
+- **优化器:** 按照 MySQL 认为最优的方案去执行。
+
-
+
简单来说 MySQL 主要分为 Server 层和存储引擎层:
diff --git "a/docs/database/mysql/InnoDB\345\257\271MVCC\347\232\204\345\256\236\347\216\260.md" b/docs/database/mysql/innodb-implementation-of-mvcc.md
similarity index 95%
rename from "docs/database/mysql/InnoDB\345\257\271MVCC\347\232\204\345\256\236\347\216\260.md"
rename to docs/database/mysql/innodb-implementation-of-mvcc.md
index 02b88c284e0..96fa1f7982b 100644
--- "a/docs/database/mysql/InnoDB\345\257\271MVCC\347\232\204\345\256\236\347\216\260.md"
+++ b/docs/database/mysql/innodb-implementation-of-mvcc.md
@@ -1,20 +1,9 @@
-
-
-- [一致性非锁定读和锁定读](#一致性非锁定读和锁定读)
- - [一致性非锁定读](#一致性非锁定读)
- - [锁定读](#锁定读)
-- [InnoDB 对 MVCC 的实现](#InnoDB对MVCC的实现)
- - [隐藏字段](#隐藏字段])
- - [ReadView](#ReadView)
- - [undo-log](#undo-log)
- - [数据可见性算法](#数据可见性算法)
-- [RC、RR 隔离级别下 MVCC 的差异](#RC、RR隔离级别下MVCC的差异)
-- [MVCC 解决不可重复读问题](#MVCC解决不可重复读问题)
- - [在 RC 下 ReadView 生成情况](#在RC下ReadView生成情况)
- - [在 RR 下 ReadView 生成情况](#在RR下ReadView生成情况)
-- [MVCC+Next-key-Lock 防止幻读](#MVCC➕Next-key-Lock防止幻读)
-
-
+---
+title: InnoDB存储引擎对MVCC的实现
+category: 数据库
+tag:
+ - MySQL
+---
## 一致性非锁定读和锁定读
diff --git "a/docs/database/mysql/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/mysql-high-performance-optimization-specification-recommendations.md
similarity index 76%
rename from "docs/database/mysql/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"
rename to docs/database/mysql/mysql-high-performance-optimization-specification-recommendations.md
index 240a1dd900f..7c2b7def8ad 100644
--- "a/docs/database/mysql/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/mysql-high-performance-optimization-specification-recommendations.md
@@ -1,58 +1,11 @@
-> 作者: 听风,原文地址: 。JavaGuide 已获得作者授权。
+---
+title: MySQL 高性能优化规范建议
+category: 数据库
+tag:
+ - MySQL
+---
-
-
-- [数据库命令规范](#数据库命令规范)
-- [数据库基本设计规范](#数据库基本设计规范)
- - [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-对于程序连接数据库账号遵循权限最小原则)
-
-
+> 作者: 听风,原文地址: 。JavaGuide 已获得作者授权。
## 数据库命令规范
diff --git "a/docs/database/mysql/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md" b/docs/database/mysql/mysql-index.md
similarity index 99%
rename from "docs/database/mysql/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md"
rename to docs/database/mysql/mysql-index.md
index d797144ec21..5dd4e526492 100644
--- "a/docs/database/mysql/MySQL\346\225\260\346\215\256\345\272\223\347\264\242\345\274\225.md"
+++ b/docs/database/mysql/mysql-index.md
@@ -1,3 +1,12 @@
+---
+title: MySQL 索引详解
+category: 数据库
+tag:
+ - MySQL
+---
+
+
+
## 何为索引?有什么作用?
**索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树, B+树和 Hash。**
diff --git "a/docs/database/mysql/MySQL\344\270\211\345\244\247\346\227\245\345\277\227.md" b/docs/database/mysql/mysql-logs.md
similarity index 99%
rename from "docs/database/mysql/MySQL\344\270\211\345\244\247\346\227\245\345\277\227.md"
rename to docs/database/mysql/mysql-logs.md
index ee621ba0826..697cf30f6a1 100644
--- "a/docs/database/mysql/MySQL\344\270\211\345\244\247\346\227\245\345\277\227.md"
+++ b/docs/database/mysql/mysql-logs.md
@@ -1,3 +1,12 @@
+---
+title: MySQL三大日志(binlog、redo log和undo log)详解
+category: 数据库
+tag:
+ - MySQL
+---
+
+
+
> 本文来自公号程序猿阿星投稿,JavaGuide 对其做了补充完善。
## 前言
diff --git "a/docs/database/mysql/MySQL\346\200\273\347\273\223.md" "b/docs/database/mysql/mysql\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 99%
rename from "docs/database/mysql/MySQL\346\200\273\347\273\223.md"
rename to "docs/database/mysql/mysql\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index 377935254d0..b07247b20f5 100644
--- "a/docs/database/mysql/MySQL\346\200\273\347\273\223.md"
+++ "b/docs/database/mysql/mysql\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,3 +1,12 @@
+---
+title: MySQL知识点&面试题总结
+category: 数据库
+tag:
+ - MySQL
+ - 大厂面试
+---
+
+
## MySQL 基础
### 关系型数据库介绍
diff --git "a/docs/database/mysql/\345\205\263\344\272\216\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250\346\227\266\351\227\264\347\232\204\344\270\200\347\202\271\346\200\235\350\200\203.md" b/docs/database/mysql/some-thoughts-on-database-storage-time.md
similarity index 95%
rename from "docs/database/mysql/\345\205\263\344\272\216\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250\346\227\266\351\227\264\347\232\204\344\270\200\347\202\271\346\200\235\350\200\203.md"
rename to docs/database/mysql/some-thoughts-on-database-storage-time.md
index 8eccaff2f0f..ccad646e5d4 100644
--- "a/docs/database/mysql/\345\205\263\344\272\216\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250\346\227\266\351\227\264\347\232\204\344\270\200\347\202\271\346\200\235\350\200\203.md"
+++ b/docs/database/mysql/some-thoughts-on-database-storage-time.md
@@ -1,3 +1,12 @@
+---
+title: 关于数据库中如何存储时间的一点思考
+category: 数据库
+tag:
+ - MySQL
+---
+
+
+
我们平时开发中不可避免的就是要存储时间,比如我们要记录操作表中这条记录的时间、记录转账的交易时间、记录出发时间等等。你会发现时间这个东西与我们开发的联系还是非常紧密的,用的好与不好会给我们的业务甚至功能带来很大的影响。所以,我们有必要重新出发,好好认识一下这个东西。
这是一篇短小精悍的文章,仔细阅读一定能学到不少东西!
@@ -150,11 +159,4 @@ MySQL 中时间到底怎么存储才好?Datetime?Timestamp? 数值保存的时
每种方式都有各自的优势,根据实际场景才是王道。下面再对这三种方式做一个简单的对比,以供大家实际开发中选择正确的存放时间的数据类型:
-
-
-如果还有什么问题欢迎给我留言!如果文章有什么问题的话,也劳烦指出,Guide 哥感激不尽!
-
-后面的文章我会介绍:
-
-- [ ] Java8 对日期的支持以及为啥不能用 SimpleDateFormat。
-- [ ] SpringBoot 中如何实际使用(JPA 为例)
\ No newline at end of file
+
\ No newline at end of file
diff --git "a/docs/database/mysql/\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/mysql/transaction-isolation-level.md
similarity index 93%
rename from "docs/database/mysql/\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"
rename to docs/database/mysql/transaction-isolation-level.md
index 19cbd71e2e6..4be2f5fde44 100644
--- "a/docs/database/mysql/\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/mysql/transaction-isolation-level.md
@@ -1,20 +1,12 @@
+---
+title: 事务隔离级别(图文详解)
+category: 数据库
+tag:
+ - MySQL
+---
+
+
> 本文由 [SnailClimb](https://github.com/Snailclimb) 和 [guang19](https://github.com/guang19) 共同完成。
-
-
-- [事务隔离级别(图文详解)](#事务隔离级别图文详解)
- - [什么是事务?](#什么是事务)
- - [事务的特性(ACID)](#事务的特性acid)
- - [并发事务带来的问题](#并发事务带来的问题)
- - [事务隔离级别](#事务隔离级别)
- - [实际情况演示](#实际情况演示)
- - [脏读(读未提交)](#脏读读未提交)
- - [避免脏读(读已提交)](#避免脏读读已提交)
- - [不可重复读](#不可重复读)
- - [可重复读](#可重复读)
- - [防止幻读(可重复读)](#防止幻读可重复读)
- - [参考](#参考)
-
-
## 事务隔离级别(图文详解)
diff --git "a/docs/database/mysql/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214\346\225\260\346\215\256\345\272\223\351\203\250\345\210\206\347\232\204\344\270\200\344\272\233\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/database/mysql/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214\346\225\260\346\215\256\345\272\223\351\203\250\345\210\206\347\232\204\344\270\200\344\272\233\346\234\200\344\275\263\345\256\236\350\267\265.md"
deleted file mode 100644
index b3031d50b0d..00000000000
--- "a/docs/database/mysql/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214\346\225\260\346\215\256\345\272\223\351\203\250\345\210\206\347\232\204\344\270\200\344\272\233\346\234\200\344\275\263\345\256\236\350\267\265.md"
+++ /dev/null
@@ -1,41 +0,0 @@
-# 阿里巴巴Java开发手册数据库部分的一些最佳实践总结
-
-## 模糊查询
-
-对于模糊查询阿里巴巴开发手册这样说到:
-
-> 【强制】页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。
->
-> 说明:索引文件具有 B-Tree 的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。
-
-## 外键和级联
-
-对于外键和级联,阿里巴巴开发手册这样说到:
-
->【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
->
->说明:以学生和成绩的关系为例,学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风 险;外键影响数据库的插入速度
-
-为什么不要用外键呢?大部分人可能会这样回答:
-
-> 1. **增加了复杂性:** a.每次做DELETE 或者UPDATE都必须考虑外键约束,会导致开发的时候很痛苦,测试数据极为不方便;b.外键的主从关系是定的,假如那天需求有变化,数据库中的这个字段根本不需要和其他表有关联的话就会增加很多麻烦。
-> 2. **增加了额外工作**: 数据库需要增加维护外键的工作,比如当我们做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,保证数据的的一致性和正确性,这样会不得不消耗资源;(个人觉得这个不是不用外键的原因,因为即使你不使用外键,你在应用层面也还是要保证的。所以,我觉得这个影响可以忽略不计。)
-> 3. 外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;
-> 4. **对分库分表不友好** :因为分库分表下外键是无法生效的。
-> 5. ......
-
-我个人觉得上面这种回答不是特别的全面,只是说了外键存在的一个常见的问题。实际上,我们知道外键也是有很多好处的,比如:
-
-1. 保证了数据库数据的一致性和完整性;
-2. 级联操作方便,减轻了程序代码量;
-3. ......
-
-所以说,不要一股脑的就抛弃了外键这个概念,既然它存在就有它存在的道理,如果系统不涉及分库分表,并发量不是很高的情况还是可以考虑使用外键的。
-
-我个人是不太喜欢外键约束,比较喜欢在应用层去进行相关操作。
-
-## 关于@Transactional注解
-
-对于`@Transactional`事务注解,阿里巴巴开发手册这样说到:
-
->【参考】@Transactional事务不要滥用。事务会影响数据库的QPS,另外使用事务的地方需要考虑各方面的回滚方案,包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等。
diff --git "a/docs/database/Redis/3\347\247\215\345\270\270\347\224\250\347\232\204\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245.md" b/docs/database/redis/3-commonly-used-cache-read-and-write-strategies.md
similarity index 98%
rename from "docs/database/Redis/3\347\247\215\345\270\270\347\224\250\347\232\204\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245.md"
rename to docs/database/redis/3-commonly-used-cache-read-and-write-strategies.md
index 21332e5dd41..841067861f2 100644
--- "a/docs/database/Redis/3\347\247\215\345\270\270\347\224\250\347\232\204\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245.md"
+++ b/docs/database/redis/3-commonly-used-cache-read-and-write-strategies.md
@@ -1,3 +1,11 @@
+---
+title: 3种常用的缓存读写策略
+category: 数据库
+tag:
+ - Redis
+---
+
+
看到很多小伙伴简历上写了“**熟练使用缓存**”,但是被我问到“**缓存常用的3种读写策略**”的时候却一脸懵逼。
在我看来,造成这个问题的原因是我们在学习 Redis 的时候,可能只是简单了写一些 Demo,并没有去关注缓存的读写策略,或者说压根不知道这回事。
diff --git a/docs/database/redis/images/redis-all/redis-list.drawio b/docs/database/redis/images/redis-all/redis-list.drawio
new file mode 100644
index 00000000000..afa767154b7
--- /dev/null
+++ b/docs/database/redis/images/redis-all/redis-list.drawio
@@ -0,0 +1 @@
+7VlNc5swFPw1PiaDENjmmNjpx6Gdjt1J2lNHAzKoEYgRcmzn11cYyRgJT1w3DnScU3grIaHd5b2HM4CTdP2Rozz5wiJMB64TrQdwOnBdEEAo/5TIpkICx6mAmJNITaqBOXnGCtTTliTCRWOiYIwKkjfBkGUZDkUDQ5yzVXPagtHmrjmKsQXMQ0Rt9IFEIqnQsTuq8U+YxIneGQyDaiRFerI6SZGgiK32IHg3gBPOmKiu0vUE05I8zUt134cDo7sH4zgTx9wwu/+V/H4g/myezsD35/vZ56/ulVrlCdGlOrB6WLHRDHC2zCJcLgIG8HaVEIHnOQrL0ZXUXGKJSKkaLh6xCBMVLFgmlKJgJGO1F+YCrw8eAuyokZ7CLMWCb+QUdcOVp9hUdnKhile1OL62WLInzEhhSPkh3i1dUyYvFGt/waBrMbi9BD3lUfPm2bwFLbT556INttPWc/sB035d0+i10wj7TaM77hmNw5fTIM6im7KeyCikqChI2ORMHp1vfsjA0cHPMrh2fR1P1/uj042KjiAbR1aRMqiWVRHxGIuXUr0tSSNxHqacY4oEeWo+RpsOaodvjMgHrPM2gKbk4+YaBVvyEKvb9suYuZLpHdcwRUWEtdDWF7tzn26V0f9ula4s4A0N4cbOtX+aB3zfWupNPaCb01cxAXjPF0cofGq68AJjIT8wXXdusxzRY/fbLJ0VDbPbOj1j2PXnrVOG/Z3A82WRWFaQXZUwujHB2SOeMMq4RDKW4VJLQqkBIUrirHSQVA9L/Lbs0Yj8lL1RAymJonKb1vavbhCP9M0/dYA+OFDF95zltTjLLPav1gECu5PmOcvf5aloD7qWx7fkoRf8+siiYggEuhbI/oSil/v+2Pp0/gLZ3y18u20/BTqDJp5O8VoSp2tJxvYrgxcXpIjV351PERnWv7RXPV39/wp49wc=
\ No newline at end of file
diff --git a/docs/database/redis/images/redis-all/redis-list.png b/docs/database/redis/images/redis-all/redis-list.png
new file mode 100644
index 00000000000..4fb4e36cb49
Binary files /dev/null and b/docs/database/redis/images/redis-all/redis-list.png differ
diff --git a/docs/database/redis/images/redis-all/redis-rollBack.png b/docs/database/redis/images/redis-all/redis-rollBack.png
new file mode 100644
index 00000000000..91f7f46d66d
Binary files /dev/null and b/docs/database/redis/images/redis-all/redis-rollBack.png differ
diff --git a/docs/database/redis/images/redis-all/redis-vs-memcached.png b/docs/database/redis/images/redis-all/redis-vs-memcached.png
new file mode 100644
index 00000000000..23844d67e6f
Binary files /dev/null and b/docs/database/redis/images/redis-all/redis-vs-memcached.png differ
diff --git a/docs/database/redis/images/redis-all/redis4.0-more-thread.png b/docs/database/redis/images/redis-all/redis4.0-more-thread.png
new file mode 100644
index 00000000000..e7e19e52e17
Binary files /dev/null and b/docs/database/redis/images/redis-all/redis4.0-more-thread.png differ
diff --git "a/docs/database/redis/images/redis-all/redis\344\272\213\344\273\266\345\244\204\347\220\206\345\231\250.png" "b/docs/database/redis/images/redis-all/redis\344\272\213\344\273\266\345\244\204\347\220\206\345\231\250.png"
new file mode 100644
index 00000000000..fc280fffaba
Binary files /dev/null and "b/docs/database/redis/images/redis-all/redis\344\272\213\344\273\266\345\244\204\347\220\206\345\231\250.png" differ
diff --git "a/docs/database/redis/images/redis-all/redis\344\272\213\345\212\241.png" "b/docs/database/redis/images/redis-all/redis\344\272\213\345\212\241.png"
new file mode 100644
index 00000000000..eb0c404cafd
Binary files /dev/null and "b/docs/database/redis/images/redis-all/redis\344\272\213\345\212\241.png" differ
diff --git "a/docs/database/redis/images/redis-all/redis\350\277\207\346\234\237\346\227\266\351\227\264.png" "b/docs/database/redis/images/redis-all/redis\350\277\207\346\234\237\346\227\266\351\227\264.png"
new file mode 100644
index 00000000000..27df6ead8e4
Binary files /dev/null and "b/docs/database/redis/images/redis-all/redis\350\277\207\346\234\237\346\227\266\351\227\264.png" differ
diff --git a/docs/database/redis/images/redis-all/try-redis.png b/docs/database/redis/images/redis-all/try-redis.png
new file mode 100644
index 00000000000..cd21a6518e4
Binary files /dev/null and b/docs/database/redis/images/redis-all/try-redis.png differ
diff --git a/docs/database/redis/images/redis-all/what-is-redis.png b/docs/database/redis/images/redis-all/what-is-redis.png
new file mode 100644
index 00000000000..913881ac6cf
Binary files /dev/null and b/docs/database/redis/images/redis-all/what-is-redis.png differ
diff --git "a/docs/database/redis/images/redis-all/\344\275\277\347\224\250\347\274\223\345\255\230\344\271\213\345\220\216.png" "b/docs/database/redis/images/redis-all/\344\275\277\347\224\250\347\274\223\345\255\230\344\271\213\345\220\216.png"
new file mode 100644
index 00000000000..2c73bd90276
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\344\275\277\347\224\250\347\274\223\345\255\230\344\271\213\345\220\216.png" differ
diff --git "a/docs/database/redis/images/redis-all/\345\212\240\345\205\245\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250\345\220\216\347\232\204\347\274\223\345\255\230\345\244\204\347\220\206\346\265\201\347\250\213.png" "b/docs/database/redis/images/redis-all/\345\212\240\345\205\245\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250\345\220\216\347\232\204\347\274\223\345\255\230\345\244\204\347\220\206\346\265\201\347\250\213.png"
new file mode 100644
index 00000000000..a2c2ed6906f
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\345\212\240\345\205\245\345\270\203\351\232\206\350\277\207\346\273\244\345\231\250\345\220\216\347\232\204\347\274\223\345\255\230\345\244\204\347\220\206\346\265\201\347\250\213.png" differ
diff --git "a/docs/database/redis/images/redis-all/\345\215\225\344\275\223\346\236\266\346\236\204.png" "b/docs/database/redis/images/redis-all/\345\215\225\344\275\223\346\236\266\346\236\204.png"
new file mode 100644
index 00000000000..648a404af8c
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\345\215\225\344\275\223\346\236\266\346\236\204.png" differ
diff --git "a/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\232\204\345\244\204\347\220\206\346\265\201\347\250\213.png" "b/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\232\204\345\244\204\347\220\206\346\265\201\347\250\213.png"
new file mode 100644
index 00000000000..11860ae1f02
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\232\204\345\244\204\347\220\206\346\265\201\347\250\213.png" differ
diff --git "a/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\251\277\351\200\217\346\203\205\345\206\265.png" "b/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\251\277\351\200\217\346\203\205\345\206\265.png"
new file mode 100644
index 00000000000..e7298c15ed6
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\347\274\223\345\255\230\347\251\277\351\200\217\346\203\205\345\206\265.png" differ
diff --git "a/docs/database/redis/images/redis-all/\351\233\206\344\270\255\345\274\217\347\274\223\345\255\230\346\236\266\346\236\204.png" "b/docs/database/redis/images/redis-all/\351\233\206\344\270\255\345\274\217\347\274\223\345\255\230\346\236\266\346\236\204.png"
new file mode 100644
index 00000000000..5aff414baa4
Binary files /dev/null and "b/docs/database/redis/images/redis-all/\351\233\206\344\270\255\345\274\217\347\274\223\345\255\230\346\236\266\346\236\204.png" differ
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.drawio" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.drawio"
new file mode 100644
index 00000000000..bc4c6d0cca7
--- /dev/null
+++ "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.drawio"
@@ -0,0 +1 @@
+7Vpbc+o2EP41ekzHl/j2iAmk02nmdA6dpn3qCFsYTWSLY0Qg/fWVbMnYluE4B4jTQh4Se6WVVt+32pU2BvY43T3mcLV8ojEiwDLiHbAfgGWZluPzP0LyVkoCwygFSY5j2WkvmOF/kBSqbhsco3WjI6OUMLxqCiOaZShiDRnMc7ptdltQ0px1BROkCWYRJLr0GcdsWUp9y9vLf0Y4WaqZTTcoW1KoOsuVrJcwptuayJ4Ae5xTysqndDdGRICncCn1pgdaK8NylLE+Ck/Pf/xthHPraf7NePliLeLZ1+c7OcorJBu5YGkse1MI5HSTxUgMYgI73C4xQ7MVjETrlnPOZUuWEtm8wISMKaF5oWsvFgsrirh8zXL6gmotsTt3HVe0KFiEekRTzLs/GPw5IXC9ls/SSpQztDu4fLMClXsjoili+RvvIhVs5VHSEX3fKd+3e1pNxdWyRqkrZVB6UlINvQebP0i834G9db3YW0Njb2vYx5BBDX++ZNYEuQlmRjN0BHlIcJJxWcRxQrwxFChiHlxGsiHFcSzm6qR2T75RTaxiUME3zZgMmFbQIq1O5jkIvG8RqN5rBLod/NmX4u9e4y8TVN3468dflYWH4s+5mtjnGJ8t77jXi/3gece75Z13EWi3845OYFfcUjyfnT//lndO4W/wvBNcTexzg8+Wd9Ql4BrBHzzxmPpN/5Z5jjDoWZ/sxmPq5YJb6nkHgYOnHlOvOfxfw5/vf7rcoxcMrgb84XOPftu/5Z4jDAbtcunguUcvGdxyzzsIHD736HUHjTyUxSPxDzNBgIBGANKIeC38mgjbXIJ2mP0pe4vnvwSiPzny7WEnAS5e3hpoo1j7L1wLa24q3eQROrbIbk5qmDsdmCtZjghk+LVpRhcRcobfKOYGHiw1BSrjqCFK86XWns4eA7VqGQzmCWLaQIVfVMs+wVX0Esd/zFWGcgG/vevbzPV1gXYG/3AX6FElublAF3Nu+9Lxo1GgXUDQBrqwC6h1NFzAJUV2t/bK7reN+HwhBJN7EPrAD8DEAf4U+GPxwNcQmGASgMAG4QRMfDAywcivqdVdSgmF59ytC9cZ8Q62vdrVNdyknJDP8wACp3N4UnadClNlfymM8esJk8pB5vnpY3DrCluU9PSTlBSd9RBVv7IcOi/Vdrptn+f8ZPt+w/s9Vz8/OeZHHqAsvXz2PZcSFN5JNoQ/ELRgh/1hvYJZH68yne7twPcf3w5jsQt49uD37ckUhGMQjGYZxGRMcDrnnWEqSM7m61XTFcvZj3toKRXmnGDnBTCrBQQHjMYFFHzhngxFoVetu/z9iNlyM6/w+QW+wkfxkdkPwcGlJSK99/HF92e9vNDOxEKJ8hExEzsrEK8EzhEJYfSSFGO3AwxXrl3VjOKn0qJ5jPIOjSlMMREzPMIcpjSLlRkSGENS/aUyxTNKPiOcJb/TlTwiSMGvwgsakpAyRtOm7KsMA2eKQZ6qWakM7OhlFKsrBt1fLAbpFeDbsazXscw0vnep6nsuMw1v2LO5pVeRs41Q+9jAM2R1RefgcuUV/rr/QrfkcP+dsz35Fw==
\ No newline at end of file
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.png" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.png"
new file mode 100644
index 00000000000..f8b9589d6d7
Binary files /dev/null and "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-read.png" differ
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.drawio" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.drawio"
new file mode 100644
index 00000000000..6fddf10f064
--- /dev/null
+++ "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.drawio"
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.png" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.png"
new file mode 100644
index 00000000000..c976cc99b91
Binary files /dev/null and "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/cache-aside-write.png" differ
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.drawio" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.drawio"
new file mode 100644
index 00000000000..7f7bfd71641
--- /dev/null
+++ "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.drawio"
@@ -0,0 +1 @@
+7LzXsuvIkiX4NWk281Bt0AAfobXWeGmDIrTW+PoG9sm8om7eriqbqp6xnj6CBAMI6R7Ll3s4+RtMdyc/x2OpDlne/gYB2fkbzPwGQeAHhp+3t+T6VfIBgF8FxVxlvz/01wK7uvPfC/94bKuyfPm7B9dhaNdq/PvCdOj7PF3/riye5+H4+8e+Q/v3vY5xkf9DgZ3G7T+W+lW2lr9KCQj/a7mQV0X5R88g9vl1p4v/ePj3mSxlnA3H3xTB7G8wPQ/D+uuqO+m8fRfvj3X5VY/7J3f/MrA579d/T4WzDRMIJQJbnjPYAxINz4F/AX9vZo/b7fcZ/wZh7dMgtYxx/w57vX5fC2za3rFS6dAO828w+dyci+T/Qp8mnp7p5/XvLv/v9xqmfha9X//lG3dVe/2q9rQVd+PPTRhGnvcun+fqyJ8ly+d/uPmXNv/hzri+A8zn6vsfqFTkw1xU8X+gxlp1jwpCQJ8f75yH7l2Yf3ftZV2GvvjnFX4f/9+u1fKzDd6VAvH/ho7nv7r7SyLv7X6Yu7j9y+02X9d8/pdHcmn1dPlnj6z5uf5L3FZF/+t2m3/Xv79Z9dmPRr13gb/p++fmOsf98n2a/KPxPv/LA8cwZ3/f9z9Uz/J0mOO1Gvo/qZ9Vy9jGv6tI1bfV39z7tkO8/m2dP5TxuSp+f//R2uSPAvC//caivxHPP+I3Fvvtw/1Goi9OxGmZ/8Zyv1H0bwT969PTCYv8RhG/kczvFwTzVn4+foj34kP/Rj4X+G8f6jcKeZsj2Le5t90/Sj7YbxTA/HUc878e2bMzkz8p+7XN/iiG/m7HQe+iPeVHWa25/azsW3w8QPuUlWvXPp/A5/LVit+R82e92jjJWypOm2Ietj6jf+3Xpz2Y+/nzl57+Fjz+AIJ8fjr9m6LfwYTPhy5f5+t55C/Y/juw/Y7sGPr75+OvOPmXZ8q/wUji97L4d2gu/tL0X9HrufgdwP4czAzGbWuBvwoWAn2apCccYf7lT7DslwqQ9I9c6d8++E/JI338dx34kFK8x/xrZf5EdG8t5hU/++gE8Db1R61fNV7dgH8U688F9zdCWtZ5aPI/ZPGjxI/kqrb9V0W/700mfSTzgCFMvRKpHoNE/n6jq7Ls7eZPteJH4Pm7SP8TRfij83+lNu/nv9EV6ufvf46uwDD839C/0xYE/0dtgYA/0RboP0FbMtZsP+1/j+a9S5j/nq81UdR/pi3/Worvso3/ZK5/oRxx8sfjwD9ZqX+6LBD891sIxv5kC0F/sigg8p+wKn9OCP7tVXmIzPheVt0Pd/qLgiqvthnDUv3CdyYZ1nXo/qd49P358ydKvg6vNsfL+IvTfavzVWrqp0vyj1Lgj5LnOovX+LEPvz5C3PhaXLryKN06AJkvBvL5o9luybrFc6W+L4xIk+HzTq++jOXPhbsCLWt6FhJsUEZ/7d8gCgIdYcctGzEnBdMiG4gt2koHcDSvqKsw2d04vmRFlw/0RLNKxbZ7u1BHF/aOqAHN5soooAFmOCyb+JkPaOwfPFjxhz2+2P/8y3+9LcRzQX3ufteJ6OcmBcJ78LzhO/G8Rujns29fdF8I9P70jBTZNk2btH7yiMXLznu9nZxYbE7WmFVKDmxja0heuaQt6U8DlKXSvMmgVKKU7QSwpi2KqrqyqEMttG2RSbK2E0vaT7GmZiTulA1pn2KUrOXAFrYjipSeHbj5U4xE8Uo1bEE7imjp6ZGYRWP6108xy1Y0wyiW7h4J2TQmD+FRXJJs8xQ7gqkDSESyi837eBhTIttcNOn0qQ6Ib3HO+7MZUSLZXBfr9CoPiBLLLdtbbFFiURwX4LQqf0gSS60b5A8mJT3FwAkwq86blMKW7QbxhU1JalGw6KNJ9FssvJPmTZuU1KVk0Ztaadr6t9eCBx7bTBWxnVTBSIzytujGzbr93uzmV8dx9Ht99odKcjGy2x6FLfgns+1MzLuZrjn92YLUvH0v52N+O8Jd5eTRSs7uukp951UlSKvY9XQ3Os83NfLc83ZQTwJixmLfDp4+wUjJgbj+PvUooqMt8T6dY8Rb8m3Zrc5nw3PK8795/ltKMyIdlrjnca6BfSqsseeB0hBKZfBgVnue/zyFTmK6zNMeXYc6OaKSSN+EfqpTQI053H6j0wMB1HIybY3O8G6IenMxtzSSsMsQBWbvvZbvHbYSqyW0pXZGYNIUdqQNbO9hYpp8xhbOnn7A8CPnbQ17fVSElPQO8LKI6BIE8Jt9t2mY7zEAXLbbfTTw6hDUiu3ge1EngutIiDRxgOnCP2jaX5GefJLqqkexOAEinKHpK+cdJqOrMeEdgefSSEwfnwq/sVK0F7HcuadJt8TBo0tnnxOvc7epaavGWlEi2e1brQQL2d/OeLpU390nP1MOPqJMqUkdAo/qCIhRvzAi5v2d88/VvJmodLNmM9GBYAaEMUN00DJfyqY+wIxZTbPzJ+RIYgkobrsLBsjrfEK8C4GKxDhZi9VlokQslfeKrK2ro6T5nCQ+SVhjEHLjyCtitQ0KJ6monepzX1lvNIiDmunb7Gkj1X4BwzVNaAhbbcooREz4mrzyZ8XT9/Btq1cfXnC59+qyPjNm4jYhlcscE3N0cA+qQ9YNTwLaFBu3Fx7oOd+Gtfu3ygCSPV5yq7hNW3OBzkTiLkH4SEd7X2zwLbdYzwRo1enurTUsD/BVuYmTtI/Tdi5Y7lFoh6/qDEnZ97Zqo2psx4snrHTCA8Gm7OmcXdiXZ5+HfL8ZoquznktLVEoMvhPEQ3YNJ9VXU1zsCKYNe7bfA7F9sF5zCOSocYGy8gitjBibBrkyXvK+E/Rg1/G1zknj8TqVjevuwHl0+bV+dAbHQ1LZVNAAJs8qWF1S+2F6gixvPbUvKYfh2GekeXpuwoqW1quvKCttY+kenv0MGkZvm1ZWLu18fZT5m3Fyfnr3wzrDlHjHHu4CZLbolIVNhjqAj7C8ATi2cyQTBiqeTFplnAa85r4KZn7EWyzNdaB1WxKIDUsXn2cNR2nS4mIe0GgfK9OYIVxrIghKE6SYzySMuL5n1HjsPUdTWRAP0QNu7AULNi69+7nprdu2MoQLgvfxLm3TuB64WNxEnAGhll9feGKdUqOithCtEoph+kvXUx1b6uk6yS8DJDRLIWKR8Fy2obXzBhpTVyc4Iym0hXrjP+P3V6ne2QGL39E0oepQaKU2fQZHkKqoum/TX1FuDNRia6UVgsoZsxLhhCTXfH7+rLE1Z/fJt9DTrkQPAVHP3tfhMxfMTV0zWsBeTtTPtr7ArUlWClRjpLTsbWOkbNv6EEchCWKF67xDZaGVHidO2V8tFwr/s9bAwy5IK7padommvR3MRxW+5nkqc6O7iiSw17fqBVF7MMxdUjx5POXHQCBZMJdlzbZAKgEBwdIhUDgHgMDvUhImfCWrF9Mm6UA8RdbQ5OEmUuIUhQ0fF7vuo0M2r5OF9tSXxH3sv8icHOwqbcnYjk7XF748DaWIvgzvxiyMmphhYRDfDy/mnvdjxC6MG+TjNTSUWmAiqITms9O54cVkTK5q4+FTC8TDdMvHcPudwBl7uOj2oMnZEqpTEFfvuUwZEVHu1/7OKOV3rxonyykwLO2ScbbQwFr7EyESEV8sr0GrEsbSeVpFNwumEqijFHxU6tMCjZHt1j5vnWHJ7HlbBvPMpz2pPE/CDrWU2pBRY9p0+6OyUyRG/ZT6vTcN9QRBXTYD1sj629SDpOEutoMRVumc5S1ygdGWV+yybrhHpwV27Yc1TbMRJcYDY6HCxxJNoXB6tI+qgqB0aMs2WjuXKZrTIG+vPSv3wdSgjG5hi0m+QdVIu6goONdA0LY2IYdFAuHTjJ0F8Jm8b5wIzcDiWFRq9hieiCNOmntAEyj1DKlDLl+jFrQTJtlc8DLxI7HQKaVCtThRxF4C2rpwHgE391rezxgqFd4iuUuG8PtisPzsPHJyhA7R7QomkEPmEeXhC98SaENqr6KNAhl9yaLU1Iazkac8xu5d+bw6Za/1D77xRblTYisTVY9vjerfPXm8dHBZH10CRhmdV9SxVUlht+hZ5FZjtTiDPycCCp8Amd625ssIMneJyGxMl1qCSvI+qj4aj0iPu5FX9hPd7Ij28wOx2YK8urTE5Uvo8lCx22Yi1tBkgBZ52aFQXuao9GA5L5wCrbShtA8eqMHjD0OUk8mOZIARHiLp8/HFk5agtzrZXn4jRT2zUobVPBDBba5Hl3iq00z10cbZLS69bXefuFJerNuGMJ9tM19D2/WBGeWcrsD0BLZg2yTwY0KSSsYDrDXHBLPzGBLJeqNKe51sdhkuhh/ePVTypjH3NskampceC0Rik6XoL1WX7JLAoRCPKV3o3qXEJbB57WGjKNoo3yiat9o2V1eGKMXEdoUvv5gKEbEfmh/vOj9OpAeCXFFaXnbTbshx1sG2DrxaaX/EPjORaX6u+aRN5e1jmqVS0PtDNstr+Aw77sn4YaLmKYGw2HFQcL2uGLqwaW4yiLQBc2VNiKbFlxa9ozrjDKxIEf9IaAgEOtiUUfrpKMbEPixhXgGYLqaXsDhKSS9cqKtdnGtfxuYHOvf1dsWj29BYyM7v2mL6yzTCVx7IyZ1HZYaIThxhm4hcm/LQKIyD+e4GEG4xi8ea+cFmOPGtZHrMGEeJ0mISLSVArj+3iBUgLxmluBkbjsZuzBPNsathDbj3B+1r6p+BIrnqu5GQpQrBhETuBbG+HTHDaxhkxj7Iog/KGTI0KgyhJMN0x3FAo/lFYKaHafQayoI/VCDk3cYMKLtia/i++OssJwDw7t2rm8tk7AqEuRcbrVLCH+YoON3gmmkJVMoqlDpzXh+jZmlXSld+abbBxZGvGKjzMKaFhddSyTau+ZVJ8aUrjrzFrj5wmfHKEXJEKv/y0amItyE+zxCPGXUzU2NZ3Vzs0NLywaMI24rFSdFelr+7n6YzG1SgoUN+GFb9OnFp5UDvtqgex8ssBXPrH2jgEfVhtA8tfX03PS6VJlftqret3QdF9Y6gb4PhMLtZ9+sRiCmbUywSrUx7OSJe9q/+igc8WKy9ts77HNWUSKDKIj6rZQs7Riqp1QjYaqGog0VkmP1dkdtPHPBx1rq8fzUv/+6eWPEUh23iO+7X9XjAh3qWVa8U+PrMUrkTj5F6pjtR5rmCJSXJpPCKHoIeaX5sNvIkLOybialhn/UZgK3aNiceNxR6DVswx2jBdk7Uuzaq4DO0lheDoMLKiFrnfqKxCCMdrsYac48+0kAETqM+bCoSxKUP9Lq+2771z4axTAt2600NtFKkV+qSb6rOWcvdlRSY9CJsVwWehjHHR//x5cLgXspTu8eqHSfDS+zHnlIZtM99bo8MbvdTtWaGXS9q6QDA609zKd59vqr/8WmRwnHbdnLz6OQ7tw5SBamV/b5N+C/asW0jHeukV7OaP76UPuiZh+AY4dmA6K4v/N/wmUClRHzs3C+bbwyzs61b4ccbFKK4bHrATjo3BZkxzKHdAikqb7ytOpD2pJdsncrN5WzrtNLi1dB9upPJ3Pt9GlHq3oukPms7rXOBVj43y7mToWbDQtba2a5ftKcG9N2d1z0a1ucrgR8/0I1XlJ1Mf+njj0An9aUPFtIyx6t8Q/uwC1OKuMfzCMvevY0tym1Ri6M5y/UFl3pd853TeDdmCnshLb7+pFFkhNfx9ynHowd09IdJb4FezXNTbGbV1PMY/GKkEdy/hOF72I2uT7+ea+4Hyv3H5X10mILLiGalzPTHj/9gq+TxxgZmUrGbqHpyfQLmnmV00uWLJa17uGF/C++rho6Fo3ixOSLJFl7LUItJS7xz05AFtE+rdKyUNrWneVTPkZxHX1n8vE5rSGmdAXhSkAoo/1IJer5F5PG8aDZS48c59EyggbKEYNPA/Uzd47ZSmlpxcJs5UNw3uPiA91L1N5UVbftQJkucb7X+JkszNWBU5jA1G4fEDRISb8e5aCo2xTb2oq7ZVEYA/ZhlHUOXdzQA5Jc26eZ72ogARkPviJoxgD64lAirYW0g++N39dztKKyJkpA913rfPFYdLRWFWfGBMhrA/n6q8o0NsWlMRSUC+MV8ykABZNYWdrCJ5xhpozNtXxI4t99IFr3xWN4xskTQxk9vAGzYZaw6qP54l34lOLgx8+Agmutjg+NraYqc8zb7cZHaK8p71vERD9bw0xqJ5dUdYXVqG/U3adR7CSUK6ySL13TeCW7QWSqU7AnZ5wMiEjd/SyXcbT8Qrg9tUXVFkWUpGVx5pp4fei3umiWnqAweGETYh4hgwevBvoBTKjO4YA3444lbNMb+6IS6zM6z2Ripig0GRimmo0kFdR1cYDJMIRUx1xrCo1kSkXT7BmwxSaGVfHeZ2Vez7dPSL4uzJMzhF/XjNCpNqWEfT+06hkl6i87l9WXj0t1syE3Bw2xGeDvTehgHL127NUWYSygT9aO82b6QNHCdZ71ubeahLtVH5ZVK51Gwxo1+XywAY14pn4KQGJfh+vfTxvcz7xfgxcQRDV7Guy3NsrNBuoTaKZP7ZS5BsW2vtIySMyQxdnPYwnoNTPfMFZFYOtoHV8zLW1okKAfO033aX3v1s0ZBhvVI11s79EHXx0hA+9gfZXvp0WMoHhekzbpTFEwgc2VDJUZ8GHC9X5bH4feZ4mrtezxldHzNAqRFjvuO9d6q9qWn6ouEGAJOiZtLVb5GPLBXr03CVEMxWPN82CTKlCet11zGnCHjXT42+/tKSofU2X2dBSWSFsFVjEP3IDIdhOiCGkFPWOTgRGyHz2x0uKkXp5KF0QAl4LQkKjlkN+KIPDoYrRfcJAmKdpQzZGS+aQ9XegMnAE8kVZ6k4WlT/ex2n+NOqpE1sqseqIdfTfCYGKyNcrI96Ux9eT4L5GhV4ZrQF7BfkPSGBfV+DwNt8FGB1hMXDFJxXT9xB48koced1RuW7yRy0hu1GNZ5rS4nu+tpe7Cx2NUixm/JF4EB1/bbLVTGkC/X2uRHewlcM3tRTfiDuWXXEYuKdtxnKb1MfV5J3QHgUFO/IRtPGElTHFz+0s9wf5FDq6uglvFltV77z7HslvbpqNJ9J1K9fgKljtaJpvISSXKooJ9oac/yuICoxgrmCc67tiJW+43vFCv4T7RObZOTK0cvEh+2ubaWa9/ewaAW8KWMXSggcOPaDyy4qUUjDzsJvjpEiskCoQ+7LBbstYlbn0AcaVXCNcm+WhDsKGnHEE/d+rS0FDjrD0G5n7l2hzZ1kxuikfYdfMT9IU5JaqjbO5NmZ75ps7tSDycsT2ivYVL5LIwbEC+F7hgxK2esh+F4EXW9NfbTbC4lUJxnHK2Qqx0sMPbdNHnLK5THiiclMd1xb0mw8625Fv3JQeEHkVs2i2BjQGSt1/dAM4fH2BOdbeuuI6X2AoO1/QXCcWZdExc2UdJk1VrWW5KE7weFrarVvuphimlKUk3smaN2WuyeCZ1mNo8N4XsxzDWwTN+4C+MQtn3Qx2PHXJBHBJnj36BsDvMKVr4yD7IXWMYWeIP4S/3MjLvpn+AqOdnCgNbC57EnsgulA9nn3oelemhEM2oHk9yarJ4Z3bhU2RBs9HdLXgNop/MrknqyIyl35+7rMcSXdMTImEhkWNDdiOE3lmO7nzSbWgJDJ9MiF6R08+RaJ/oWNlb1HTK5oDo2hvEYouTEjam+iwXYRSvyNr9kWQTTvigKyKwU5cq1lEfwGl13C3wo7lxGP0wEQLStd/F3NNi92B7lj1qjPg7FaNG8xlTpIies2JAEKzRSzkupcdFYJo+gY52xf2qNHD0eh/Ex03TtXSCXnRkzXrnD1OSoACIEqXJXFluM+BwpQa1O9xy6DdhnG5A3NsV1sUSDx+3gk/hlJlP88rsXblZENleGjZe56abJGA8TIrpH/hTPm3OGbpqpAjo28Yd0pyfP8QoLmFSjaNSKHrc9GzwSkXI7MORgma7kL9vXIlky+jBuZzSu5YbNUC0iQMaxi2BgyeaVIEY71VgDO3ggwNb5BUiHo8v3u6cTdQiaDyKSJRM8bvzGFZlWHfxXiAj7IelcMY4kRGuUVrwCfjzg+HlMYtdWYo7ycBqPlRsv31A6p02JjJSsuNwAnSOHsQpacLFRLENHthrB0wEWeo2oqVG7W6ZSq+v2wU5SqSpktk/z5KyPA0Ge9yk5NW1GUazaSeZkIsX3VkkHMcNzIB68zoomSitOmSlqq3KPpf1EZtiihF+g32VApBTgtgF83WPQG6Tl7DdOiSWEXs6ESFcIOCnE+vIDOnTn1NhkfH3Fz26ZapQtcn85b1QtAOJADzzQIxFabXedTpc5Q3Lk3TLdVBCSKKZUeH/o7uEc384cHL4VCmVXYqdILDPBi5/4CTZlaKN2F8e6ue+qflBdAZfYj/l8d8jzCJKguWcr07SmroD2L6kFH5Clku/zoiffAMbEUATZhtXT/TydyLRtUXIpZw9mqyKlZcPRN6ywzCJKPuT6PJ4dBZOPH5Wln6/fElHx8MMopJxXeINli/LyejT4T6VBlFh2ItF7AhGQfFykjEC/vgeEBe2JEcLZb6Xi6VHf8v2nilpIUqMO5PiCBvj26X+/xPhUYt2K9sgQAWMieU/iti3d5/itYlJyoy70+F3fczLBN4LPU8F9z9o80sVB7O0vUbZ3++6zfOk/FVJ5/GrH05sQGAE4fvmQbWzeJ92XCWBvb7OwvwT2qfKeksmFnmJrrh0GwYBhznwq75cjz6XvqSppu55uySgdiuJ7qvtnCQP/0wP4fzuL4Pr7VIB/83T8PyNn4E9Px7E/yTDBfxJC4L8mDP1/Mxfkz7I97N8H+Se5hP8PJfZHggPyR9rH38gMB/8XZnlA/+9neaDQv8ry+LNEKeTP9Bj7r9Ljf8eq/G+b5eEAzV+zPDLsgCyr5xiwOijPYYOWPj9HOFHFDs01a28XBy2qK5uv1Tiqc8LDYatCzRps/fqQmEzvoVbR5ui7nLC8/K9TlVcme4b/BKWiFo7g7+PHnxCOg879+In3GPX3dhTdyR7kurIhmdXhYauHEloqyxGZVVGKRR5mcKI8yTqnlpNsWjIHo4lCh2zrQ0ocieZ0bWZu1iAptWfu2PWf6UtLSQk5WqK0VBR5UqEgK5oqy/pIVxjqQVDsZRoamsU0KXYXK6a4L3SiT9OoLnRusVIHaUWVrH5u5nj6IAmYOyfRrEKRXM9VzKMSIaVmyBP7AljS0hoxxCHVUJ8+hCsV9LG0qaKobhaw0E4oxId6oZsyu+bbcenU8UGczEE60kFAb1yKpBPRtOAtzN8+3sllFs0yFMVt0sDcqkFaasPceeAXBf1MjhZ0sEQrrig2p0RbUTHTx06GVW2kf0zugjxo7O14Hdv75eniG5ImfjhDCcwf5T3p3hoVz87ASOHvGzKUPvsMGa/wzoGWmiIOagF+g/7OymaSB6J3DzoTAXIdJUvU4yOAIfAGUnkN5xe+ucz5C302zExscGiPyO3ysUvhZ6yfy83egEaL2OkZr7UrdjTTU7obN89UMScszYhGIZxg3ARpMHuz9yoZKVj9ZtpPpDACCg2VgQhJXfui2B7amAjta7JtipvsbGcDnZRH0bYJTVqgYDtYFajZ7Tb/dgA712GUoCGdZ+7UZeg0ZmTDQTRmk7zs3G8kM+fiIBgchB2EYxYM4PoJi3ef3l4ppbzFVMmOnSti5VkuFhEcr4t9yIGXGwGKNEqKXOlyp48htagJSWLaIJJ12TNed0EJ1NIm34g/ZyOESn6Mad4Oj7fhipcQzFqxwkZnzGQkDdyAFguTdzyRnSELFoOOkEsuHUiK/cuTehdxJN/RHd/5IwDF0n4DcEJQJDZtpMT8jhI4g8ln/9dpNqoAKBqw/KUs4ighQEZpOoASh0CoksgODc6ObG6XTYE9zsh34waIPKLPj6haEf5qIkUW5v3TFhXrYqFkZO1IGelJESu+UNDkClqGzwPYw3FBxTajt/I2NXyJmzcXyoRUnzNDtXOVSCwkILWkiqfIqs0xfRSNow9mfg/MLE0iBQM7YZpu6NNbJCyf1IebBWPm5JLWjg1pmiUiUp8OSL+coC5OXd9JVrnzGsQg8yhCbCvWqN8X8c3Nr4Mavt7wiPP5uAJOjFis20Ypi8R36Qwv3l34fOTydJe32CcaMIuACQLvYImWtQ7XtCA4UPJ6ZzhiyXmTZGQ8GulerLrzEe5iW8K+flpi42MtsvcanVM1KW0Sq2MsPQCSlvQr/YEjabY8H0ORx0p6z8KcaifNy6I7e/owHbGm3ba5spsJN3244iSTd8az9rgN+NiXdvW5aspHE2zeTtoJIdaPvM1TA5/+puEbBhb1JTWdcVG4tpmLnZrDCLfQ4bQZqBUKTsWiyXGz3OnC/vqo3Xe0h9RtPgoldNvI6jwjR86ngux6ZADIVcAtmlbWJzmpNt7Q5uCTecshjHcN235OfsWKi2cS7HGARiNm8tY45rVeL0YcLF7SlSBUiADJ7G1pumbMwsmF4jHBZmCmxbWo8KnTzNCBBEUhX3OQ+QeMHe0l2eQSfm2y4cN2btprDgKqV44wfcbgM4VE5LRdtHw9B9oqAGV20Wg6gIdEGeWd/5gbtQT7mncaLvCjmlZOxBSYUb7MT+6rnyAzTIh0ytbm908vq11ukL0obgvMsgTlKlAra/5rpmYbGa176tufU4Bvd5EG/cbvE7f4XlnTLeJsadTBEee4bR5vaO/eWB0aDWTjjqh0ir5DV+2+OZAgrp6UUvuuYDQmRMupuWvzM2etfp6rEXWvbUK0Gk5lUowmOeKDOiz/k7hEETWrLv5VA5D5AdoqCDo5cL92BqqyzhM3rdN4cn2h8s2M+KwAsLjXjT/zQx2NIXFnK9xUmCCg76FTpL5CPVPiyX++vUuT8pYwG7kqnzfrwzT7TxXOmdawDllpGfbtxCiCCIYMTuHmILmzyTEWPRxioTVr9qWbtb0wKVh+HUj7FDSxGptC9ituF+1jgKWqO5D3GEA8QUluu2Iy31tfaevOzveyRFHF/fEMw1tONJa9itgI7SN5Tz/NcwAb12F1shag96B382MapcXgKoWqLnXijZWtpEgugfJ0bKOZ2pCyLmZ2BqXObJoT6cekXDSFlL0ZSZdQWdBxmCMiUSFlL5IYjgFHhawW85NbLfIGQLFINjom7V78UXCxdbv3FKkBMTsSTZoEQdrxei8EbdddlIDQvMjwhL7g7a8meRs2VIQfl9zjuo8d57RDKbFjBIIcwz2L5QCXqRmEei1QonShZ7LZBfLOSF15Y4qy618NsLAD8TWyGXpV7z3EKnaMV1/8FyimBQBeb1WXWGfVCjkhNt4jOAetvqh43owh8nK1x5ZOizRNLW/4VEaAzZFFeML39M0nXWdtAExrKC9+gHfmI/IIcprZfJjYJ8/FfAxq0rt9m5ZUUvJ59bNA1/4q+w7J4p0ssAtjyI1zEgbu5vieAsyoA8nakYWGASaAhLwJueBPwFbEjRfFlzewocvHjJvoFxPs15//BlM1sjucYInUy1UwvpO9chTprM+bUOi+/NAuKTJ9Kc3lgwYsiOJRvAQFO77cHn7hRP1GZxMUSSTlytCu+Hx0RsoGm2lLTkIbJ6czbF/SC4FhomnrTei4N8hnn4eTUAYtsJUJla5YV3mfaDVC4waIRGw17w5HsfvpVBV92hZeiGAbf91SK/jM9oNWOuKIwz+3fjZuZ4tSYp9qoy1vIBOhaK72bsjZKmPBwppQ/VdBrQf4xs8HZSHz2QMO/ZU/gxFngPpmF3iOWdjNWZfu9SBw3+7q4eK6w9Udme6oEfqeec7o87J+KHYhKxlcbyFaQ6l7z9yTZ/P6OGZpZQu0n76VhsFC2V71K4dTbg3PzFUylKrvHj5UjHHjAX2lA4VUXBY7BTLhh40cPYSiPdTRlwBJd+dQvtyPmLDVQxitRdPokm9HMl8ValaOdy88q5kI1H3K6jdtrNYOTx3+pGxdBRqPglsc5ErC2W9tVZFuGN7feHBcESnwwFcqWtJptFuv8T24DGmThMNhEGLFIn0ro28KDQP1w91b+NgWnYlFoNr4WfqpSM0K55HX2e80Fm7Njv3xtcSEWYIbaqzwpYRhiT7smCrCr1kqjfJGtfKjdUcsuOxs5AAgYJZ++X7ZwBG727INnch5c6Jq+h78GuZhnLWJ3TbBEbpv+OE1i3EsEfWhekNTgWJLJzbljklGbCLxX9OptIBPsjLVc0mRaS770pzcr5sRuRHKOwYfWfZyzA9AV/Uzo4/CHKkHP1J+pxJJxiggoJTqwuShPhO275WwomlPfChS4YVZIOKRps/e6zBN95EU7gpGIhWWLRM7EmNXQjIV52XJEsN7BUJdFAMuNiUpjkbFFY+7HdFUvYeXB/+GUDukOWf6jYyNLmR+59Kjj0AgYpG6B6zkGGJoa43ALjFnPDoNakTaBSqTtK7oDht3vFX4ySNqeLDjVuVrbbgBqdA3OOWb0lv/4exXOjz4K7HZog0EU3HmG2k0PTu4vH42zs+LFgYr39LiBB5P6Q0RbwbAYyJb9EwaT/He31p5WJk52xvT6bTGYmaWwXhoVm4kxBLU5mmD0jCf6QgiNZ7NPVoHG7QRv/HdaEkv6LG37EDNvlNszGAgD6j7tky9WcXxtn6nOH9XM1MrteTUxqIJ8raWtkGUhcUnd91Es0xmBhgN1uw03V/EyyD5UvUdhYOHMKjzeqjLixTPZyZMY41SahMoSgYtAkYc63Glrh7VHTYBKTE0Kz6O7Lfc2JwFDJ4dRwhUCyWN54dOcN0X5nuFYhvyW5VU2D62XRwxn8ukWPtE16UdbpMC9ZhGExTTEk/lv/AIjcV0YKQccgDy0wshTqL3ziJ0wK7LwdopjWksjzmJmov+WMI2XToEHgsHByGNmFSEhfUM2hW7RcmPc2dH1PbunGRqZB9UCFdKGd9qzYVoNhmpKSwSya4YLZmd9tw8BXCbd/5MNMIs1DRZPPCWwVHcstffG1iUKAMm3bZc3lsq9TJZ+jq68DVQsyPrUIzkvAfLzv/0UUsmpU4p1ONmHJCB9BPgFFK7tq8rClcB4pFHkI/TDb4s5KC9N57xEJ5oXxsJzxH5PIW4th6kIGEKi1GeW6TTFiF/LYHma+91jz6e+MZKXE18NFlLnZJt8lhCHvoXfoVNmr4eud9ljiwGwpWsI26UZdAoOBNmytAdc6PUYNeuI1H+2RjE8eZuc5rCbROvjX6QigcJsHE7UZCLwYisxdsiH4g01KTuaGR7MkMcguOMfoFOPfSOpqOD49WNPqscnOAK9sUFQJa5WqoTrP0qjUDrcfLZAH+di4VsBXseY9PA4lBUyRdpqvlo9Ul4FvPB4epC9Zp6WeZOImElipL6mMqqVM0TOmjfv2sRpgqRzV/K5D178s1aoVDNbSyFu2yXM1lsrjynu6mSVcf0YOXQa0YUg0sSaMks84WDr1iUpKH5Q7vXgzoeVbcWIc/n9xsk/EN18k9wMTxsT3T4Hgww2etcZr5+bKIL7+dCSsoirSVYvdQ1uqkCvmOs/QKsMzIfv4CNaxzWiMpIaXCo90s9DSvLZi0gXjLN5f4KXHuGmec1MvcIWDBIwjFokZDKG4nneKk9Sv8OflKTDoF2BB6q8YTi+0asFAJZHs+uqqTMRJUOhJFO7TDerSmF5ULHXLtidorS8T6mTsjDRMo3yrGhRqQ1SakXRTr2Bg6x4g1SUynB2vI9gS+NGGhqstNp8tkS6lzWz+HVnZF9K4ctrXnGwCRTXdbutcfMaefXa01/QybFtevNQZUq9wdSTAnS9Wh9/X7PL+dxaqRURdEhSS3PZa7aAItmrllSvurcJ8UQ7YdyU/BNWINsTvGgzqon1PE66wRRWyPZHVhytHqqv+7IcpS0ujabn/G6jj/sj4vW6y5ZK+cWs9409O52m30sho0y4SlAdEodyfapYxOhtapFJiwudfDhqE/HmuSWizzMvBrAydl8iwfytFkL8o4mX62qWq7RikbAzcr3xo/NQmQESlHutqdFk/yb6KEkavl49DHU0pacoPUbarJYIS8hmE0M1wwfjpQpso7T/Rgi4ntqIou+mYyZqQ4PKXxcYpVYaBONG/TNQZ6F9HtuYf+wLlIqcFQDYMQhIgp4/MtvZFIRlNi+5xu8DxnPUKqv2KAF+CByQWW7jXqVnlJ3cBngxVerRU1QpZog+lXCzVZ4++h5s6RLr64zBUtNmpjFQMSsIrMTgR3DWlBTkJgKu86/rupEVDBepd1Kiq5jdmGfGeLU9C5lxeu2buJ5sekJyiRwDIbBpUjd7U0XBjgwb9hitjRI17MKSqtLSCcsSRzgVLqhEiaajHc8pMkVfHha34yh5yz3y7vM19y9u9LBcGT98PHPTp01v499/4nKkDXdPXNjC/vxdAqmzu09OSzu9aC+oC7OtN3fGVUK3pufR/m6+ZPMck1NYC09oVgkq/rG5gT6ouU8QgBzbFkK3rw7eq4EKuV+uE7RP4bTaQ9MnNnZ0i39hhcwxc6ceMk6/r2J+jwOGXUjsbxhg+2NabX3YPUhU6ITm1e0XEYjnUaCLZlbu6iFJU9en1GZM1iZH0+npJkPcRAsxJW5we/irMNBKCFJAdv9DECqNpU2xUQoLw5IUJ8zVNlF/34pw1mGcTwOvKcbryhopj4NQ3FNkYofv8NqbmiUaeKR30MP2EY4qHArfxyq4KqO1Dtm6fMNXFbEa564MqyPf2AYWtnQfuMInKzujid3Q1BfExe5d6HDb6ZCF3C5AH7MyrQK74OR4K1KZx6Xm1kXev977gqIg9joDe2zQ2yLsetnz1nnewwLp9qFKrM4CGyeQhMwvyO0TcSMo6boLkr6YHNh32rJxMXi1+WWPrpyR1JNF3ZZY+1sNbO2wmdShdKZnrluXp+5Zsjoqy4qGF+gMWgsQmL2RxR5V7GOgGl6gb7HMvenCTQc71EbTBIQ8WtHi2H6dyq9/mby7DsGwl0Kzl8CvSFbHLGsRGPVZPZ2MBObQnpxAI7PjiE/21AI+7cWi3IbJHlkbYte+rS4ulJRnW/R3Q1IZChZy3qvvS5f5VRfIzVRsWx2DPhQQlE/OFb6wKgCU6SzD5W803UjFltcVIwTBZaQ6e2qpaztJn2z+P3eJjiWwZhn951fX2vmZ2V6aWJGDm8M9JIsnUOfC25Fp2cybxhSIulwtoFmZkW/V1ubStNSl0PXJuUpMIuI4gRHrmyXUBfWT5XgzTAywDEiGxm/fTrNK1cimof/vbsNjimhq1ZiWUiHMy2wY5UQKCYAz9yPokk54NX92S9uS7yn1ZU96gbNWjxqZbNNJ8qU0RbBKksn2oxwA8sRiUJ4IcbOiaVF4NpKrjwR3puEnoFYVMe4HHu8lJf1ibpKNHcWFyhbZ8TbJKdchs6ZNcj3a0YRTk0i2XbYqXMErkMu5Bwu29sS+2ZXWbzitiJP05LIeOq17R3NyjMaoQUR+9d51tA29xsD3G6qE4ItgTf+xTov31ieg2ZwxJEWabvjWTovCvQyfc9Y0FxT6kmUycdn4bw2xbjDUhulRYBNH97zFrfwfO8egvfsYQtqG8EquiD/Txv/rI032qNKxElyGTONP+kDJCVZLsrOjVQUxU8CwX8ghwD6J+e2/6Ecgj89e/0v+4Y98ic5BNhvH/Q3Cvj5ZRHmN5J9kwko8s0q+N83meDfL7o/kgk+/yC6P/t5kf+yVII/Edz/6lSCf0H/HakE4J+qM/pfpM7w/49TCSz6b34wIkeOr2cFwo32a1JV3RcgXTc4CmkSBx/G4bv4pPyHFV3Hmr4ycz3OBV3thRhTtjZUVFysAu0VQGjZs09dpFWpAjwAwUNJiJu4FtZrjJkEAMDoNNLGtfYx2/BjQyEoh/M8O1HYeAlZs0Mzip74vX9TB/p2GYzcB2IanEjS9vU0QIayKfItZ5IFRIEmQpIySVELcxWkqZDCwL5ZrFRAslecJjszVc+8R1vWrKhGOJJ9f4gAzhmPNV3SZtO4dpRbNimS2Bp+RpCBZEkM6Cq3cwmKlCRDg0vwTaIEZop/Q+b7Z0DqYdL6CPLTk/hw7Ic5Xg+6WizY/bAbWr6/IkbVA/Z+YaIbpzCPvXoKppAxqdkEN914TyDRqL5xDNN79csM1p6S1ei86xS3oBw2dhBFkKo24yGSkpwdUVKD+Qw5RUUidVio7xfPOJH9aqW4Di6l8t3h04f4fr+RC6TIIkXGXdiAVrmrXhPMrFhkjeG268cr6yMgZYbUaEvXScOCtEUfN9kZTUiVV9/TAAFIHo/8IW4v88ez5mM4wK3r4Fa6PknZZrK1LZn3oVTV56hOPiOeA2tZq9LRa3Lm5EAiyUSYYQnc/M3wP0FJ0DfqpLjoUCAP3sDaMnlLfYqmdaiqWJ12OeT09XYp7M8zI87QPNVBIo4kCz61LzWHwXzaGJGhhFpxoU8ZxN27voS0fPmzivtxeg9g/JzHZg+RC8lx9104iVTjLeB50aM9ctsyCC30WVL7ZdEsqAwKzpU62WqUJece7t6MyimHJ2Aw6PVqKRDfc45BcXskQroFhaTqYTB+FmHHyMqR7z3P1XksNpUjBYnbASvDkW6ln3MRfnRPHEAzYKghaE+djLSyQ4ectav2rn1On4KbCDUaGeSFPHk5uc8dCFyKLcEOWTWAfUgfUBxU08VgSmD0nqwkZkAFK75BxPCNpVPbwI+J/ibTXqG+gLlGBdplZwJj0o3gJKtfm979YLY1AGRJVvGmFzOEyp3QzW431k1lw6AEKdfPYQ4TFkZxY0FHqJ1WG99Jcq5sZULbpQjBcKKEjwNtRnS+XjibTPmvjUSL2K9wTJ8sQqkOey291EXdd2sT67nvxAkU+5qGaDx+cBIFgx054zEaoiTOul78TAbwVlLVy5lT5FVwLIw6Cv4bAnQII+9x6hFr4qXWPJ7t7/kUZpxdMmII4al5OZ9o4vjbR00+NrYVQJTDLHvE9M546/sF3/N6A1YhCnxXZTB9fX6GXMwwWCjqhWChwXuFTJtv0Bk/vIJt2feXH/TZ8wqeMdGTCOlrnGCZPrmQKgA9/fDkoiTqVTzqRtK04I8NMZwyvafoaeJPe2chVVQPUix3FauDtS8mLzRnf8xBiai3dZU8YtJI6as0aYg5l5AE3q8KwD2GufpMcK/ngrPMhAZFBI8DqM684/jMUJjheEX3xVfLgzyNMIHnm6GwuhvdefHq90nbXmgkBHmUyhdV8hLWrl9EZR04iiJexGOAZo6IIuSEChnq8HxuLciiVLqgs8HDK+c6c11q/nqYLXGfyw3Y3+8Lz33ALaU680Q6Cs6MA3yw9UACFVlZVNEexSA3KPrSLMQq59PvKRCjO7QSKVVhx4xQ1CUdU0noNyp5kTJ9ldziTAI6e1csVbMHznpwR7RlbFgOmiUXWeGoIjxvAd0bZgyuiepMAS+AffQJMS1IbtXi3ZGUhoJ80aOawhwKuPv8ynNpURYIG5qKLBuRQ7xeUbt0O5+030wAzgSeTi9tPB87whUToYt4rV/wwnSlTdvM5/s6pnurjbnG9Yh5cAn1KBh4eVLYY6Wblw5tU48BSi3AS5XIHHtZojTSASBtT9jhTVFm52Myr0dG4aefitt1ZTkmwX6qMG3Fp0NpOsAC8pm7EBPg1Go7tAGvsVvD70AfKIosTyHq8DKTOAU1RXmhb+FEOdb93vkAwzhim7Ltok2LlWf06xkxpTUie8FMDtPvm1aAeqQvKqPYfGWOdIo3nCQs3/OCFQzvVUZkA7d4CZPz2k8nJ0xiWj3SpOzp3TThrjcyKdFddtQo5+lk52ScG9h6yyltRVpkOhR8C4dDKn3fw+/teCwV2s6jS9nMFpfVnf18J90E+zF7ULE7MfAWDqYK+nwBBJPrjL6SxdlXULEn+RYjUPrrHm9TaUZRFPoOLckW6D1kcNjTQchT7glaQ90HoVtQ6xnkS+eRJT44CK+iIV3DQuZRiwRWxmrtylKV7Jkq/24scvxyaXSDRciSowF+rCNQZINax8zm3jNf4XDuziUrErVETdFPG1GOiiaOmDlsQhnJlaSHQgChcBo0Za7fMJ7XUAgpuxxb8tVjNvLFn4OJBTco0VrHbQZypM2SjaOcSm9muIn0FQ2/2wDCFJK5yKrkTQTJ+NuiXP0UI7Y8kij1fm0B6T27dd6vBjCVvoNltaseTVqMQFbae1xvjukU2VhYF6+Jn2AC+An4PZtmYqlWaWWaBPcZf/GyxUsCt1p9cceBYyV3Xpi9yqtKF9/flAm+vby9Ya+GWrpzVFza3zblkVVkshaKb9MdbClZ1jUnNxp30mVWxI/d1YqDJ1/c8eG5SUj2kXf8CXXQJv3X7k6eMhGVJX236OrN63ysJb/4zOQML1FRv4YwVBV2r4C92SLTcNd1xK1KOQiq3yuOhkj2nn+iXrTSdljwZjNYbCceciwDcI1casA0IaPeuIjuGGlTGh7eQv59+K6Mqe/PTj0WdTVFk5vNB8He7yYou5/3kC1J6io/pGmVyyhxUfA9I5pA3PokXmGSsdcz0JhsiTfPjNvZnaY/xA55OthwcJBTHBK6hym6iY9Sc5HJbEgDu8hpbwdEKe7DwvqQiMAlDKCK0pgEedlsHDwIdCjHF5ZOnQm/TBwS7KNluZbom9tjft+gnxlDWEFGFJO6ZAzeh8B9YMW6BQ9eU5lkzk1pdfsFu/fUVBRWK4bB3goCUMdmUqUbcilDKZoaMj1RnygUtywK3Sxru9L8hmTl1Ucsb/FqCY2fXTtLg2zKZ0OspFhwBfjYtPDK7ZI16TOuBnKJFMm8VDJcPZfkxbZBMp5U7WkymYevhEZt0qLnqVQleapQDhQrb93DKObOOQCyonzHdIv/09c/6SsGKFTI2Ey2PNuhL3eilIItxh4S8tIX2/t/tHdlTW4iSfjXzOsGiPuR+xIgQJxv3Ie4BRLw65dSt8dju2fXEePdCe86ol9oJQJlVX2ZWV9W5gUTffTxSseFjhhXYLB9zMz08E7VE9r1ruPY5VuRPYbtTIVnJX48LO8CdwjN6bnE+yBtagRrEwDFaaIXc7cuNiP3HTsTy7v9sx27CymIO2yKKPB+vi2Dz2zcQ1GVqapMFTmh7O2R90F6tb0beeC64t9i+LpZ4g152yjPJ+WKJ6HAo+msv2zRPHG+rIMc2XEN7tn5ubxJvv0BHy6UsuSwSarsOa/0VEersq61QkMi8qdLPp7xQPn91bSYuzyqNcB9O219MrJSScn853QhnY1FwzJTJm+ZOSzQhSrPz4gQ0tdrXZeR/0CIDhBXGraAFzUAHmkXA3Msi1L8jIbP4iajZXh9VmsdNrnLWSCXiblgrFyY6E1p85q0LjFc1Ah1+CW5mMQbETDbKDD0gMUNTxleZSeX/AyxPC9S8uEzXcERVwaGl+VwR1q0FiqXHuTM8rAWqzPv5m8+wJryyRjdm/oEJDy5zW50blTFyBFqPDMrFagwse+SwgKHydV2bcdKBs2Ym5By7hHU8Rg1lzW33lIph5/ZbAWOF1zavNtUGZh7rwE+Kb9WeYo/LOPA6TJySyGtdd0zNfkJuFfBOzUbDYrAeEVM6pLUdbfV6AYcZAr5Qnz3TH7fnNuwa3FUTryKC2M6g0pbYId+bBquTbO+rf359GikaU+4KjnXIACJA66wBfVeexCj0DsnbFVzbs/tHR3cnOcesTMOKWbqR0yzHqZTo8fZn3asWoPehU+i3IoIMdOiqdG7H+GI3iYKc4qmcyghOjLBxAWpH48cED0KZviDL82FtjdiEJfugdjshuzEtIa3J6+A0kMsKch7t4ijc3gfO0/bcb+VYA6WRrsWTFUeb0jqpnNrwETkkNzt2JiPbblw7uPr+XhqKVNtVVi5uM6gCzlq9e0rmKeV5uzdJsyv5M1aNR9BrkE06/2yBYw8uiRbGzGEN/B0s2qsnm1NxNY5CavEuisV30C5tJN3XbIc0wAn+t05HOxy9tT7APScHZ6QMfnqzUOJyiu2ejEmKQEkeqDXIl2rfgoyyXxvPeLCQLjFFsTqvq8vBW+Z49pgBWlDV9HQpSkoOH7TJkATvQo2g1gIYaF1UkoRKEn2aZetBCM4BdxWtd6EH56nH9Cy7Jnmq1CP7b04EccIp0/xOrXPyXMboOjJhgw6YR250Pf5gFFACOtjEd9a0TBEd8GSxfEro565yqMupl8rT8LfGBtPAzbA53OekHDarZs3esqlVu+8Rdcr7wWnfTXRVRFI9qpfrEaETq5EIqIQs0mZzDn89mOO2dXQkpAbD3d0SBfEKP79onWIhc4XfKe9yzGdTleIulw1CL4H6p1pLQ3iNA3G8/0Gs5FKsHLXoHSSUutqobhWS1tWCcQsd8kVOpxNY78ThvU0yH1/bI0b1ehjOlyd3TQ6rdd5Vxb5IL8JE1hVmG8Q3PiKIS1jOlTD49q5eEbbMwCI6Hdy6FxvmDIu043PaaFh6ZSUas9h3uI+H38dDhg2jMalPmwmzT8tFIStBnz1exUerw2UmYdEdEaNtriz9yrSvdkj0nbHkP7AUcS6xjZwsAiMQag6OBlXB9YBdSxFSHlRd6TQngN+zJO7WRyzfLjwx/KXMnxZj1C/muNAdLi2iFWjtSngEutuA4UYCFazhFEuJ5jigyobJ1eeW12s836DCbDLWuIpTdrOGXfIVi40RYxEdLGrWSzr5nG50H3lkFPDh8rrBKp2btAlJikyAKW6urNHYmWsPMVwJAj9CN1jYEvgFZRcdZCtBIkwNci7hIToRByus1aluWhm+gbs5m5Jm9pkiBunDUSndFX1z52g9HQ3FyY48Lz1tZjHu6SGrPxQ/2mPew/HMyxHUwtjBEGcuF7iS/kMZwQEdt+g/YGo2LDkWHqKs3G4Ri1rKYOfQ1jSwleGpO+9HV0tEtqLlGcvwhAeq2aXofVMBRxuwVTnPxm+YMKwSeA0ZXqaEdiH4oW7bVytEqHRxCsmvFhozbKfZmCIC7Ua2mMNZ6Y7pWizm4xsFZ7Ai7EZGUGHrk16OnELErGP0ShoRc7YQ/aIFikFLFF1ljhzUY/AE8w+xqAWoqNvtKqyVZNLAf6WFiAFSMaBswCHeJarT3oYF3DdFXW41Pdo2c+9Sg0ZLSjO0wd7r7FVQNEIP2RW3vftlQ3yoO3Qm6HDJ616DtYlzhqnOGv1jUjxkbnFkHaYxGyOU7a4pwb3GM8zYx9a9valZ0TuUSqgOobK6/yxFD3OOuZdrAxVYOr0mTdHiLyuL7lajcuIwmw4vmrzRpqZQVRGIdtE0uxHHF5stHwBWMZbSOJNEbzk68pEy0ofy/fh1wPIY+wJ45YM+uH7zEd0v+6uaZDemtBypds9NkN9uopQbdi8gKHlYbWL+UFCaihtbROXhQHMXSCBKiEF6tIsbTAmAnyJGjrFdcuENVFXk/bg78N81ZVbA2MBKT86sEOrUAtpjDJdsDcZhcU2vzk0y2GprPvWatIyAw+6NmnDk6Z/8K70IIg9uZJswZr5eWLGTQMBOJMWTyvZLFAFJY+ff5WkRP+EEfpTkhL59tDsx6wO/J8iKYkPSMo3ShJ99UFAQUOE/11u8vtH7BM3CX9w0Bkn/ovsJPHNcGRpkX364f00l33Rd1HDf/7vV4r7LHPuAZv2GsE6m+ftXZ3RMvdfju/bM8GDviA6P+gVcO+XKcn+PY84R1ORzf9C7k/GYcqaaK4eX77HD1fyt3P+51Iy/J1KPv2dSqb+DiUfqpw2H9x/LOT3y+CPn3Hr+5e/XW3vV3/DCvirg/N+66WvuvkPVQq+SCwgvsapt7d6v+fzANPTFG1/EBuAwP17n4J/3bLqa+mvW8x8KQ82qV/P/zzXftfHX+gL8lFxhF8tsX61xPrpW2Kd/vHbpwZYX7S8+rDTFf0biYK2R7TwG8X93jDry55aP3Pvqw/ys74/Dwv/jjQs/AOH/Ue0vvoYtD5Kw/oFWr9A66cHLeQfL7A6MOeVG/sN7Byf/j8hD/I19HzUMuwHQQ/YBfu9Pembe/W5ySvC/xM=
\ No newline at end of file
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.png" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.png"
new file mode 100644
index 00000000000..f8f457c7490
Binary files /dev/null and "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/read-through.png" differ
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.drawio" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.drawio"
new file mode 100644
index 00000000000..7626c8d1f50
--- /dev/null
+++ "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.drawio"
@@ -0,0 +1 @@
+7LzXsuvIkiX4NWk281Bl0AAfobXWeGmDIrTW+PoG9sm8om6WsqnqGevpI0gwgNDuy5d7OPkbTHcnP8djqQ5Z3v4GAdn5G8z8BkHgB4aft7fk+r0EAH4vKeYq+73srwV2ded/PPh76VZl+fJ3D67D0K7V+PeF6dD3ebr+XVk8z8Px9499h/bvex3jIv+HAjuN238s9atsLX+VEhD+13Ihr4ryj55B7PPrThf/8fDvM1nKOBuOvymC2d9geh6G9ddVd9J5+67eH+vyqx73r9z9y8DmvF//IxXONkwglAhsec5gD0g0PAf+Cfy9mT1ut99n/BuEtU+D1DLG/Tvs9fp9LbBpe8dKpUM7zL/B5HNzLpL/C32aeHqmn9e/u/y/32uY+ln0fv2nb9xV7fWr2tNW3I0/N2EYed67fJ6rI3+WLJ//4eZf2vyHO+P6DjCfq+9/olKRD3NRxf+JGmvVPSIIAX1+vHMeundh/sO1l3UZ+uJfr/D7+P92rZYfNXhXCsT/GR3Pf3H31468t/th7uL2L7fbfF3z+Z+enUurp8s/e2TNz/Wf4rYq+l+32/y7/v3Nqs9+JOq9C/xN3z831znul+/T5B+N9/lfHjiGOfv7vv+hepanwxyv1dD/Sf2sWsY2/l1Eqr6t/ubetx3i9W/r/CGMz1Xx+/uP1CZ/FID//BuL/kY8/4jfWOy3D/cbib44Eadl/hvL/UbRvxH0r09PJyzyG0X8RjK/XxDMW/n5+CHeiw/9G/lc4L99qN8o5G2OYN/m3nb/KPlgv1EA89dxzP9yZI9mJn9S9kvN/iiG/k7joHfRnvKjrNbcflb2LT4epH3KyrVrn0/gc/lKxe/I+bNebZzkLRWnTTEPW5/Rv/T1aQ/mfv78pae/BY8/gCCfn07/puh3MOHzocvX+Xoe+Qu4/w5sv0M7hv7++fgrTv7lmfJvMJL4vSz+HZqLvzT9V/R6Ln4HsD8HM4Nx21rgr4KFQJ8m6QlHmH/6Eyz7JQIk/bOv9G8f/Kfk2X38dxn4kFK8x/xrZf5k695azLv97CMTwNvUH7V+1XhlA/4RrD/fuL/ZpGWdhyb/Yy9+hPjZuapt/0XR77rJpM/OPGAIU++OVI9BIn+/0VVZ9nbzp1Lxs+H5u0j/hiD80fm/EJv389/ICvXz979GVmAY/mf076QFwf9RWh7A+Edpgf4LpCVjzfbT/o9o3ruE+R/5WhNF/WfS8i938V228T8+/b+wkDj5owXg31wWCP57FYKxP1Eh6E8WBUT+C1blzwnBv78qD5EZ38uq++FOfxFQ5ZU2Y1iqX/jOJMO6Dt2/iUffnz9/IuTr8EpzvIy/ON23Ol+hpn66JP8oBf4oea6zeI0f+/DrI8SNr8WlK4/SrQOQ+WIgnz+a7ZasWzxX6vvCiDQZPu/06stY/ly4K9CypmchwQZl9Nf+DaIg0BF23LIRc1IwLbKB2KKtdABH84q6CpPdjeNLVnT5QE80q1Rsu7cLdXRh74ga0GyujAIaYIbDsomf+YDG/sGDFX/Y44v9z7/819tCPBfU5+53nYh+blIgvAfPG74Tz2uEfj779kX3hUDvT89IkW3TtEnrJ49YvOy819vJicXmZI1ZpeTANraG5JVL2pL+NEBZKs2bDEolStlOAGvaoqiqK4s61ELbFpkkazuxpP0Ua2pG4k7ZkPYpRslaDmxhO6JI6dmBmz/FSBSvVMMWtKOIlp4eiVk0pn/9FLNsRTOMYunukZBNY/IQHsUlyTZPsSOYOoBEJLvYvI+HMSWyzUWTTp/qgPgW57w/mxElks11sU6v8oAosdyyvcUWJRbFcQFOq/KHJLHUukH+YFLSUwycALPqvEkpbNluEF/YlKQWBYs+kkS/xcI7ad60SUldSha9qZWmrX9/LXjgsc1UEdtJFYzEKG+Lbtys2+/Nbn51HEe/12d/qCQXI7vtUdiCfzLbzsS8m+ma0x8VpObtezkf89sR7ionj1RydtdV6juvKkFaxa6nu9F5vqmR5563g3oSEDMW+3bw9AlGSg7E9fepRxEdbYn36Rwj3pJvy251PgrPKc//5vlvKc2IdFjinse5BvapsMaeB0pDKJXBg1ntef7zFDqJ6TJPe3Qd6uSISiJ9E/qpTgE15nD7jU4PBFDLybQ1OsO7IerNxdzSSMIuQxSYvfdavnfYSqyW0JbaGYFJU9iRNrC9h4lp8hlbOHv6AcOPnLc17PVREVLSO8DLIqJLEMBv9t2mYb7HAHDZbvfRwKtDUCu2g+9FnQiuIyHSxAGmC/+gaX9FevJJqqsexeIEiHCGpq+cd5iMrsaEdwSeSyMxfXwq/MZK0V7EcueeJt0SB48unX1OvM7dpqatGmtFiWS3b7USLGR/O+PpUn21T36mHHxEmVKTOgQe0REQo35hRMz7O+efq3kzUelmzWaiA8EMCGOG6KBlvpRNfYAZs5pm50/IkcQSUNx2FwyQ1/mEeBcCFYlxshary0SJWCrv3bK2ro6S5nOS+CRhjUHIjSPvFqttUDhJRe1Un/vKeqNBHNRM32ZPG6n2CxiuaUJD2GpTRiFiwtfklT8rnr6Hb1u98vCCy71Xl/WZMRO3Calc5piYo4N7UB2ybngS0KbYuL3wQM/5Nqzdv1UGkOzxklvFbdqaC3QmEncJwkc62vtig2+5xXomQKtOd2+tYXmAr8hNnKR9nLZzwXKPQjt8RWdIyr63VRtVYztePGGlEx4INmVP5+zCvjz7POT7zRBdnfVcWqJSYvCdIB6yazipvpLiYkcwbdijfg/E9sF6zSGQo8YFysqzaWXE2DTIlfGS952gB7uOr3VOGo/XqWxcdwfOI8uv9aMzOB6SyqaCBjB5VsHqktoP0xNkeeupfUk5DMc+I83TcxNWtLRefUVZaRtL9/DoM2gYvW1aWbm08/VR5m/Gyfnp3Q/rDFPiHXu4C5DZolMWNhnqAD7C8gbg2M6RTBioeDJplXEa8Jr7Cpj5EW+xNNeB1m1JIDYsXXyeNRylSYuLeUCjfaxMY4ZwrYkgKE2QYj6TMOL6nlHjsfccTWVBPEQPuLEXLNi49Opz01u3bWUIFwTv413apnE9cLG4iTgDQi2/vvDEOqVGRW0hWiUUw/SXrqc6ttTTdZJfBkholkLEIuG5bENr5w00pq5OcEZSaAv1xn/G769SvbMDFr+jaULVodBKbfoMjiBVUXXfpr+i3BioxdZKKwSVM2YlwglJrvn8/Flja87uk2+hp12JHgKinr2vw2cumJu6ZrSAvZyon219gVuTrBSoxkhp2dvGSNm29SGOQhLECtd5h8pCKz1OnLK/Wi4U/metgYddkFZ0tewSTXs7mI8ofM3zVOZGdxVJYK9v1Qui9mCYu6R48njKj4FAsmAuy5ptgVQCAoKlQ6BwDgCB36UkTPhKVi+mTdKBeIqsocnDTaTEKQobPi523UeHbF4nC+2pL4n72H+ROTnYVdqSsR2dri98eRpKEX0ZXsUsjJqYYWEQ3w8v5p73Y8QujBvk4zU0lFpgIqiE5qPp3PBiMiZXtfHwqQXiYbrlY7j9TuCMPcRze9DkbAnVKYir91ymjIgo92t/Z5Tyu1eNk+UUGJZ2yThbaGCt/YkQiYgvltegVQlj6TytopsFUwnUUQo+KvVpgcbIdmuft86wZPa8LYN55tOeVJ4nYYdaSm3IqDFtuv1R2SkSo35K/d6bhnqCoC6bAWtk/W3qQdJwF9vBCKt0zvIWucBoyyt2WTfco9MCu/bDmqbZiBLjgbFQ4WOJplA4PdJHVUFQOrRlG62dyxTNaZC3156V+2BqUEa3sMUk36BqpF1UFJxrIGhbm5DDIoHwacbOAvhM3jdOhGZgcSwqNXsMT8QRJ809oAmUeobUIZevUQvaCZNsLniZ+JFY6JRSoVqcKGIvAW1dOM8GN/da3s8YKhXeIrlLhvD7YrD8aB45OUKH6HYFE8gh84jy8IVvCbQhtVfRRoGMvmRRamrD2chTHmP3rnxembLX+gff+KLcKbGViarHt0b17548Xjq4rI8sAaOMzivq2KqksFv0LHKrsVqcwZ8TAYVPgExvW/NlBJm7RGQ2pkstQSV5H1UfjUekx93IK/uJbnZE+/mB2GxBXl1a4vIldHmo2G0zEWtoMkCLvOxQKC9zVHqwnBdOgVbaUNoHD9Tg8YchyslkRzLACA+R9Pn44klL0FudbC+/kaKeWSnDah6I4DbXo0s81Wmm+mjj7BaX3ra7T1wpL9ZtQ5iP2szX0HZ9YEY5pyswPYEt2DYJ/JiQpJLxAGvNMcHsPIZEst6o0l4nm12Gi+GHV4dK3jTm3iZZQ/PSY4FIbLIU/aXqkl0SOBTiMaUL3buUuAQ2rz1sFEUb5RtF81bb5urKEKWY2K7w5RdTISL2Q/PjXefHifRAkCtKy8tu2g05zjrY1oFXKu2P2GcmMs3PNZ+0qbx9TLNUCnp/yGZ5DZ9hxz0ZP0zUPCUQFjsOCq7XFUMXNs1NBpE2YK6sCdG0+NKid1RnnIEVKeIfCQ2BQAebMko/HcWY2IclzCsA08X0EhZHKemFC3W1i3Pty9j8QOe+3q54dBsaC9n5XVtMf5lG+O4HcnLnUZkhohNH2CYi16Y8NArjYL7aAMItZvFYMz/YDCe+lUyPGeMoUVpMoqUEyPXnFrEC5CWjFDdjw9HYjXmiOXY1rAH3/qB9Tf0zUCRXfTcSslQhmJDIvSDWtyNmeA2DzNgHWfRBOUOGRoUhlGSY7jgOaDS/CMz0MI1eQ1nwhwqEvNuYAWVXbA3fF3+d5QQA3r17dXOZjF2BMPdio1VK+MMcBacbXDMtgUpZhVJnzutj1CztSunKL802uDjyFQN1Hsa0sPBaKtnGNb8yKb50xZG32NUHLjPefYQckcq/fHQq4m2IzzPEY0bdzNRYVjcXO7S0fPAowrZicVK0l+Xv7qfpzAYVaOiQH4ZVv05cWjnQqxbV43iZpWBu/QMNPKI+jPahpa/vpsel0uSqXfW2tfugqN4R9G0wHGY36349AjFlc4pFopVpL0fEy/6VX/GAB4u119Z5n6OaEglUWcRntWxhx0gltRoBWy0UdbCIDLO/K3L7iQM+zlqX96/k5d/dEyue4rBNfMf9uh4P+FDPsuqVAl+fWSp34jFSz3QnyjxXsKQkmRTerYegZzc/Nht5Ehb2zcTUsM/6DMBWbZsTjxsKvYYtmGO0YDsn6l0bVfAZWsuLQVBhZUStcz/RWISRDldjjblHH2kgAqdRHzYVCeLSB3pd323f+kdhLNOC3XpTA60U6ZW65Juqc9ZydyUFJr0I21WBp2HM8dF/fLkwuJfy1O6xasfJ8BL7sadUBu1zn9sjg9v9VK2ZYdeLWjoA8PrTXIp3n6/qf3xapHDctp3cPDr5zq2DVEFqZb9vE/6LdmzbSMc66dWs5o8vpQ965iE4Rng2ILrrC/83fCZQKREfO/fL5hvD7GzrVvjxBoUoLpsesJPOTUFmDHNot0CKyhtvqw6kPeklW6dycznbOq20eDV0n+5kMvd+n0aUuvciqc/aTutcoJXPzXLuZKjZsJC1drbrF+2pAX1353WPhvX57sCPH+jGK8pOpr/08Uegk/rSBwtpmeMVvqF92IUpRdzjeYRl797GFuW2qMXRnOX6gku9rvnOabyKmcJeSIuvP2kUGeF1/H3K8egBHf1h0lugV/PcFJtZNfU8Br8YaQT3L2H4Hnaj69Ov55r7gXL/cXkfGabgMqJZKTP98eM/2Cp5vLGBmVTsJqqeXJ+AuWcZnXT5YknrHm7Y38L7qqFj4ShebI5IsoXXMtRi0hLv3DRkAe3TKh0rpU3taR7VcyTn0VcWP6/TGlJaZwCeFKQCyr9Ugp5vEXk8L5qN1PhxDj0TaKAsIdg0cD9T97itlKZWHNxmDhT3DS4+4L1U/U1lRds+lMkS51utv8nSTA0YlTlMzcYhcYOExNtxLpqKTbGNvahrNpURQD9mWcfQ5R0NAPmlTbr5njYigNHQO6JmDKAPLiXCalgbyP74XT13OwproiRkz7XeN49VR0tFYVZ8oIwGsL+fqnxjQ2waU1GJAH4xnzJQAJm1hR1s4jlG2uhM25cEzu03kkVvPJZ3jCwRtPHTGwAbdhmrDqo/3qVfCQ5uzDw4iOb62OD4Wpoi57zNflyk9orynnV8xIM1/LRGYnllR1id2kb9TRr1XkKJwjrJ4jWdd4IbdJYKJXtC9vmAiMTN31IJd9sPhOtDW1RdUWRZSgZXnqnnh16Lu2bJKSqDBwYR9iEiWPB6sC/glMoMLlgD/njiFo2xPzKhLrPzKBsjVbHBwCjFdDSpoK6DC0yGKaQi5lpDeDRLIpJu34AtJim0kq+WmX012z4t/bI4S8IcflE/TqPSlBr28dSuY5ikt+hcXl82Lt3NhtwUPMxmhLczrYdx8NK1W1OEuYQyUT/Km+0LSQPXedbr1mYe6lJ9VF6pdB4Fa9zo98UCMObd5VMQEuMyXP9+2vh+5v0CvJg4osHLeLelWXY2SJdQO2Vyv8wlKLbtlZZRcoYkxm4OW1ivgemeuSISS0f74Ip5eUuLBOXAebpP+2uvftYoyLAe6Xprhz7o+hgJaB/7o2wvPXoMxeOCtFl3ioIJZK5sqMSIDwOu98vyOPw+U1ytfY+njI6vWYC0yHHfsd5b1b70VH2REEPAKXFzqcrXiAf26rVJmGooBmueD5tEmfKk9ZrLmDNkvMvHZn9fSemQOruvs6BE0iK4inHoHkSmgxBdUCPoCYscnIjt8JmNDjf14lSyMBqgBJyWRCWH7EYckUcGo/WCmyRB0Y5yhozMN+3hSm/gBOCJpMqTNDxtqp/d7nPcSTWyRnbVA/XwqwkeE4O1UU62J52pL89ngRytKlwT+gL2C5LesKDe72GgDT4q0HrigkEqrusn7uCRJPS4s3rD8p1ETnqjFsM6r9XlZHc9bQ82FrtaxPgt+SIw4Np+u4XKGPLlWpv8SC+Ba2Yvqgl/MLfsOmJR0Y77LKWXqc8rqTsAHGrqN2TjCSNpioPLX/IZ7i9yaHUV1DK+rNZr/zmW3dI+HVW670Sq10+g1NE60VReIkkOFfQTLe1ZHhcQ1VjBPMF511bEar/xnWIF/4nWqW1ycuXoReLDNtfWcu3bOxjUAr6UsQsFBG5c+4EFN7Vo5GEnwVeHSDFZIPRhl8WCvTZx6xOII61KuCbZVwuCHSXtGOKpW5+WlgJn/SEo9zPX7tCmbnJDNNK+g4+4P8QpSQ11e2fS7Mw3bXZX6uGE5QntNUwqn4VxA+Kl0B0jZuWM9TAcL6Kut8Z+ms2lBIrzjKMVcrWDBca+myZveYXyWPGkJKY77i0Jdr4116I/OSj8IHLLZhFsDIis9foeaObwGHuis23ddaTUXmCwtr9AOM6sa+LCJkqarFrLekuS8P2gsFW12lc9TDFNSaqJPXPUTovdM6HTzOaxIXwvhrkGlukbd2EcwrYP+njsmAvyiCBz/BuUzWFewcp3z4PsBZaxBd4g/lI/M+Nu+ie4Sk62MKC18HnsiexC6UD2ufdhqR4a0YzawSS3JqtnRjcuVTYEG/1VyWsA7XR+t6Se7EjK3bn7egzxJR0xMiYSGRZ0N2L4jeXY7ifNppbA0Mm0yAUp3Ty51om+hY1VfYdMLqiOjWE8hig5cWOq72IBdtGKvM0vWRbBtC+KAjIrRblyLeURvEbX3QIfijuX0Q8TARBt6138HQ12L7ZH+aPWqI9DMVo0rzFVusgJKzYkwQqNlPNSalw0lskj6Fhn7J9aI0ePx2F8zDRdexfIZWfGjHffYWpyVAARglS5K4stRnyOlKBWp3sO3Qbssw3IG5viuliiweN28En8MpMpfvndCzcrIpsrw8bL3HTTZIyHCRHds/8Uz5tzhm6aqQI6NvGHdKcnz/EKC5hUo2jUih63PRs8EpFyOzDkYJmu5C/b1yJZMvowbmc0ruWGzVAtIkDGsYtgYMnmlSBGO9VYAzt4IMDW+QVIh6PL96vTiToEzQcRyZIJHjd+44pMqw7+K0SE/ZB0rhhHEqI1SiveDX484Ph5TGLXVmKO8nAaj5UbL99QOqdNiYyUrLjcAJ0jh7EKWnCxUSxDR7YawdMBFnqNqKlRu1umUqvr9sFOUqkqZLZP8+SsjwNBnvcpOTVtRlGs2knmZCLF91ZJBzHDcyAevM6KJkorTpkpaqtyj6X9RGbYooRfoN9lQKQU4LYBfN1j0Buk5ew3ToklhF7OhEhXCDgpxPryAzp059TYZHx9xc9umWqULXJ/OW9ULQDiQA880CMRWm13nU6XOUNy5FWZbioISRRTKrw/dPdwjm9nDg7fCoWyK7FTJJaZ4MVP/ASbMrRRu4tj3dx3VT+oroBL7Md8vhryPIIkaO7ZyjStqSug/UtqwQdkqeT7vOjJN4AxMRRBtmH1dD9PJzJtW5RcytmD2apIadlw9A0rLLOIkg+5Po9Ho2Dy8aOy9PP1WyIqHn4YhZTzbt5g2aK8vB4N/lNpECWWnUj0nkAEJB8XKSPQr+8BYUF7YoRw9lupeHrUt3z/qaIWktSoAzm+oAG+ffrfLzE+lVi3oj0yRMCYSN6TuG1L9zl+q5iU3KgLPX7X95xM8I3g81Rw37M2j3RxEHv7S5TtVd99li/9p0Iqj1/teHoTAiMAxy8fso3N+6T7MgHs7W0W9pfAPlXeUzK50FNszbXDIBgwzJlP5f1y5Ln0PVUlbdfTLRmlQ1F8T3X/LGHg3zyA//ezCK6/TwX4d0/H/ytyBv70dBz7kwwT/CchBP5rwtD/N3NB/izbw/59kH+SS/j/cMf+SHBA/kj7+Js9w8H/hVke0P/7WR4o9C+yPP4sUQr5MznG/rvk+D+wKv/bZnk4QPPXLI8MOyDL6jkGrA7Kc9igpc/PEU5UsUNzzdrbxUGL6srmazWO6pzwcNiqULMGW78+JCbTe6hVtDn6LicsL//rVOXdkz3Df4JSUQtH8Pfx408Ix0HnfvzEe4z6ezuK7mQPcl3ZkMzq8LDVQwktleWIzKooxSIPMzhRnmSdU8tJNi2Zg9FEoUO29SEljkRzujYzN2uQlNozd+z6z/SlpaSEHC1RWiqKPKlQkBVNlWV9pCsM9SAo9jINDc1imhS7ixVT3Bc60adpVBc6t1ipg7SiSlY/N3M8fZAEzJ2TaFahSK7nKuZRiZBSM+SJfQEsaWmNGOKQaqhPH8KVCvpY2lRRVDcLWGgnFOJDvdBNmV3z7bh06vggTuYgHekgoDcuRdKJaFrwFuZvH+/kMotmGYriNmlgbtUgLbVh7jzwi4J+JkcLOliiFVcUm1OiraiY6WMnw6o20j8md0EeNPZ2vI7t/fJ08Q1JEz+coQTmj/KedG+NimdnYKTw9w0ZSp99hox3886BlpoiDmoBfoP+zspmkgeidw86EwFyHSVL1OMjgCHwBlJ5DecXvrnM+Qt9NsxMbHBoj8jt8rFL4Wesn8vN3oBGi9jpGa+1K3Y001O6GzfPVDEnLM2IRiGcYNwEaTB7s/cqGSlY/WbaT6QwAgoNlYEISV37otge2pgI7WuybYqb7GxnA52UR9G2CU1aoGA7WBWo2e02/3YAO9dhlKAhnWfu1GXoNGZkw0E0ZpO87NxvJDPn4iAYHIQdhGMWDOD6CYt3n95eKaW8xVTJjp0rYuVZLhYRHK+LfciBlxsBijRKilzpcqePIbWoCUli2iCSddkzXndBCdTSJt+IP2cjhEp+jGneDo+34YqXEMxascJGZ8xkJA3cgBYLk3c8kZ0hCxaDjpBLLh1Iiv3Lk3oXcSTf0R3f+SMAxdJ+A3BCUCQ2baTE/I4SOIPJZ//XaTaqACgasPylLOIoIUBGaTqAEodAqJLIDg3Ojmxul02BPc7Id+MGiDyiz89WtSL81USKLMz7py0q1sVCycjakTLSkyJWfKGgyRW0DJ8HsIfjgoptRm/lbWr4EjdvLpQJqT5nhmrnKpFYSEBqSRVPkVWbY/ooGkcfzPwemFmaRAoGdsI03dCnt0hYPqkPNwvGzMklrR0b0jRLRKQ+HZB+OUFdnLq+k6xy5zWIQeYRhNhWrFG/L+Kbm18HNXy94RHn83EFnBixWLeNUhaJ79IZXry78Pnsy9Nd3mKfaMAsAiYIvIMlWtY6XNOC4EDJ653hiCXnTZKR8Uike7Hqzke4i20J+/ppiY2Ptcjea3RO1aS0SayOsfQASFrS7+4PHEmz5fkYijxW0nsW5lQ7aV4W3dnTh+mINe22zZXdTLjpwxUnmbwznrXHbcDHvrSrz1VTPpJg83bSTgixfuRtnhr49DcN3zCwqC+p6YyLwrXNXOzUHEa4hQ6nzUCtUHAqFk2Om+VOF/bXR+2+oz2kbvNRKKHbRlbnGTlyPhVk1yMDQK4CbtG0sj7JSbXxhjYHn8xbDmG8a9j2c/IrVlw8k2CPAzQaMZO3xjGv9Xox4mDxkq4EoUIESGZvS9M1YxZOLhSPCTYDMy2uRYVPnWaGDiQoCvmag8w/YOxoL8kml/Brkw0ftnPTXnMQUL1yhOkzBp8pJCKn7aLl6znQVgEos4tG0wE8JMoo7/zH3Kgl2Ne803CBH9W0ciKmwIzyZX5yX/0EmWFCpFO2Nr9/elntcoPsRXFbYJYlKFeBWlnzXzM128ho3VPf/pwCfLuLNOg3fp+4xffKmm4RZ0ujDo44x23zeEN7dWN1aDSQjTui0in6Dl21++ZAgrh6Ukrtu4LRmBAtp+auzc+ctfp5rkbUvbYJ0Wo4lUkxmuSID+qw/E/iEkXUrLr4Vw1A5gdoqyDo5MD92hmoyjpP3LRO48n1hco3M+KzAsDiXjf+zA91NIbEna1wU2GCgL6HTpH6CvVMiSf/+fYuTcpbwmzkqnzerA/T7D9VOGdawzpkpWXYtxOjCCIYMjiFm4PkzibHWPRwiIXWrNmXbtb2wqRg+XUg7VPQxGpsCtmvuF20jwGWqu5A3mMA8QQlue2KyXxvfaWtOzvfyxJFFffHMwxvOdFY9ipiI7SP5D39NM8BbFyH1clagN6D3s2PaZQWg6sUqrrUiTdWtpIiuQTK07GNZmpDyrqY2RmUOrNpTqQfk3LRFFL2ZiRdQmVBx2GOiESFlL1IYjgGHBWyWsxPbrXIGwDFItnomLR78UfBxdbt3lOkBsTsSDRpEgRpx+u9ELRdd1ECQvMiwxP6gre/muRt2FARflxyj+s+dpzTDqXEjhEIcgz3LJYDXKZmEOq1QInShZ7JZhfIOyN15Y0pyq5/NcDCDsTXyGboFb33EKvYMV598V+gmBYAeL1VXWKdVSvkhNh4j+ActPqi4nkzhsjL1R5bOi3SNLW84VMZATZHFuEJ39M3n3SdtQEwraG8+AHemY/II8hpZvNhYp88F/MxqEnv9m1aUknJ59XPAl37K+w7JIt3ssAujCE3zkkYuJvjewowow4ka0cWGgaYABLyJuSCPwFbETdeFF/ewIYuHzNuol9MsF9//htM1cjucIIlUi9XwfhO9spRpLM+b0Kh+/JDu6TI9KU0lw8asCCKR/ESFOz4cnv4hRP1G51NUCSRlCtDu+Lz0RkpG2ymLTkJbZyczrB9SS8EhommrTeh494gn30eTkIZtMBWJlS6Yl3lfaLVCI0bIBKx1bw7HMXup1NV9GlbeCGCbfx1S63gM9sPWumIIw7/3PrZuJ0tSol9qo22vIFMhKK52rshZ6uMBQtrQvVfAbUe4Bs/H5SFzEcHHPorfwYjzgD1zS7wHLOwm7Mu3etB4L7d1cPFdYerOzLdUSP0PfOc0edl/VDsQlYyuN5CtIZS9565J4/y+jhmaWULtJ++lYbBQtle9SuHU24Nz8xVMpSq7x4+VIxx4wF9pQOFVFwWOwUy4YeNHD2Eoj3U0ZcASXfnUL7cj5iw1UMYrUXT6JJvRzJfFWpWjlcXntVMBOo+ZfWbNlZrh6cOf1K2rgKNR8EtDnIl4ey3tqpINwzvbzw4rogUeOArFS3pNNqt1/geXIa0ScLhMAixYpG+ldE3hYaB+uHuLXxsi87EIlBt/Cz9VKRmhfPI6+x3Ggu3Zsf++FpiwizBDTVW+FLCsEQfdkwV4dcslUZ5o1r50bojFlx2NnIAEDBLv3y/bOCI3W3Zhk7kvDlRNX0Pfg3zMM7axG6b4AjdN/zwmsU4loj6UL2hqUCxpRObcsckIzaR+K/pVFrAJ1mZ6rmkyDSXfWlO7tfNiNwI5R2Djyx7OeYHoKv6mdFHYY7Ugx8pv1OJJGMUEFBKdWHyUJ8J2/dKWNG0Jz4UqfDCLBDxSNNn73WYpvtICncFI5EKy5aJHYmxKyGZivOyZInhvQKhLooBF5uSFEej4orH3Y5oqt7Dy4N/Q6gd0pwz/UbGRhcyv3Pp0UcgELFI3QNWcgwxtLVGYJeYMx6dBjUi7QKVSVpXdIeNO94q/OQRNTzYcavytTbcgFToG5zyTemt/3D2Kx0e/JXYbNEGgqk48400mp4dXF4/G+fnRQuDlW9pcQKPp/SGiDcD4DGRLXomjad472+tPKzMnO2N6XRaYzEzy2A8NCs3EmIJavO0QWmYz3QEkRrP5h6pgw3aiN/4brSkF/TYW3agZt8pNmYwkAfUfVum3qzieFu/U5y/q5mplVpyamPRBHlbS9sgysLik7tuolkmMwOMBmt2mu4v4mWQfKn6jsLBQxjUeT3U5UWK5zMTprFGKbUJFCWDFgEjjvW4UleP6g6bgJQYmhUfR/ZbbmzOAgbPjiMEqoWSxvNDJ7juC/O9QrEN+a1KKmwf2y6OmM9lUqx9ouvSDrdJgXpMowmKaYmn8l94hMZiOjBSDjkA+emFECfRe2cROmDX5WDtlMY0lsecRM1Ffyxhmy4dAo+Fg4OQRkwqwsJ6Bu2K3aLkx7mzI2p7NSeZGtkHFcKVUsa3WnMhmk1GagqLRLIrRktmpz03TwHc5p0/E40wCzVNFg+8ZXAUt+z19wYWJcqASbctl/eWSr1Mlr6OLnwN1OzIOhQjOe/BsvM/fdSSSalTCvW4GQdkIP0EOIXUru3risJVgHjkEeTjdIMvCzlo741nPIQn2tdGwnNEPk8hrq0HKUiYwmKU5xbptEXIX0ug+dp73aOPJ76xElcTH03WUqdkmzyWkIf+hV9hk6avR+53mSOLgXAl64gbZRk0Cs6EmTJ0x9woNdi160iUfzYGcby525ymcNvEa6MfpOJBAmzcThTkYjAia/G2yAciDTWpOxrZnswQh+A4o1+gUw+9o+no4Hh1o88qBye4gn1xAZBlrpbqBGu/SiPQepx8NsBf52IhW8Gex9g0sDgUVfJFmmo+Wn0SnsV8cLi6UL2mXpa5k0hYiaKkPqayKlXzhA7a9+9ahKlCZPOXMnmPTr5ZKxSquY2lcJftciaLzZXndDdVsuqYHqwces2IYnBJAi2ZZb5w8BWLkjQ0f2j3elDHo+rWIuT5/H6DhH+oTv4JLoaH7YkO34MBJnudy8zXj0104f1cSElZpLUEq5e6RjdVwHeMtV+AdUbm4xewcY3DGlEZKQ0O9X6pp2Fl2awFxEumudzfDdeeYeZ5jcw9AhYMknAMWiSk8kbiOV5qj9K/g5/UpEOgHYGHajyh+L4RK4VAlsezqyopM1GlA2GkUzuMd2tKYbnQMdeumJ2idLyPqRPyMJHyjXJsqBFpTVLqRZGOvYFDrHiD1FRKsLZ8T+BLIwaamux0mny2hDqX9XN4dWdk38phS2ueMTDJVJe1e+0xc9r59VrT35BJce16c1Clyv2BFFOCdD1aX7/f88t5nBopVVF0SFLLc5mrNsCimWuWlK8690kxRPuh3BR8E9Ygm1M8qLPqCXW8zjpB1NZIdgeWHK2e6q87shwlra7N5me8ruMP++Oi9bpL1sq5xaw3Db273WYfi2GjTHgKEJ1SR7J96thEaK1qkQmLSx18OOrTsSa55SIPM68GcHI23+KBPG3WgryjyVeqqpZrtKIRcLPyvfFjsxAZgVKUu+1p0ST/JnooiVo+Hn0MtbQlJ2j9hposVshLCGYTwzXDhyNliqzjdD+GiPiemsiibyZjZqrDQwofl1glFtpE4wZ9c5BnIf2eW9g/rIuUChzVABhxiIgCHv/yG5lUBCW27/kG70PGM5TqKzZoAT6IXFDZbqNepafUHVwGePHValETVKkmiH6VcLMV3j563izp0qvrTMFSkyZmMRAxq8jsRGDHsBbUFCSmwq7zr6s6ERWMV2m3kqLrmF3YZ4Y4Nb1LWfG6rZt4Xmx6gjIJHINhcClSd3vThQEOzBu2mC0N0vWsgtLqEtIJSxIHOJVuqISJJuMdD2lyBR+e1jdj6DnL/fIu8zV37650MBxZP3z8s1Nnze9j33+iMmRNd8/c2MJ+PJ2CqXN7Tw6Lez2oL6iLM233d0aVgvfm51G+bv4ks1xTE1hLTygWyaq+sTmBvmg5jxDAHFuWgjevRs+VQKXcD9cp+sdwOu2BiTM7W7ql3/ACptiZEy9Zx783UZ/HIaNuJJY3bLC9Ma32Hqw+ZEp0YvOKlstopNNIsCVzaxe1sOTJ6zMqcwYr8+PplDTzIQ6ChbgyN/hdnHU4CCUkKWC7nwFI1abSppgI5cUBCepzhiq76N8vZTjLMI7Hgfd04xUFzdSnYSiuKVLx43dYzQ2NMk08+/fQA7YRDircyh+HKriqI/WOWfp8A5cV8Zonrgzr4x8YhlY2tN84Aieru+PJ3RDU18RF7l3o8Jup0AVcLoAfszKtwvtgJHir0pnH5WbWhd7/nrsC4iA2ekP7aIhtMXb96Jx1vsewcKpdqDKLg8DmKTQB8ztC20TMOGqK7qKkDzYX9q2WTFwsfl1u6SMrdyTVdGGXNdbOVjNrK3wmVSid6Znr5vWZa4aMvuqigvEFGoPGIiRmf0SRdxXrCJimF+h7LHN/mkDD8R6xwSQBEb92tBimf6fS628mj94xEO5ScP4S6A3Z4ohlJRqrJrO3g5nYFNKLA3B8NIb8bEMh7N9aLMptkOSRtS166dPi6kpFdb5FdzcgkaFkLeu99rp8lVN9jdRExbLZMeBDCUX94FjpA6MKTJHOPlTyTteNWGxxUTFOFFhCprerlrK2m/TN4vd7m+BYBmOe3Xd+fa2Zn5XppYkZObwx0EuydA59LrgVnZ7JvGFIiaTD2QaamRX9Xm1tKk1LXQ5dm5SnwCwiihMcubJdQl1YP1WCN8PIAMeIbGT89uk0r1yJaB7+92obHFNCV63EspAOZ1pgxyohUEwAnrkfRZNywKv7s1/clnhPqyt71A2atXjUymabTpQpoy2CVZZOtBnhBpYjEoXwQoydE0uLwLWVXHkivDcJPQOxqI5xOfZ4KS/rE3WVaO4sLlC2zoi3SU65DJ0za5Dv14winJpEsu2wU+cIXIdcyDlctrcl9s2usnjFbUWepiWR8dRr2zualWc0Qgsi9q/zrKFt7jcGuN1UJwRbAm/8i3VevrE8B83giCMt0nbHs3ReFOhl+p6xoLmm1JMok4/PwnltinGHpTZKiwCbPrznLW7h+d49BO/ZwxbUNoJVdEH+nzb+tTbeaI8qESfJZcw0/qQPkJRkuSg7N1JRFD8JBP+JHALoXzmk/U/lEPzp2et/2zfskT/JIcB++6C/UcDPL4swv5Hsm0xAkW9Wwf++yQT/8a37I5ng8w9b92c/L/LflkrwJxv3vzqV4J/Q/0AqAfin4oz+N4kz/P/jVAKL/psfjMiR4+tZgXCj/ZpUVfcFSNcNjkKaxMGHcfguPin/YUXXsaavzFyPc0FXeyHGlK0NFRUXq0B7BRBa9uxTF2lVqgAPQPBQEuImroX1GmMmAQAwOo20ca19zDb82FAIyuE8z04UNl5C1uzQjKInfu/f1IG+XQYj94GYBieStH09DZChbIp8y5lkAVGgiZCkTFLUwlwFaSqkMLBvFisVkOwVp8nOTNUz79GWNSuqEY5k3x8igHPGY02XtNk0rh3llk2KJLaGnxFkIFkSA7rK7VyCIiXJ0OASfJMogZni35D5/hmQepi0PoL89CQ+HPthjteDrhYLdj/shpbvr4hR9YC9X5joxinMY6+egilkTGo2wU033hNINKpvHMP0Xv0yg7WnZDU67zrFLSiHjR1EEaSqzXiIpCRnR5TUYD5DTlGRSB0W6vvFM05kv1oproNLqXx3+PQhvt9v5AIpskiRcRc2oFXuqtcEMysWWWO47frxyvoISJkhNdrSddKwIG3Rx012RhNS5dX3NEAAkscjf4jby/zxrPkYDnDrOriVrk9StplsbUvmfShV9Tmqk8+I58Ba1qp09JqcOTmQSDIRZlgCN38z/E9QEvSNOikuOhTIgzewtkzeUp+iaR2qKlanXQ45fb1dCvvzzIgzNE91kIgjyYJP7UvNYTCfNkZkKKFWXOhTBnH3ri8hLV/+rOJ+nN4DGD/nsdlD5EJy3H0XTiLVeAt4XvRoj9y2DEILfZbUflk0CyqDgnOlTrYaZcm5h7s3o3LK4QkYDHq9WgrE95xjUNyeHSHdgkJS9TAYP4uwY2TlyPee5+o8FpvKkYLE7YCV4Ui30s+5CD+6Jw6gGTDUELSnTkZa2aFDztpVe9c+p0/BTYQajQzyQp68nNznDgQuxZZgh6wawD6kDygOquliMCUwek9WEjOgghXfIGL4xtKpbeDHRH+Taa9QX8BcowLtsjOBMelGcJLVr03vfgDaGgCyJKt404sZQuVO6Ga3G+umsmFQgpTr5zCHCQujuLGgI9ROq43vJDlXtjKh7VKEYDhRwseBNiM6Xy+cTab810aiRexXOKZPFqFUh72WXuqi7ru1ifXcd+IEin1NQzQePziJgsGOnPEYDVESZ10vfiYDeCup6uXMKfIqOBZGHQX/DQE6hJH3OPWINfFSax7P9vd8CjPOLhkxhPDUvJxPNHH87aMmHxvbCiDKYZY9YnpnvPX9gu95vQGrEAW+qzKYvj4/Qy5mGCwU9UKw0OC9QqbNN+iMH17Btuz7yw/67HkFz5joSYT0NU6wTJ9cSBWAnn54clES9SoecSNpWvDHhhhOmd5T9DTxp72zkCqqBymWu4rVwdoXkxeasz/moETU27pKHjFppPRVmjTEnEtIAu9XBeAew1x9JrjXc8FZZkKDIoLHAVRn3nF8ZijMcLyi++Kr5UGeRpjA881QWN2N7rx49fukbS80EoI8SuWLKnkJa9cvorIOHEURL+IxQDNHRBFyQoUMdXg+txZkUSpd0Nng4ZVznbkuNX89zJa4z+UG7O/3hec+4JZSnXkiHQVnxgE+2HoggYqsLKpoj2KQGxR9aRZilfPp9xSI0R1aiZSqsGNGKOqSjqkk9BuVvEiZvkpucSYBnb0rlqrZA2c9uCPaMjYsB82Si6xwVBGet4DuDTMG10R1poAXwD76hJgWJLdq8e5ISkNBvuhRTWEOBdx9fuW5tCgLhA1NRZaNyCFer6hdup1P2m8mAGcCT6eXNp6PHeGKidBFvNYveGG60qZt5vN9HdO91cZc43rEPLiEegQMvDwp7LHSzUuHtqnHAKUW4KVKZI69LFEa6QCQtifs8KYos/MxmdezR+Gnn4rbdWU5JsF+qjBtxadDaTrAAvKZuxAT4NRqO7QBr7Fbw+9AHyiKLE8h6vAykzgFNUV5oW/hRDnW/d75AMM4Ypuy7aJNi5Vn9OsZMaU1InvBTA7T75tWgHqkLyqj2HxljnSKN5wkLN/zghUM71VGZAO3eAmT89pPJydMYlo90qTs6VWacNcbmZToLjtqlPN0snMyzg1sveWUtiItMh0KvoXDIZW+7+H3djyWCm3n0aVsZovL6s5+vpNugv2YPajYnRh4CwdTBX2+AILJdUZfyeLsK6jYk3yLESj9dY+3qTSjKAp9h5ZkC/QeMjjs6SDkKfcEraHug9AtqPUM8qXzyBIfHIRX0ZCuYSHzqEUCK2O1dmWpSvZMlX8Vixy/XBrdYBGy5GiAH+sIFNmg1jGzuffMVzicu3PJikQtUVP000aUo6KJI2YOm1BGciXpoRBAKJwGTZnrN4znNRRCyi7Hlnz1mI188edgYsENSrTWcZuBHGmzZOMop9KbGW4ifbeG320AYQrJXGRV8iaCZPxtUa5+ihFbHkmUer+2gPSe3TrvVwOYSt/BstpVjyYtRiAr7T2uN8d0imwsrIvXxE8wAfwE/B6lmViqVVqZJsF9xl+8bPGSwK1WX9xx4FjJnRdmr/Kq0sX3N2WCby9vb9iroZbuHBWX9rdNefYqMlkLxbfpDraULOuakxuNO+kyK+LH7mrFwZMv7vjw3CQk++x3/Al10Cb91+5OnjIRlSV9t+jqzet8rCW/+MzkDC9RUb+GMFQVdq+Avdki03DXdcStSjkIqt8rjoZI9p5/ol600nZY8GYzWGwnHnIsA3CNXGrANCGj3riI7hhpUxoe3kL+ffiujKnvz049FnU1RZObzQfB3u8mKLuf95AtSeoqP6RplcsocVHwPSOaQNz6JF5hkrHXM9CYbIk3z4zb2Z2mP8QOeTrYcHCQUxwSuocpuomPUnORyWxIA7vIaW8HRCnuw8L6kIjAJQygitKYBHnZbBw8CHQoxxeWTp0Jv0wcEuwjZbmW6JvbY37foJ8ZQ1hBRhSTumQM3ofAfWDFugUPXlOZZM5NaXX7Bbv31FQUViuGwd4KAlDHZlKlG3IpQymaGjI9UZ8oFLcsCt0sa7vS/IZk5dVHLG/xagmNH62dpUE25bMhVlIsuAJ8bFp45XbJmvQZVwO5RIpkXioZrp5L8mLbIBlPqvY0mczDV0KjNmnR81SqkjxVKAeKlbfuYRRz5xwAWVG+Y7rF/+nrX+krBihUyNhMtjzboS93opSCLcYeEvLSF9vbQPn/2d6VNTlqJOFf41cHiPuR+xIgQJxv3Ie4BRLw65dS93g8M23vRHi8a+86ol9oJSBlVX2ZWZmVn48+XuW40BHjCgy2j5mZHt6pekK73nUcu3xrssewnanwrMSPh+Vd4A6hOT2XeB+UTY1gbQKgOE30Yu7WxWbkvmNnYnm3f7ZjdyEFcYdNEQXez7dl8JmNeyiqMlWVqSInlL098j5Ir7Z3Iw9cV/xbDF83S7whbxvl+aRc8SQUeDSd9ZctmifOl3VQIzuuwT07P5c3ybc/4MOFUpYcNkmVPedVnupoVda1VmhIRP50ycczHii/v5oWc5dHtQa4b6etT0ZWKimZ/5wupLOxaFhmyuQtM4cFulDl+RkRQvp6resy8h8I0YHElYYt4IsaAI+0i4E5lkUpfkbDZ3GT0TK8Pqu1Dpvc5SxQy8RcMFYuTPSmtHlNWpcYLmqEOvySXEzijQiYbRQYesDihqcMr7KTS36GWJ4XKfnwma7giCsDw8tyuCMtWguVSw9yZnlYi9WZd/M3H2BN+WSM7k19AhKe3GY3OjeqYuQINZ6ZlQpUmNh3SWGBw+Rqu7ZjJYNmzE1IOfcI6niMmsuaW2+plMPPbLYCxwsubd5tqgzMvdcAn5RfqzzFH5Zx4HQZuaWQ1rrumZr8BLlXwTs1Gw2awHhFTOqS1HW31egGHFQK+UJ890x+35zbsGtxVE68igtjOoNOW2CHfmwark2zvq39+fRopGlPuCo51yAAiQOusAX1XnsQo9A7J2xVc27P7R0d3JznHrEzDilm6kdMsx6mU6PH2Z92rFqD3oVPotyKCDHToqnRux/hiN4mCnOKpnMoIToywcQFqR+PHCR6FMzwB1+aC21vxCAu3QOx2Q3ZiWkNb09eAa2HWFKQ924RR+fwPnaetuN+K8EcLI12LZiqPL4hqZvOrQETkUNyt2NjPrblwrmPr/fjqaVMtVVh5eI6gy7kqNW3r2CeVpqzd5swv5I3a9V8BLkG0az3yxYw8uiSbG3EEN7A082qsXq2NRFb5ySsEuuuVHwD5dJO3nXJckwDnOh353Cwy9lT7wPQc3Z4QsbkqzcPJSqv2OrFmKQEJNEDvRbpWvVTUEnme+sRFwbCLbYgVvd9fSl4yxzXBitIG7qKhi5NQcHxmzaBNNGrYTOIhRAWWielFIGSZJ922UowglPAbVXrTfjhefoBLcueab4a9djeKyfiGOH0KV6n9jl5bgMUPdmQQSesIxf6Ph8wChLC+ljEt1Y0DNFdsGRx/MqoZ67yqIvp18qT8DfGxtOADfD5nCcknHbr5o2ecqnVO2/R9cp7wWlfTXRVBJK96herEaGTK5GIKMRsUiZzDr/9mGN2NbQk5MbDHR3SBTGKf79oHWKh8wXfae9yTKfTFaIuVw2C74F6Z1pLgzhNg/F8v8FspBKs3DUonaTUuloortXSllUCMctdcoUOZ9PY74RhPQ1y3x9b40Y1+pgOV2c3jU7rdd6VRT7Ib8IEVhXmGwQ3vmJIy5gO1fC4di6e0fYMACL6nRw61xumjMt043NaaFg6JaXac5i3uM/HX4cDhg2jcakPm0nzTwsFYasBX/1ehcdrA2XmIRGdUaMt7uy9inRv9oi03TGkP3AUsa6xDRwsAmMQqg5OxtWBdZA6liKkvKg7UmjPAT/myd0sjlk+XPhj+UsZvqxHqF/NcSA6XFvEqtHaFHCJdbeBQgwEq1nCKJcTTPFBlY2TK8+tLtZ5v8EE2GUt8ZQmbeeMO2QrF5oiRiK62NUslnXzuFzovnLIqeFD5XUCVTs36BKTFBmAVl3d2SOxMlaeYjgShH6E7jGwJfAKWq46yFaCQpga1F1CQnQiDtdZq9JcNDN9A3Zzt6RNbTLEjdMGolO6qvrnTlB6upsLExx43vpazONdUkNWfqj/tMe9h+MZlqOphTGCIE5cL/GlfIYzAgK7b9D+QFRsWHIsPcXZOFyjlrWUwc8hLGnhK0PS996OrhYJ7UXKsxdhCI9Vs8vQeqYCDrdgqvOfDF8wYdgkcJoyPc0I7EPxwt02rlaJ0GjiFRNeLLRm2U8zMMSFWg3tsYYz051StNlNRrYKT+DF2IyMoEPXJj2duAWJ2MdoFLQiZ+whe0SLlAKWqDpLnLmoR+AJZh9jUAvR0TdaVdmqyaUAfysLkAIk48BZgEM8y9UnPYwLuO6KOlzqe7Ts516lhowWFOfpg73X2CqgaIQfMivv+/aqBnnQdujN0OGTVj0H6xJnjVOctfpGpPjI3GJIO0xiNscpW9xTg3uM55mxDy17+9IzIvcoFdAdQ+V1/liKHmcd8y5WhiowdfrMmyNEXteXXK3GZURhNhxftXkjzcwgKqOQbSJp9iMOLzZavgAs4y0k8aYIXvJ1ZaJlpY/l+/DrAdQx9oRxSwb98H3mI7pfd9c0SG9NaLnS7R6boT5dRag2bF7A0PKw2sX8ICE1lLa2icvCAOYukECXkAJ1aZY2GBMBvkQNneK6ZcKaqKtJe/D3Yb7qyq2BsYCUHx3YoVWohTRGmS7Ym4zCYpvfHJrlsFTWfWs1aZmBB12btOFJ0z94V3oQxJ5cSbZgzfw8MeOmgQCcSYunlWwW6IKSx88/mqREfyP985tJSuTbQ7MfZ3XgPytJSXyQpHxLSaIvHgQUECL87+Ymv3/EPuUm4Q8OOuPEfzA7SXwzHFlaZJ9+eD/NZV/0XdTwn//7leI+y5x7kE17jWCdzfP2rs5omfsvx/c3U533fpmS7N+nDedoKrL5d+Tenwd+y++Ow5Q10Vw9vmTt+eFK/nbO/6WVDH+nkk9/KSVT/w0lH7qdNh/cfyzk98vg159x6/vD366296s/fwX88MF5v/XSV938qy4FXxQWEF/j1NvXfL/n8wDT0xRtvxIbgMD9e9+Cf01Z9bX01xQzX8qDTerX+z/PtV/08Qd4QT5qjvAPJdY/lFh/e0qs088/fSLA+oLy6kOmK/onEgW0R7TwE8X9Qpj1JafWF9xX7w/+f6G/wr+jEgv/wGf/EexXH+PWR5VY/+DWP7j1t8ct5OcXXh2w8yqP/QZ5jk//n4j3kK+h5yPWsB8EPWAj7BeG0jcP6zPRK8L/Cw==
\ No newline at end of file
diff --git "a/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.png" "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.png"
new file mode 100644
index 00000000000..ecdbd6d2c2e
Binary files /dev/null and "b/docs/database/redis/images/\347\274\223\345\255\230\350\257\273\345\206\231\347\255\226\347\225\245/write-through.png" differ
diff --git a/docs/database/Redis/redis-all.md "b/docs/database/redis/redis\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 99%
rename from docs/database/Redis/redis-all.md
rename to "docs/database/redis/redis\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index 55dc910f54b..f2ef0eb8756 100644
--- a/docs/database/Redis/redis-all.md
+++ "b/docs/database/redis/redis\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,3 +1,9 @@
+---
+title: Redis知识点&面试题总结
+category: 数据库
+tag:
+ - Redis
+---
### 简单介绍一下 Redis 呗!
@@ -595,7 +601,7 @@ AOF 重写可以产生一个新的 AOF 文件,这个新的 AOF 文件和原有
AOF 重写是一个有歧义的名字,该功能是通过读取数据库中的键值对来实现的,程序无须对现有 AOF 文件进行任何读入、分析或者写入操作。
-在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新旧两个 AOF 文件所保存的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。
+在执行 BGREWRITEAOF 命令时,Redis 服务器会维护一个 AOF 重写缓冲区,该缓冲区会在子进程创建新 AOF 文件期间,记录服务器执行的所有写命令。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新的 AOF 文件保存的数据库状态与现有的数据库状态一致。最后,服务器用新的 AOF 文件替换旧的 AOF 文件,以此来完成 AOF 文件重写操作。
### Redis 事务
diff --git "a/docs/database/\345\255\227\347\254\246\351\233\206.md" "b/docs/database/\345\255\227\347\254\246\351\233\206.md"
index 8c19d6e897a..1cca2575e6e 100644
--- "a/docs/database/\345\255\227\347\254\246\351\233\206.md"
+++ "b/docs/database/\345\255\227\347\254\246\351\233\206.md"
@@ -1,3 +1,11 @@
+---
+title: 字符集
+category: 数据库
+tag:
+ - 数据库基础
+---
+
+
MySQL 字符编码集中有两套 UTF-8 编码实现:**`utf8`** 和 **`utf8mb4`**。
如果使用 **`utf8`** 的话,存储emoji 符号和一些比较复杂的汉字、繁体字就会出错。
diff --git "a/docs/database/\346\225\260\346\215\256\345\272\223\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/database/\346\225\260\346\215\256\345\272\223\345\237\272\347\241\200\347\237\245\350\257\206.md"
index 92f16b970a1..92d30998a71 100644
--- "a/docs/database/\346\225\260\346\215\256\345\272\223\345\237\272\347\241\200\347\237\245\350\257\206.md"
+++ "b/docs/database/\346\225\260\346\215\256\345\272\223\345\237\272\347\241\200\347\237\245\350\257\206.md"
@@ -1,38 +1,70 @@
-数据库知识基础,这部分内容一定要理解记忆。虽然这部分内容只是理论知识,但是非常重要,这是后面学习 MySQL 数据库的基础。PS:这部分内容由于涉及太多概念性内容,所以参考了维基百科和百度百科相应的介绍。
+---
+title: 数据库基础知识
+category: 数据库
+tag:
+ - 数据库基础
+---
-## 什么是数据库,数据库管理系统,数据库系统,数据库管理员?
+数据库知识基础,这部分内容一定要理解记忆。虽然这部分内容只是理论知识,但是非常重要,这是后面学习 MySQL 数据库的基础。PS: 这部分内容由于涉及太多概念性内容,所以参考了维基百科和百度百科相应的介绍。
-- **数据库** :数据库(DataBase 简称 DB)就是信息的集合或者说数据库是由数据库管理系统管理的数据的集合。
-- **数据库管理系统** : 数据库管理系统(Database Management System 简称 DBMS)是一种操纵和管理数据库的大型软件,通常用于建立、使用和维护数据库。
-- **数据库系统** : 数据库系统(Data Base System,简称 DBS)通常由软件、数据库和数据管理员(DBA)组成。
-- **数据库管理员** : 数据库管理员(Database Administrator,简称 DBA)负责全面管理和控制数据库系统。
+## 什么是数据库, 数据库管理系统, 数据库系统, 数据库管理员?
+
+* **数据库** : 数据库(DataBase 简称 DB)就是信息的集合或者说数据库是由数据库管理系统管理的数据的集合。
+* **数据库管理系统** : 数据库管理系统(Database Management System 简称 DBMS)是一种操纵和管理数据库的大型软件,通常用于建立、使用和维护数据库。
+* **数据库系统** : 数据库系统(Data Base System,简称 DBS)通常由软件、数据库和数据管理员(DBA)组成。
+* **数据库管理员** : 数据库管理员(Database Administrator, 简称 DBA)负责全面管理和控制数据库系统。
数据库系统基本构成如下图所示:

-## 什么是元组,码,候选码,主码,外码,主属性,非主属性?
+## 什么是元组, 码, 候选码, 主码, 外码, 主属性, 非主属性?
-- **元组** : 元组(tuple)是关系数据库中的基本概念,关系是一张表,表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。 在二维表里,元组也称为行。
-- **码** :码就是能唯一标识实体的属性,对应表中的列。
-- **候选码** : 若关系中的某一属性或属性组的值能唯一的标识一个元组,而其任何、子集都不能再标识,则称该属性组为候选码。例如:在学生实体中,“学号”是能唯一的区分学生实体的,同时又假设“姓名”、“班级”的属性组合足以区分学生实体,那么{学号}和{姓名,班级}都是候选码。
-- **主码** : 主码也叫主键。主码是从候选码中选出来的。 一个实体集中只能有一个主码,但可以有多个候选码。
-- **外码** : 外码也叫外键。如果一个关系中的一个属性是另外一个关系中的主码则这个属性为外码。
-- **主属性** : 候选码中出现过的属性称为主属性。比如关系 工人(工号,身份证号,姓名,性别,部门).显然工号和身份证号都能够唯一标示这个关系,所以都是候选码。工号、身份证号这两个属性就是主属性。如果主码是一个属性组,那么属性组中的属性都是主属性。
-- **非主属性:** 不包含在任何一个候选码中的属性称为非主属性。比如在关系——学生(学号,姓名,年龄,性别,班级)中,主码是“学号”,那么其他的“姓名”、“年龄”、“性别”、“班级”就都可以称为非主属性。
+* **元组** : 元组(tuple)是关系数据库中的基本概念,关系是一张表,表中的每行(即数据库中的每条记录)就是一个元组,每列就是一个属性。 在二维表里,元组也称为行。
+* **码** :码就是能唯一标识实体的属性,对应表中的列。
+* **候选码** : 若关系中的某一属性或属性组的值能唯一的标识一个元组,而其任何、子集都不能再标识,则称该属性组为候选码。例如:在学生实体中,“学号”是能唯一的区分学生实体的,同时又假设“姓名”、“班级”的属性组合足以区分学生实体,那么{学号}和{姓名,班级}都是候选码。
+* **主码** : 主码也叫主键。主码是从候选码中选出来的。 一个实体集中只能有一个主码,但可以有多个候选码。
+* **外码** : 外码也叫外键。如果一个关系中的一个属性是另外一个关系中的主码则这个属性为外码。
+* **主属性** : 候选码中出现过的属性称为主属性。比如关系 工人(工号,身份证号,姓名,性别,部门). 显然工号和身份证号都能够唯一标示这个关系,所以都是候选码。工号、身份证号这两个属性就是主属性。如果主码是一个属性组,那么属性组中的属性都是主属性。
+* **非主属性:** 不包含在任何一个候选码中的属性称为非主属性。比如在关系——学生(学号,姓名,年龄,性别,班级)中,主码是“学号”,那么其他的“姓名”、“年龄”、“性别”、“班级”就都可以称为非主属性。
## 主键和外键有什么区别?
-- **主键(主码)** :主键用于唯一标识一个元组,不能有重复,不允许为空。一个表只能有一个主键。
-- **外键(外码)** :外键用来和其他表建立联系用,外键是另一表的主键,外键是可以有重复的,可以是空值。一个表可以有多个外键。
+* **主键(主码)** :主键用于唯一标识一个元组,不能有重复,不允许为空。一个表只能有一个主键。
+* **外键(外码)** :外键用来和其他表建立联系用,外键是另一表的主键,外键是可以有重复的,可以是空值。一个表可以有多个外键。
+
+## 为什么不推荐使用外键与级联?
+
+对于外键和级联,阿里巴巴开发手册这样说到:
+
+> 【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
+>
+> 说明: 以学生和成绩的关系为例,学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式、高并发集群; 级联更新是强阻塞,存在数据库更新风暴的风 险; 外键影响数据库的插入速度
+
+为什么不要用外键呢?大部分人可能会这样回答:
+
+> 1. **增加了复杂性:** a. 每次做DELETE 或者UPDATE都必须考虑外键约束,会导致开发的时候很痛苦, 测试数据极为不方便; b. 外键的主从关系是定的,假如那天需求有变化,数据库中的这个字段根本不需要和其他表有关联的话就会增加很多麻烦。
+> 2. **增加了额外工作**: 数据库需要增加维护外键的工作,比如当我们做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,保证数据的的一致性和正确性,这样会不得不消耗资源;(个人觉得这个不是不用外键的原因,因为即使你不使用外键,你在应用层面也还是要保证的。所以,我觉得这个影响可以忽略不计。)
+> 3. 外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;
+> 4. **对分库分表不友好** :因为分库分表下外键是无法生效的。
+> 5. ......
+
+我个人觉得上面这种回答不是特别的全面,只是说了外键存在的一个常见的问题。实际上,我们知道外键也是有很多好处的,比如:
+
+1. 保证了数据库数据的一致性和完整性;
+2. 级联操作方便,减轻了程序代码量;
+3. ......
+
+所以说,不要一股脑的就抛弃了外键这个概念,既然它存在就有它存在的道理,如果系统不涉及分库分表,并发量不是很高的情况还是可以考虑使用外键的。
+
## 什么是 ER 图?
> 我们做一个项目的时候一定要试着画 ER 图来捋清数据库设计,这个也是面试官问你项目的时候经常会被问道的。
-**E-R 图**也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型。 它是描述现实世界关系概念模型的有效方法。 是表示概念关系模型的一种方式。
+**E-R 图** 也称实体-联系图(Entity Relationship Diagram),提供了表示实体类型、属性和联系的方法,用来描述现实世界的概念模型。 它是描述现实世界关系概念模型的有效方法。 是表示概念关系模型的一种方式。
-下图是一个学生选课的 ER 图,每个学生可以选若干门课程,同一门课程也可以被若干人选择,所以它们之间的关系是多对多(M:N)。另外,还有其他两种关系是:1 对 1(1:1)、1 对多(1:N)。
+下图是一个学生选课的 ER 图,每个学生可以选若干门课程,同一门课程也可以被若干人选择,所以它们之间的关系是多对多(M: N)。另外,还有其他两种关系是:1 对 1(1:1)、1 对多(1: N)。

@@ -54,20 +86,20 @@
一些重要的概念:
-- **函数依赖(functional dependency)** :若在一张表中,在属性(或属性组)X 的值确定的情况下,必定能确定属性 Y 的值,那么就可以说 Y 函数依赖于 X,写作 X → Y。
-- **部分函数依赖(partial functional dependency)** :如果 X→Y,并且存在 X 的一个真子集 X0,使得 X0→Y,则称 Y 对 X 部分函数依赖。比如学生基本信息表 R 中(学号,身份证号,姓名)当然学号属性取值是唯一的,在 R 关系中,(学号,身份证号)->(姓名),(学号)->(姓名),(身份证号)->(姓名);所以姓名部分函数依赖与(学号,身份证号);
-- **完全函数依赖(Full functional dependency)** :在一个关系中,若某个非主属性数据项依赖于全部关键字称之为完全函数依赖。比如学生基本信息表 R(学号,班级,姓名)假设不同的班级学号有相同的,班级内学号不能相同,在 R 关系中,(学号,班级)->(姓名),但是(学号)->(姓名)不成立,(班级)->(姓名)不成立,所以姓名完全函数依赖与(学号,班级);
-- **传递函数依赖** : 在关系模式 R(U)中,设 X,Y,Z 是 U 的不同的属性子集,如果 X 确定 Y、Y 确定 Z,且有 X 不包含 Y,Y 不确定 X,(X∪Y)∩Z=空集合,则称 Z 传递函数依赖(transitive functional dependency) 于 X。传递函数依赖会导致数据冗余和异常。传递函数依赖的 Y 和 Z 子集往往同属于某一个事物,因此可将其合并放到一个表中。比如在关系 R(学号 ,姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖。。
+* **函数依赖(functional dependency)** :若在一张表中,在属性(或属性组)X 的值确定的情况下,必定能确定属性 Y 的值,那么就可以说 Y 函数依赖于 X,写作 X → Y。
+* **部分函数依赖(partial functional dependency)** :如果 X→Y,并且存在 X 的一个真子集 X0,使得 X0→Y,则称 Y 对 X 部分函数依赖。比如学生基本信息表 R 中(学号,身份证号,姓名)当然学号属性取值是唯一的,在 R 关系中,(学号,身份证号)->(姓名),(学号)->(姓名),(身份证号)->(姓名);所以姓名部分函数依赖与(学号,身份证号);
+* **完全函数依赖(Full functional dependency)** :在一个关系中,若某个非主属性数据项依赖于全部关键字称之为完全函数依赖。比如学生基本信息表 R(学号,班级,姓名)假设不同的班级学号有相同的,班级内学号不能相同,在 R 关系中,(学号,班级)->(姓名),但是(学号)->(姓名)不成立,(班级)->(姓名)不成立,所以姓名完全函数依赖与(学号,班级);
+* **传递函数依赖** : 在关系模式 R(U)中,设 X,Y,Z 是 U 的不同的属性子集,如果 X 确定 Y、Y 确定 Z,且有 X 不包含 Y,Y 不确定 X,(X∪Y)∩Z=空集合,则称 Z 传递函数依赖(transitive functional dependency) 于 X。传递函数依赖会导致数据冗余和异常。传递函数依赖的 Y 和 Z 子集往往同属于某一个事物,因此可将其合并放到一个表中。比如在关系 R(学号 , 姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖。。
**3NF(第三范式)**
-3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。符合 3NF 要求的数据库设计,**基本**上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。比如在关系 R(学号 ,姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖,所以该表的设计,不符合 3NF 的要求。
+3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。符合 3NF 要求的数据库设计,**基本**上解决了数据冗余过大,插入异常,修改异常,删除异常的问题。比如在关系 R(学号 , 姓名, 系名,系主任)中,学号 → 系名,系名 → 系主任,所以存在非主属性系主任对于学号的传递函数依赖,所以该表的设计,不符合 3NF 的要求。
**总结**
-- 1NF:属性不可再分。
-- 2NF:1NF 的基础之上,消除了非主属性对于码的部分函数依赖。
-- 3NF:3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。
+* 1NF:属性不可再分。
+* 2NF:1NF 的基础之上,消除了非主属性对于码的部分函数依赖。
+* 3NF:3NF 在 2NF 的基础之上,消除了非主属性对于码的传递函数依赖 。
## 什么是存储过程?
@@ -77,15 +109,15 @@
阿里巴巴 Java 开发手册里要求禁止使用存储过程。
-
+
## drop、delete 与 truncate 区别?
### 用法不同
-- drop(丢弃数据): `drop table 表名` ,直接将表都删除掉,在删除表的时候使用。
-- truncate (清空数据) : `truncate table 表名` ,只删除表中的数据,再插入数据的时候自增长 id 又从 1 开始,在清空表中数据的时候使用。
-- delete(删除数据) : `delete from 表名 where 列名=值`,删除某一列的数据,如果不加 where 子句和`truncate table 表名`作用类似。
+* drop(丢弃数据): `drop table 表名` ,直接将表都删除掉,在删除表的时候使用。
+* truncate (清空数据) : `truncate table 表名` ,只删除表中的数据,再插入数据的时候自增长 id 又从 1 开始,在清空表中数据的时候使用。
+* delete(删除数据) : `delete from 表名 where 列名=值`,删除某一列的数据,如果不加 where 子句和`truncate table 表名`作用类似。
truncate 和不带 where 子句的 delete、以及 drop 都会删除表内的数据,但是 **truncate 和 delete 只删除数据不删除表的结构(定义),执行 drop 语句,此表的结构也会删除,也就是执行 drop 之后对应的表不复存在。**
@@ -95,8 +127,8 @@ truncate 和 drop 属于 DDL(数据定义语言)语句,操作立即生效,
**DML 语句和 DDL 语句区别:**
-- DML 是数据库操作语言(Data Manipulation Language)的缩写,是指对数据库中表记录的操作,主要包括表记录的插入(insert)、更新(update)、删除(delete)和查询(select),是开发人员日常使用最频繁的操作。
-- DDL (Data Definition Language)是数据定义语言的缩写,简单来说,就是对数据库内部的对象进行创建、删除、修改的操作语言。它和 DML 语言的最大区别是 DML 只是对表内部数据的操作,而不涉及到表的定义、结构的修改,更不会涉及到其他对象。DDL 语句更多的被数据库管理员(DBA)所使用,一般的开发人员很少使用。
+* DML 是数据库操作语言(Data Manipulation Language)的缩写,是指对数据库中表记录的操作,主要包括表记录的插入(insert)、更新(update)、删除(delete)和查询(select),是开发人员日常使用最频繁的操作。
+* DDL (Data Definition Language)是数据定义语言的缩写,简单来说,就是对数据库内部的对象进行创建、删除、修改的操作语言。它和 DML 语言的最大区别是 DML 只是对表内部数据的操作,而不涉及到表的定义、结构的修改,更不会涉及到其他对象。DDL 语句更多的被数据库管理员(DBA)所使用,一般的开发人员很少使用。
### 执行速度不同
@@ -113,6 +145,6 @@ truncate 和 drop 属于 DDL(数据定义语言)语句,操作立即生效,
## 参考
--
--
--
+*
+*
+*
diff --git "a/docs/database/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\346\261\240.md" "b/docs/database/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\346\261\240.md"
deleted file mode 100644
index 3e84dfc8efd..00000000000
--- "a/docs/database/\346\225\260\346\215\256\345\272\223\350\277\236\346\216\245\346\261\240.md"
+++ /dev/null
@@ -1,21 +0,0 @@
-- 公众号和Github待发文章:[数据库:数据库连接池原理详解与自定义连接池实现](https://www.fangzhipeng.com/javainterview/2019/07/15/mysql-connector-pool.html)
-- [基于JDBC的数据库连接池技术研究与应用](http://blog.itpub.net/9403012/viewspace-111794/)
-- [数据库连接池技术详解](https://juejin.im/post/5b7944c6e51d4538c86cf195)
-
-数据库连接本质就是一个 socket 的连接。数据库服务端还要维护一些缓存和用户权限信息之类的 所以占用了一些内存
-
-连接池是维护的数据库连接的缓存,以便将来需要对数据库的请求时可以重用这些连接。为每个用户打开和维护数据库连接,尤其是对动态数据库驱动的网站应用程序的请求,既昂贵又浪费资源。**在连接池中,创建连接后,将其放置在池中,并再次使用它,因此不必建立新的连接。如果使用了所有连接,则会建立一个新连接并将其添加到池中。**连接池还减少了用户必须等待建立与数据库的连接的时间。
-
-操作过数据库的朋友应该都知道数据库连接池这个概念,它几乎每天都在和我们打交道,但是你真的了解 **数据库连接池** 吗?
-
-### 没有数据库连接池之前
-
-我相信你一定听过这样一句话:**Java语言中,JDBC(Java DataBase Connection)是应用程序与数据库沟通的桥梁**。
-
-
-
-
-
-
-
-
diff --git "a/docs/system-design/distributed-system/api-gateway/api\347\275\221\345\205\263\345\205\245\351\227\250.md" b/docs/distributed-system/api-gateway.md
similarity index 99%
rename from "docs/system-design/distributed-system/api-gateway/api\347\275\221\345\205\263\345\205\245\351\227\250.md"
rename to docs/distributed-system/api-gateway.md
index 659ec202b1d..11bab874ff1 100644
--- "a/docs/system-design/distributed-system/api-gateway/api\347\275\221\345\205\263\345\205\245\351\227\250.md"
+++ b/docs/distributed-system/api-gateway.md
@@ -1,3 +1,6 @@
+
+# 网关
+
## 何为网关?为什么要网关?

@@ -101,3 +104,4 @@ Shenyu 通过插件扩展功能,插件是 ShenYu 的灵魂,并且插件也
- Github 地址: https://github.com/apache/incubator-shenyu
- 官网地址 : https://shenyu.apache.org/
+
diff --git "a/docs/system-design/distributed/\345\210\206\345\270\203\345\274\217ID.md" b/docs/distributed-system/distributed-id.md
similarity index 99%
rename from "docs/system-design/distributed/\345\210\206\345\270\203\345\274\217ID.md"
rename to docs/distributed-system/distributed-id.md
index 8c5c1fd3f1b..0ec45819e55 100644
--- "a/docs/system-design/distributed/\345\210\206\345\270\203\345\274\217ID.md"
+++ b/docs/distributed-system/distributed-id.md
@@ -1,4 +1,6 @@
-## 分布式 ID
+# 分布式 ID
+
+## 分布式 ID 介绍
### 何为 ID?
diff --git a/docs/distributed-system/distributed-transaction.md b/docs/distributed-system/distributed-transaction.md
new file mode 100644
index 00000000000..985fefbee09
--- /dev/null
+++ b/docs/distributed-system/distributed-transaction.md
@@ -0,0 +1,7 @@
+# 分布式事务
+
+这部分内容为我的星球专属,已经整理到了[《Java面试进阶指北 打造个人的技术竞争力》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7?# )中。
+
+欢迎加入我的星球,[一个纯 Java 面试交流圈子 !Ready!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) (点击链接了解星球详细信息,还有专属优惠款可以领取)。
+
+
diff --git a/docs/system-design/distributed-system/rpc/Dubbo.md b/docs/distributed-system/rpc/dubbo.md
similarity index 99%
rename from docs/system-design/distributed-system/rpc/Dubbo.md
rename to docs/distributed-system/rpc/dubbo.md
index 90f2fa4d2df..870cc45dc5f 100644
--- a/docs/system-design/distributed-system/rpc/Dubbo.md
+++ b/docs/distributed-system/rpc/dubbo.md
@@ -1,3 +1,5 @@
+# Dubbo知识点&面试题总结
+
这篇文章是我根据官方文档以及自己平时的使用情况,对 Dubbo 所做的一个总结。欢迎补充!
## RPC基础
diff --git "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md" b/docs/distributed-system/rpc/why-use-rpc.md
similarity index 98%
rename from "docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md"
rename to docs/distributed-system/rpc/why-use-rpc.md
index 2b755e51d27..a2fe5dbefa2 100644
--- "a/docs/system-design/distributed-system/rpc/\346\234\215\345\212\241\344\271\213\351\227\264\347\232\204\350\260\203\347\224\250\344\270\272\345\225\245\344\270\215\347\233\264\346\216\245\347\224\250HTTP\350\200\214\347\224\250RPC.md"
+++ b/docs/distributed-system/rpc/why-use-rpc.md
@@ -1,3 +1,5 @@
+# 服务之间的调用为啥不直接用 HTTP 而用 RPC?
+
## 什么是 RPC?RPC原理是什么?
### **什么是 RPC?**
diff --git a/docs/system-design/distributed-system/zookeeper/images/curator.png "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/curator.png"
similarity index 100%
rename from docs/system-design/distributed-system/zookeeper/images/curator.png
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/curator.png"
diff --git "a/docs/system-design/distributed-system/zookeeper/images/watche\346\234\272\345\210\266.png" "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/watche\346\234\272\345\210\266.png"
similarity index 100%
rename from "docs/system-design/distributed-system/zookeeper/images/watche\346\234\272\345\210\266.png"
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/watche\346\234\272\345\210\266.png"
diff --git a/docs/system-design/distributed-system/zookeeper/images/znode-structure.png "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/znode-structure.png"
similarity index 100%
rename from docs/system-design/distributed-system/zookeeper/images/znode-structure.png
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/znode-structure.png"
diff --git "a/docs/system-design/distributed-system/zookeeper/images/zookeeper\351\233\206\347\276\244.png" "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/zookeeper\351\233\206\347\276\244.png"
similarity index 100%
rename from "docs/system-design/distributed-system/zookeeper/images/zookeeper\351\233\206\347\276\244.png"
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/zookeeper\351\233\206\347\276\244.png"
diff --git "a/docs/system-design/distributed-system/zookeeper/images/zookeeper\351\233\206\347\276\244\344\270\255\347\232\204\350\247\222\350\211\262.png" "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/zookeeper\351\233\206\347\276\244\344\270\255\347\232\204\350\247\222\350\211\262.png"
similarity index 100%
rename from "docs/system-design/distributed-system/zookeeper/images/zookeeper\351\233\206\347\276\244\344\270\255\347\232\204\350\247\222\350\211\262.png"
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/zookeeper\351\233\206\347\276\244\344\270\255\347\232\204\350\247\222\350\211\262.png"
diff --git "a/docs/system-design/distributed-system/zookeeper/images/\350\277\236\346\216\245ZooKeeper\346\234\215\345\212\241.png" "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/\350\277\236\346\216\245ZooKeeper\346\234\215\345\212\241.png"
similarity index 100%
rename from "docs/system-design/distributed-system/zookeeper/images/\350\277\236\346\216\245ZooKeeper\346\234\215\345\212\241.png"
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/images/\350\277\236\346\216\245ZooKeeper\346\234\215\345\212\241.png"
diff --git a/docs/system-design/distributed-system/zookeeper/zookeeper-in-action.md "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-in-action.md"
similarity index 84%
rename from docs/system-design/distributed-system/zookeeper/zookeeper-in-action.md
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-in-action.md"
index 4b1f9eb9175..71dad09a4a2 100644
--- a/docs/system-design/distributed-system/zookeeper/zookeeper-in-action.md
+++ "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-in-action.md"
@@ -1,31 +1,4 @@
-
-
-
-
-
-- [1. 前言](#1-前言)
-- [2. ZooKeeper 安装和使用](#2-zookeeper-安装和使用)
- - [2.1. 使用Docker 安装 zookeeper](#21-使用docker-安装-zookeeper)
- - [2.2. 连接 ZooKeeper 服务](#22-连接-zookeeper-服务)
- - [2.3. 常用命令演示](#23-常用命令演示)
- - [2.3.1. 查看常用命令(help 命令)](#231-查看常用命令help-命令)
- - [2.3.2. 创建节点(create 命令)](#232-创建节点create-命令)
- - [2.3.3. 更新节点数据内容(set 命令)](#233-更新节点数据内容set-命令)
- - [2.3.4. 获取节点的数据(get 命令)](#234-获取节点的数据get-命令)
- - [2.3.5. 查看某个目录下的子节点(ls 命令)](#235-查看某个目录下的子节点ls-命令)
- - [2.3.6. 查看节点状态(stat 命令)](#236-查看节点状态stat-命令)
- - [2.3.7. 查看节点信息和状态(ls2 命令)](#237-查看节点信息和状态ls2-命令)
- - [2.3.8. 删除节点(delete 命令)](#238-删除节点delete-命令)
-- [3. ZooKeeper Java客户端 Curator简单使用](#3-zookeeper-java客户端-curator简单使用)
- - [3.1. 连接 ZooKeeper 客户端](#31-连接-zookeeper-客户端)
- - [3.2. 数据节点的增删改查](#32-数据节点的增删改查)
- - [3.2.1. 创建节点](#321-创建节点)
- - [3.2.2. 删除节点](#322-删除节点)
- - [3.2.3. 获取/更新节点数据内容](#323-获取更新节点数据内容)
- - [3.2.4. 获取某个节点的所有子节点路径](#324-获取某个节点的所有子节点路径)
-
-
-
+# ZooKeeper 实战
## 1. 前言
diff --git a/docs/system-design/distributed-system/zookeeper/zookeeper-intro.md "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-intro.md"
similarity index 93%
rename from docs/system-design/distributed-system/zookeeper/zookeeper-intro.md
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-intro.md"
index f9b94eb2bcd..3ead663c4b3 100644
--- a/docs/system-design/distributed-system/zookeeper/zookeeper-intro.md
+++ "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-intro.md"
@@ -1,34 +1,4 @@
-
-
-
-
-- [1. 前言](#1-前言)
-- [2. ZooKeeper 介绍](#2-zookeeper-介绍)
- - [2.1. ZooKeeper 由来](#21-zookeeper-由来)
- - [2.2. ZooKeeper 概览](#22-zookeeper-概览)
- - [2.3. ZooKeeper 特点](#23-zookeeper-特点)
- - [2.4. ZooKeeper 典型应用场景](#24-zookeeper-典型应用场景)
- - [2.5. 有哪些著名的开源项目用到了 ZooKeeper?](#25-有哪些著名的开源项目用到了-zookeeper)
-- [3. ZooKeeper 重要概念解读](#3-zookeeper-重要概念解读)
- - [3.1. Data model(数据模型)](#31-data-model数据模型)
- - [3.2. znode(数据节点)](#32-znode数据节点)
- - [3.2.1. znode 4 种类型](#321-znode-4种类型)
- - [3.2.2. znode 数据结构](#322-znode-数据结构)
- - [3.3. 版本(version)](#33-版本version)
- - [3.4. ACL(权限控制)](#34-acl权限控制)
- - [3.5. Watcher(事件监听器)](#35-watcher事件监听器)
- - [3.6. 会话(Session)](#36-会话session)
-- [4. ZooKeeper 集群](#4-zookeeper-集群)
- - [4.1. ZooKeeper 集群角色](#41-zookeeper-集群角色)
- - [4.2. ZooKeeper 集群中的服务器状态](#42-zookeeper-集群中的服务器状态)
- - [4.3. ZooKeeper 集群为啥最好奇数台?](#43-zookeeper-集群为啥最好奇数台)
-- [5. ZAB 协议和 Paxos 算法](#5-zab-协议和paxos-算法)
- - [5.1. ZAB 协议介绍](#51-zab-协议介绍)
- - [5.2. ZAB 协议两种基本的模式:崩溃恢复和消息广播](#52-zab-协议两种基本的模式崩溃恢复和消息广播)
-- [6. 总结](#6-总结)
-- [7. 参考](#7-参考)
-
-
+# ZooKeeper 相关概念总结(入门)
## 1. 前言
diff --git a/docs/system-design/distributed-system/zookeeper/zookeeper-plus.md "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-plus.md"
similarity index 96%
rename from docs/system-design/distributed-system/zookeeper/zookeeper-plus.md
rename to "docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-plus.md"
index ef37abb3c75..11f2ac5a1a8 100644
--- a/docs/system-design/distributed-system/zookeeper/zookeeper-plus.md
+++ "b/docs/distributed-system/\345\210\206\345\270\203\345\274\217\345\215\217\350\260\203/zookeeper/zookeeper-plus.md"
@@ -1,39 +1,6 @@
-[FrancisQ](https://juejin.im/user/5c33853851882525ea106810) 投稿。
-
-
-
-
-
-
-- [1. 好久不见](#1-好久不见)
-- [2. 什么是ZooKeeper](#2-什么是zookeeper)
-- [3. 一致性问题](#3-一致性问题)
-- [4. 一致性协议和算法](#4-一致性协议和算法)
- - [4.1. 2PC(两阶段提交)](#41-2pc两阶段提交)
- - [4.2. 3PC(三阶段提交)](#42-3pc三阶段提交)
- - [4.3. `Paxos` 算法](#43-paxos-算法)
- - [4.3.1. prepare 阶段](#431-prepare-阶段)
- - [4.3.2. accept 阶段](#432-accept-阶段)
- - [4.3.3. `paxos` 算法的死循环问题](#433-paxos-算法的死循环问题)
-- [5. 引出 `ZAB`](#5-引出-zab)
- - [5.1. `Zookeeper` 架构](#51-zookeeper-架构)
- - [5.2. `ZAB` 中的三个角色](#52-zab-中的三个角色)
- - [5.3. 消息广播模式](#53-消息广播模式)
- - [5.4. 崩溃恢复模式](#54-崩溃恢复模式)
-- [6. Zookeeper的几个理论知识](#6-zookeeper的几个理论知识)
- - [6.1. 数据模型](#61-数据模型)
- - [6.2. 会话](#62-会话)
- - [6.3. ACL](#63-acl)
- - [6.4. Watcher机制](#64-watcher机制)
-- [7. Zookeeper的几个典型应用场景](#7-zookeeper的几个典型应用场景)
- - [7.1. 选主](#71-选主)
- - [7.2. 分布式锁](#72-分布式锁)
- - [7.3. 命名服务](#73-命名服务)
- - [7.4. 集群管理和注册中心](#74-集群管理和注册中心)
-- [8. 总结](#8-总结)
-
-
+# ZooKeeper 相关概念总结(进阶)
+> [FrancisQ](https://juejin.im/user/5c33853851882525ea106810) 投稿。
## 1. 好久不见
diff --git "a/docs/system-design/distributed-system/CAP\347\220\206\350\256\272.md" "b/docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/cap&base\347\220\206\350\256\272.md"
similarity index 59%
rename from "docs/system-design/distributed-system/CAP\347\220\206\350\256\272.md"
rename to "docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/cap&base\347\220\206\350\256\272.md"
index 52710b947f6..3340409a799 100644
--- "a/docs/system-design/distributed-system/CAP\347\220\206\350\256\272.md"
+++ "b/docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/cap&base\347\220\206\350\256\272.md"
@@ -1,3 +1,6 @@
+
+# CAP & BASE理论
+
经历过技术面试的小伙伴想必对这个两个概念已经再熟悉不过了!
Guide哥当年参加面试的时候,不夸张地说,只要问到分布式相关的内容,面试官几乎是必定会问这两个分布式相关的理论。
@@ -85,3 +88,70 @@ CAP 理论的提出者布鲁尔在提出 CAP 猜想的时候,并没有详细
1. [CAP 定理简化](https://medium.com/@ravindraprasad/cap-theorem-simplified-28499a67eab4) (英文,有趣的案例)
2. [神一样的 CAP 理论被应用在何方](https://juejin.im/post/6844903936718012430) (中文,列举了很多实际的例子)
3. [请停止呼叫数据库 CP 或 AP ](https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html) (英文,带给你不一样的思考)
+
+## BASE 理论
+
+[BASE 理论](https://dl.acm.org/doi/10.1145/1394127.1394128)起源于 2008 年, 由eBay的架构师Dan Pritchett在ACM上发表。
+
+### 简介
+
+**BASE** 是 **Basically Available(基本可用)** 、**Soft-state(软状态)** 和 **Eventually Consistent(最终一致性)** 三个短语的缩写。BASE 理论是对 CAP 中一致性 C 和可用性 A 权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。
+
+### BASE 理论的核心思想
+
+即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
+
+> 也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。
+
+**BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充。**
+
+**为什么这样说呢?**
+
+CAP 理论这节我们也说过了:
+
+> 如果系统没有发生“分区”的话,节点间的网络连接通信正常的话,也就不存在 P 了。这个时候,我们就可以同时保证 C 和 A 了。因此,**如果系统发生“分区”,我们要考虑选择 CP 还是 AP。如果系统没有发生“分区”的话,我们要思考如何保证 CA 。**
+
+因此,AP 方案只是在系统发生分区的时候放弃一致性,而不是永远放弃一致性。在分区故障恢复后,系统应该达到最终一致性。这一点其实就是 BASE 理论延伸的地方。
+
+### BASE 理论三要素
+
+
+
+#### 1. 基本可用
+
+基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。
+
+**什么叫允许损失部分可用性呢?**
+
+- **响应时间上的损失**: 正常情况下,处理用户请求需要 0.5s 返回结果,但是由于系统出现故障,处理用户请求的时间变为 3 s。
+- **系统功能上的损失**:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的部分非核心功能无法使用。
+
+#### 2. 软状态
+
+软状态指允许系统中的数据存在中间状态(**CAP 理论中的数据不一致**),并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
+
+#### 3. 最终一致性
+
+最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
+
+> 分布式一致性的 3 种级别:
+>
+> 1. **强一致性** :系统写入了什么,读出来的就是什么。
+>
+> 2. **弱一致性** :不一定可以读取到最新写入的值,也不保证多少时间之后读取到的数据是最新的,只是会尽量保证某个时刻达到数据一致的状态。
+>
+> 3. **最终一致性** :弱一致性的升级版,系统会保证在一定时间内达到数据一致的状态。
+>
+> **业界比较推崇是最终一致性级别,但是某些对数据一致要求十分严格的场景比如银行转账还是要保证强一致性。**
+
+那实现最终一致性的具体方式是什么呢? [《分布式协议与算法实战》](http://gk.link/a/10rZM) 中是这样介绍:
+
+> - **读时修复** : 在读取数据时,检测数据的不一致,进行修复。比如 Cassandra 的 Read Repair 实现,具体来说,在向 Cassandra 系统查询数据的时候,如果检测到不同节点 的副本数据不一致,系统就自动修复数据。
+> - **写时修复** : 在写入数据,检测数据的不一致时,进行修复。比如 Cassandra 的 Hinted Handoff 实现。具体来说,Cassandra 集群的节点之间远程写数据的时候,如果写失败 就将数据缓存下来,然后定时重传,修复数据的不一致性。
+> - **异步修复** : 这个是最常用的方式,通过定时对账检测副本数据的一致性,并修复。
+
+比较推荐 **写时修复**,这种方式对性能消耗比较低。
+
+### 总结
+
+**ACID 是数据库事务完整性的理论,CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸。**
diff --git "a/docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/paxos&raft\347\256\227\346\263\225.md" "b/docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/paxos&raft\347\256\227\346\263\225.md"
new file mode 100644
index 00000000000..36bd77241dd
--- /dev/null
+++ "b/docs/distributed-system/\347\220\206\350\256\272&\347\256\227\346\263\225/paxos&raft\347\256\227\346\263\225.md"
@@ -0,0 +1,4 @@
+# Paxos 算法和 Raft 算法
+
+Paxos 算法诞生于 1990 年,这是一种解决分布式系统一致性的经典算法 。但是,由于 Paxos 算法非常难以理解和实现,不断有人尝试简化这一算法。到了2013 年才诞生了一个比 Paxos 算法更易理解和实现的分布式一致性算法—Raft 算法。
+
diff --git a/docs/high-availability/limit-request.md b/docs/high-availability/limit-request.md
new file mode 100644
index 00000000000..1c611e55a41
--- /dev/null
+++ b/docs/high-availability/limit-request.md
@@ -0,0 +1,203 @@
+# 限流
+
+## 何为限流?为什么要限流?
+
+针对软件系统来说,限流就是对请求的速率进行限制,避免瞬时的大量请求击垮软件系统。毕竟,软件系统的处理能力是有限的。如果说超过了其处理能力的范围,软件系统可能直接就挂掉了。
+
+限流可能会导致用户的请求无法被正确处理,不过,这往往也是权衡了软件系统的稳定性之后得到的最优解。
+
+现实生活中,处处都有限流的实际应用,就比如排队买票是为了避免大量用户涌入购票而导致售票员无法处理。
+
+
+
+## 常见限流算法
+
+简单介绍 4 种非常好理解并且容易实现的限流算法!
+
+> 图片来源于 InfoQ 的一篇文章[《分布式服务限流实战,已经为你排好坑了》](https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673)。
+
+### 固定窗口计数器算法
+
+固定窗口其实就是时间窗口。**固定窗口计数器算法** 规定了我们单位时间处理的请求数量。
+
+假如我们规定系统中某个接口 1 分钟只能访问 33 次的话,使用固定窗口计数器算法的实现思路如下:
+
+- 给定一个变量 `counter` 来记录当前接口处理的请求数量,初始值为 0(代表接口当前 1 分钟内还未处理请求)。
+- 1 分钟之内每处理一个请求之后就将 `counter+1` ,当 `counter=33` 之后(也就是说在这 1 分钟内接口已经被访问 33 次的话),后续的请求就会被全部拒绝。
+- 等到 1 分钟结束后,将 `counter` 重置 0,重新开始计数。
+
+**这种限流算法无法保证限流速率,因而无法保证突然激增的流量。**
+
+就比如说我们限制某个接口 1 分钟只能访问 1000 次,该接口的 QPS 为 500,前 55s 这个接口 1 个请求没有接收,后 1s 突然接收了 1000 个请求。然后,在当前场景下,这 1000 个请求在 1s 内是没办法被处理的,系统直接就被瞬时的大量请求给击垮了。
+
+
+
+### 滑动窗口计数器算法
+
+**滑动窗口计数器算法** 算的上是固定窗口计数器算法的升级版。
+
+滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:**它把时间以一定比例分片** 。
+
+例如我们的借口限流每分钟处理 60 个请求,我们可以把 1 分钟分为 60 个窗口。每隔 1 秒移动一次,每个窗口一秒只能处理 不大于 `60(请求数)/60(窗口数)` 的请求, 如果当前窗口的请求计数总和超过了限制的数量的话就不再处理其他请求。
+
+很显然, **当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。**
+
+
+
+### 漏桶算法
+
+我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为漏桶漏水。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
+
+如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了(和消息队列削峰/限流的思想是一样的)。
+
+
+
+### 令牌桶算法
+
+令牌桶算法也比较简单。和漏桶算法算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。我们根据限流大小,按照一定的速率往桶里添加令牌。如果桶装满了,就不能继续往里面继续添加令牌了。
+
+
+
+## 单机限流
+
+单机限流可以直接使用 Google Guava 自带的限流工具类 `RateLimiter` 。 `RateLimiter` 基于令牌桶算法,可以应对突发流量。
+
+> Guava 地址:https://github.com/google/guava
+
+除了最基本的令牌桶算法(平滑突发限流)实现之外,Guava 的`RateLimiter`还提供了 **平滑预热限流** 的算法实现。
+
+平滑突发限流就是按照指定的速率放令牌到桶里,而平滑预热限流会有一段预热时间,预热时间之内,速率会逐渐提升到配置的速率。
+
+我们下面通过两个简单的小例子来详细了解吧!
+
+我们直接在项目中引入 Guava 相关的依赖即可使用。
+
+```xml
+
+ com.google.guava
+ guava
+ 31.0.1-jre
+
+```
+
+下面是一个简单的 Guava 平滑突发限流的 Demo。
+
+```java
+import com.google.common.util.concurrent.RateLimiter;
+
+/**
+ * 微信搜 JavaGuide 回复"面试突击"即可免费领取个人原创的 Java 面试手册
+ *
+ * @author Guide哥
+ * @date 2021/10/08 19:12
+ **/
+public class RateLimiterDemo {
+
+ public static void main(String[] args) {
+ // 1s 放 5 个令牌到桶里也就是 0.2s 放 1个令牌到桶里
+ RateLimiter rateLimiter = RateLimiter.create(5);
+ for (int i = 0; i < 10; i++) {
+ double sleepingTime = rateLimiter.acquire(1);
+ System.out.printf("get 1 tokens: %ss%n", sleepingTime);
+ }
+ }
+}
+
+```
+
+输出:
+
+```bash
+get 1 tokens: 0.0s
+get 1 tokens: 0.188413s
+get 1 tokens: 0.197811s
+get 1 tokens: 0.198316s
+get 1 tokens: 0.19864s
+get 1 tokens: 0.199363s
+get 1 tokens: 0.193997s
+get 1 tokens: 0.199623s
+get 1 tokens: 0.199357s
+get 1 tokens: 0.195676s
+```
+
+下面是一个简单的 Guava 平滑预热限流的 Demo。
+
+```java
+import com.google.common.util.concurrent.RateLimiter;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 微信搜 JavaGuide 回复"面试突击"即可免费领取个人原创的 Java 面试手册
+ *
+ * @author Guide哥
+ * @date 2021/10/08 19:12
+ **/
+public class RateLimiterDemo {
+
+ public static void main(String[] args) {
+ // 1s 放 5 个令牌到桶里也就是 0.2s 放 1个令牌到桶里
+ // 预热时间为3s,也就说刚开始的 3s 内发牌速率会逐渐提升到 0.2s 放 1 个令牌到桶里
+ RateLimiter rateLimiter = RateLimiter.create(5, 3, TimeUnit.SECONDS);
+ for (int i = 0; i < 20; i++) {
+ double sleepingTime = rateLimiter.acquire(1);
+ System.out.printf("get 1 tokens: %sds%n", sleepingTime);
+ }
+ }
+}
+```
+
+输出:
+
+```bash
+get 1 tokens: 0.0s
+get 1 tokens: 0.561919s
+get 1 tokens: 0.516931s
+get 1 tokens: 0.463798s
+get 1 tokens: 0.41286s
+get 1 tokens: 0.356172s
+get 1 tokens: 0.300489s
+get 1 tokens: 0.252545s
+get 1 tokens: 0.203996s
+get 1 tokens: 0.198359s
+```
+
+另外,**Bucket4j** 是一个非常不错的基于令牌/漏桶算法的限流库。
+
+> Bucket4j 地址:https://github.com/vladimir-bukhtoyarov/bucket4j
+
+相对于,Guava 的限流工具类来说,Bucket4j 提供的限流功能更加全面。不仅支持单机限流和分布式限流,还可以集成监控,搭配 Prometheus 和 Grafana 使用。
+
+不过,毕竟 Guava 也只是一个功能全面的工具类库,其提供的开箱即用的限流功能在很多单机场景下还是比较实用的。
+
+Spring Cloud Gateway 中自带的单机限流的早期版本就是基于 Bucket4j 实现的。后来,替换成了 **Resilience4j**。
+
+Resilience4j 是一个轻量级的容错组件,其灵感来自于 Hystrix。自[Netflix 宣布不再积极开发 Hystrix](https://github.com/Netflix/Hystrix/commit/a7df971cbaddd8c5e976b3cc5f14013fe6ad00e6) 之后,Spring 官方和 Netflix 都更推荐使用 Resilience4j 来做限流熔断。
+
+> Resilience4j 地址: https://github.com/resilience4j/resilience4j
+
+一般情况下,为了保证系统的高可用,项目的限流和熔断都是要一起做的。
+
+Resilience4j 不仅提供限流,还提供了熔断、负载保护、自动重试等保障系统高可用开箱即用的功能。并且,Resilience4j 的生态也更好,很多网关都使用 Resilience4j 来做限流熔断的。
+
+因此,在绝大部分场景下 Resilience4j 或许会是更好的选择。如果是一些比较简单的限流场景的话,Guava 或者 Bucket4j 也是不错的选择。
+
+## 分布式限流
+
+分布式限流常见的方案:
+
+- **借助中间件架限流** :可以借助 Sentinel 或者使用 Redis 来自己实现对应的限流逻辑。
+- **网关层限流** :比较常用的一种方案,直接在网关层把限流给安排上了。不过,通常网关层限流通常也需要借助到中间件/框架。就比如 Spring Cloud Gateway 的分布式限流实现`RedisRateLimiter`就是基于 Redis+Lua 来实现的,再比如 Spring Cloud Gateway 还可以整合 Sentinel 来做限流。
+
+如果你要基于 Redis 来手动实现限流逻辑的话,建议配合 Lua 脚本来做。
+
+网上也有很多现成的脚本供你参考,就比如 Apache 网关项目 ShenYu 的 RateLimiter 限流插件就基于 Redis + Lua 实现了令牌桶算法/并发令牌桶算法、漏桶算法、滑动窗口算法。
+
+> ShenYu 地址: https://github.com/apache/incubator-shenyu
+
+
+
+## 相关阅读
+
+- 服务治理之轻量级熔断框架 Resilience4j :https://xie.infoq.cn/article/14786e571c1a4143ad1ef8f19
+- 超详细的 Guava RateLimiter 限流原理解析:https://cloud.tencent.com/developer/article/1408819
+- 实战 Spring Cloud Gateway 之限流篇 👍:https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html
diff --git "a/docs/high-availability/\346\200\247\350\203\275\346\265\213\350\257\225.md" "b/docs/high-availability/\346\200\247\350\203\275\346\265\213\350\257\225.md"
new file mode 100644
index 00000000000..dc3ff9ba749
--- /dev/null
+++ "b/docs/high-availability/\346\200\247\350\203\275\346\265\213\350\257\225.md"
@@ -0,0 +1,150 @@
+# 性能测试入门
+
+性能测试一般情况下都是由测试这个职位去做的,那还需要我们开发学这个干嘛呢?了解性能测试的指标、分类以及工具等知识有助于我们更好地去写出性能更好的程序,另外作为开发这个角色,如果你会性能测试的话,相信也会为你的履历加分不少。
+
+这篇文章是我会结合自己的实际经历以及在测试这里取的经所得,除此之外,我还借鉴了一些优秀书籍,希望对你有帮助。
+
+本文思维导图:
+
+
+
+## 一 不同角色看网站性能
+
+### 1.1 用户
+
+当用户打开一个网站的时候,最关注的是什么?当然是网站响应速度的快慢。比如我们点击了淘宝的主页,淘宝需要多久将首页的内容呈现在我的面前,我点击了提交订单按钮需要多久返回结果等等。
+
+所以,用户在体验我们系统的时候往往根据你的响应速度的快慢来评判你的网站的性能。
+
+### 1.2 开发人员
+
+用户与开发人员都关注速度,这个速度实际上就是我们的系统**处理用户请求的速度**。
+
+开发人员一般情况下很难直观的去评判自己网站的性能,我们往往会根据网站当前的架构以及基础设施情况给一个大概的值,比如:
+
+1. 项目架构是分布式的吗?
+2. 用到了缓存和消息队列没有?
+3. 高并发的业务有没有特殊处理?
+4. 数据库设计是否合理?
+5. 系统用到的算法是否还需要优化?
+6. 系统是否存在内存泄露的问题?
+7. 项目使用的 Redis 缓存多大?服务器性能如何?用的是机械硬盘还是固态硬盘?
+8. ......
+
+### 1.3 测试人员
+
+测试人员一般会根据性能测试工具来测试,然后一般会做出一个表格。这个表格可能会涵盖下面这些重要的内容:
+
+1. 响应时间;
+2. 请求成功率;
+3. 吞吐量;
+4. ......
+
+### 1.4 运维人员
+
+运维人员会倾向于根据基础设施和资源的利用率来判断网站的性能,比如我们的服务器资源使用是否合理、数据库资源是否存在滥用的情况、当然,这是传统的运维人员,现在 Devpos 火起来后,单纯干运维的很少了。我们这里暂且还保留有这个角色。
+
+## 二 性能测试需要注意的点
+
+几乎没有文章在讲性能测试的时候提到这个问题,大家都会讲如何去性能测试,有哪些性能测试指标这些东西。
+
+### 2.1 了解系统的业务场景
+
+**性能测试之前更需要你了解当前的系统的业务场景。** 对系统业务了解的不够深刻,我们很容易犯测试方向偏执的错误,从而导致我们忽略了对系统某些更需要性能测试的地方进行测试。比如我们的系统可以为用户提供发送邮件的功能,用户配置成功邮箱后只需输入相应的邮箱之后就能发送,系统每天大概能处理上万次发邮件的请求。很多人看到这个可能就直接开始使用相关工具测试邮箱发送接口,但是,发送邮件这个场景可能不是当前系统的性能瓶颈,这么多人用我们的系统发邮件, 还可能有很多人一起发邮件,单单这个场景就这么人用,那用户管理可能才是性能瓶颈吧!
+
+### 2.2 历史数据非常有用
+
+当前系统所留下的历史数据非常重要,一般情况下,我们可以通过相应的些历史数据初步判定这个系统哪些接口调用的比较多、哪些 service 承受的压力最大,这样的话,我们就可以针对这些地方进行更细致的性能测试与分析。
+
+另外,这些地方也就像这个系统的一个短板一样,优化好了这些地方会为我们的系统带来质的提升。
+
+### 三 性能测试的指标
+
+### 3.1 响应时间
+
+**响应时间就是用户发出请求到用户收到系统处理结果所需要的时间。** 重要吗?实在太重要!
+
+比较出名的 2-5-8 原则是这样描述的:通常来说,2到5秒,页面体验会比较好,5到8秒还可以接受,8秒以上基本就很难接受了。另外,据统计当网站慢一秒就会流失十分之一的客户。
+
+但是,在某些场景下我们也并不需要太看重 2-5-8 原则 ,比如我觉得系统导出导入大数据量这种就不需要,系统生成系统报告这种也不需要。
+
+### 3.2 并发数
+
+**并发数是系统能同时处理请求的数目即同时提交请求的用户数目。**
+
+不得不说,高并发是现在后端架构中非常非常火热的一个词了,这个与当前的互联网环境以及中国整体的互联网用户量都有很大关系。一般情况下,你的系统并发量越大,说明你的产品做的就越大。但是,并不是每个系统都需要达到像淘宝、12306 这种亿级并发量的。
+
+### 3.3 吞吐量
+
+吞吐量指的是系统单位时间内系统处理的请求数量。衡量吞吐量有几个重要的参数:QPS(TPS)、并发数、响应时间。
+
+1. QPS(Query Per Second):服务器每秒可以执行的查询次数;
+2. TPS(Transaction Per Second):服务器每秒处理的事务数(这里的一个事务可以理解为客户发出请求到收到服务器的过程);
+3. 并发数;系统能同时处理请求的数目即同时提交请求的用户数目。
+4. 响应时间: 一般取多次请求的平均响应时间
+
+理清他们的概念,就很容易搞清楚他们之间的关系了。
+
+- **QPS(TPS)** = 并发数/平均响应时间
+- **并发数** = QPS\平均响应时间
+
+书中是这样描述 QPS 和 TPS 的区别的。
+
+> QPS vs TPS:QPS 基本类似于 TPS,但是不同的是,对于一个页面的一次访问,形成一个TPS;但一次页面请求,可能产生多次对服务器的请求,服务器对这些请求,就可计入“QPS”之中。如,访问一个页面会请求服务器2次,一次访问,产生一个“T”,产生2个“Q”。
+
+### 3.4 性能计数器
+
+**性能计数器是描述服务器或者操作系统的一些数据指标如内存使用、CPU使用、磁盘与网络I/O等情况。**
+
+### 四 几种常见的性能测试
+
+### 性能测试
+
+性能测试方法是通过测试工具模拟用户请求系统,目的主要是为了测试系统的性能是否满足要求。通俗地说,这种方法就是要在特定的运行条件下验证系统的能力状态。
+
+性能测试是你在对系统性能已经有了解的前提之后进行的,并且有明确的性能指标。
+
+### 负载测试
+
+对被测试的系统继续加大请求压力,直到服务器的某个资源已经达到饱和了,比如系统的缓存已经不够用了或者系统的响应时间已经不满足要求了。
+
+负载测试说白点就是测试系统的上线。
+
+### 压力测试
+
+不去管系统资源的使用情况,对系统继续加大请求压力,直到服务器崩溃无法再继续提供服务。
+
+### 稳定性测试
+
+模拟真实场景,给系统一定压力,看看业务是否能稳定运行。
+
+## 五 常用性能测试工具
+
+这里就不多扩展了,有时间的话会单独拎一个熟悉的说一下。
+
+### 5.1 后端常用
+
+没记错的话,除了 LoadRunner 其他几款性能测试工具都是开源免费的。
+
+1. Jmeter :Apache JMeter 是 JAVA 开发的性能测试工具。
+2. LoadRunner:一款商业的性能测试工具。
+3. Galtling :一款基于Scala 开发的高性能服务器性能测试工具。
+4. ab :全称为 Apache Bench 。Apache 旗下的一款测试工具,非常实用。
+
+### 5.2 前端常用
+
+1. Fiddler:抓包工具,它可以修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是Web 调试的利器。
+2. HttpWatch: 可用于录制HTTP请求信息的工具。
+
+## 六 常见的性能优化策略
+
+性能优化之前我们需要对请求经历的各个环节进行分析,排查出可能出现性能瓶颈的地方,定位问题。
+
+下面是一些性能优化时,我经常拿来自问的一些问题:
+
+1. 系统是否需要缓存?
+2. 系统架构本身是不是就有问题?
+3. 系统是否存在死锁的地方?
+4. 系统是否存在内存泄漏?(Java 的自动回收内存虽然很方便,但是,有时候代码写的不好真的会造成内存泄漏)
+5. 数据库索引使用是否合理?
+6. ......
\ No newline at end of file
diff --git "a/docs/high-availability/\347\201\276\345\244\207\350\256\276\350\256\241\345\222\214\345\274\202\345\234\260\345\244\232\346\264\273.md" "b/docs/high-availability/\347\201\276\345\244\207\350\256\276\350\256\241\345\222\214\345\274\202\345\234\260\345\244\232\346\264\273.md"
new file mode 100644
index 00000000000..18756b69127
--- /dev/null
+++ "b/docs/high-availability/\347\201\276\345\244\207\350\256\276\350\256\241\345\222\214\345\274\202\345\234\260\345\244\232\346\264\273.md"
@@ -0,0 +1,14 @@
+# 灾备设计&异地多活
+
+**灾备** = 容灾+备份。
+
+- **备份** : 将系统所产生的所有重要数据多备份几份。
+- **容灾** : 在异地建立两个完全相同的系统。当某个地方的系统突然挂掉,整个应用系统可以切换到另一个,这样系统就可以正常提供服务了。
+
+**异地多活** 描述的是将服务部署在异地并且服务同时对外提供服务。和传统的灾备设计的最主要区别在于“多活”,即所有站点都是同时在对外提供服务的。异地多活是为了应对突发状况比如火灾、地震等自然或者人为灾害。
+
+相关阅读:
+
+- [搞懂异地多活,看这篇就够了](https://mp.weixin.qq.com/s/T6mMDdtTfBuIiEowCpqu6Q)
+- [四步构建异地多活](https://mp.weixin.qq.com/s/hMD-IS__4JE5_nQhYPYSTg)
+- [《从零开始学架构》— 28 | 业务高可用的保障:异地多活架构](http://gk.link/a/10pKZ)
\ No newline at end of file
diff --git "a/docs/high-availability/\350\266\205\346\227\266\345\222\214\351\207\215\350\257\225\346\234\272\345\210\266.md" "b/docs/high-availability/\350\266\205\346\227\266\345\222\214\351\207\215\350\257\225\346\234\272\345\210\266.md"
new file mode 100644
index 00000000000..ee4f90f2056
--- /dev/null
+++ "b/docs/high-availability/\350\266\205\346\227\266\345\222\214\351\207\215\350\257\225\346\234\272\345\210\266.md"
@@ -0,0 +1,5 @@
+# 超时&重试机制
+
+**一旦用户的请求超过某个时间得不到响应就结束此次请求并抛出异常。** 如果不进行超时设置可能会导致请求响应速度慢,甚至导致请求堆积进而让系统无法再处理请求。
+
+另外,重试的次数一般设为 3 次,再多次的重试没有好处,反而会加重服务器压力(部分场景使用失败重试机制会不太适合)。
\ No newline at end of file
diff --git "a/docs/high-availability/\351\231\215\347\272\247&\347\206\224\346\226\255.md" "b/docs/high-availability/\351\231\215\347\272\247&\347\206\224\346\226\255.md"
new file mode 100644
index 00000000000..2ff7b922893
--- /dev/null
+++ "b/docs/high-availability/\351\231\215\347\272\247&\347\206\224\346\226\255.md"
@@ -0,0 +1,9 @@
+# 降级&熔断
+
+降级是从系统功能优先级的角度考虑如何应对系统故障。
+
+服务降级指的是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
+
+熔断和降级是两个比较容易混淆的概念,两者的含义并不相同。
+
+降级的目的在于应对系统自身的故障,而熔断的目的在于应对当前系统依赖的外部系统或者第三方系统的故障。
\ No newline at end of file
diff --git "a/docs/high-availability/\351\233\206\347\276\244.md" "b/docs/high-availability/\351\233\206\347\276\244.md"
new file mode 100644
index 00000000000..5da34020f32
--- /dev/null
+++ "b/docs/high-availability/\351\233\206\347\276\244.md"
@@ -0,0 +1,3 @@
+# 集群
+
+相同的服务部署多份,避免单点故障。
\ No newline at end of file
diff --git "a/docs/system-design/high-availability/\345\246\202\344\275\225\350\256\276\350\256\241\344\270\200\344\270\252\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\246\201\350\200\203\350\231\221\345\223\252\344\272\233\345\234\260\346\226\271.md" "b/docs/high-availability/\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\256\276\350\256\241.md"
similarity index 97%
rename from "docs/system-design/high-availability/\345\246\202\344\275\225\350\256\276\350\256\241\344\270\200\344\270\252\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\246\201\350\200\203\350\231\221\345\223\252\344\272\233\345\234\260\346\226\271.md"
rename to "docs/high-availability/\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\256\276\350\256\241.md"
index 191609f2812..e336f676251 100644
--- "a/docs/system-design/high-availability/\345\246\202\344\275\225\350\256\276\350\256\241\344\270\200\344\270\252\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\246\201\350\200\203\350\231\221\345\223\252\344\272\233\345\234\260\346\226\271.md"
+++ "b/docs/high-availability/\351\253\230\345\217\257\347\224\250\347\263\273\347\273\237\350\256\276\350\256\241.md"
@@ -1,3 +1,5 @@
+# 高可用系统设计
+
一篇短小的文章,面试经常遇到的这个问题。本文主要包括下面这些内容:
1. 高可用的定义
@@ -66,7 +68,3 @@
4. **灰度发布:** 将服务器集群分成若干部分,每天只发布一部分机器,观察运行稳定没有故障,第二天继续发布一部分机器,持续几天才把整个集群全部发布完毕,期间如果发现问题,只需要回滚已发布的一部分服务器即可
5. **定期检查/更换硬件:** 如果不是购买的云服务的话,定期还是需要对硬件进行一波检查的,对于一些需要更换或者升级的硬件,要及时更换或者升级。
6. .....(想起来再补充!也欢迎各位欢迎补充!)
-
-## 总结
-
-
diff --git "a/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/docs/high-performance/message-queue/kafka\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 99%
rename from "docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
rename to "docs/high-performance/message-queue/kafka\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index 4077bd95898..8cea44f2225 100644
--- "a/docs/system-design/distributed-system/message-queue/Kafka\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
+++ "b/docs/high-performance/message-queue/kafka\347\237\245\350\257\206\347\202\271&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,8 +1,5 @@
-------
-
-
-## Kafka面试题总结
+# Kafka知识点&面试题总结
### Kafka 是什么?主要应用场景有哪些?
diff --git a/docs/system-design/distributed-system/message-queue/message-queue.md b/docs/high-performance/message-queue/message-queue.md
similarity index 97%
rename from docs/system-design/distributed-system/message-queue/message-queue.md
rename to docs/high-performance/message-queue/message-queue.md
index 1a79514ea33..161bd5a021d 100644
--- a/docs/system-design/distributed-system/message-queue/message-queue.md
+++ b/docs/high-performance/message-queue/message-queue.md
@@ -1,4 +1,4 @@
-# 消息队列其实很简单
+# 消息队列知识点&面试题总结
“RabbitMQ?”“Kafka?”“RocketMQ?”...在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。
@@ -76,13 +76,13 @@ JMS(JAVA Message Service,java 消息服务)是 java 的消息服务,JMS
**① 点到点(P2P)模型**
-
+
使用**队列(Queue)**作为消息通信载体;满足**生产者与消费者模式**,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送 100 条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)
**② 发布/订阅(Pub/Sub)模型**
-
+
发布订阅模型(Pub/Sub) 使用**主题(Topic)**作为消息通信载体,类似于**广播模式**;发布者发布一条消息,该消息通过主题传递给所有的订阅者,**在一条消息广播之后才订阅的用户则是收不到该条消息的**。
diff --git "a/docs/system-design/distributed-system/message-queue/RabbitMQ\345\205\245\351\227\250\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md" b/docs/high-performance/message-queue/rabbitmq-intro.md
similarity index 93%
rename from "docs/system-design/distributed-system/message-queue/RabbitMQ\345\205\245\351\227\250\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md"
rename to docs/high-performance/message-queue/rabbitmq-intro.md
index 38444481507..d676114c8e6 100644
--- "a/docs/system-design/distributed-system/message-queue/RabbitMQ\345\205\245\351\227\250\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md"
+++ b/docs/high-performance/message-queue/rabbitmq-intro.md
@@ -1,25 +1,5 @@
-
-
-- [一文搞懂 RabbitMQ 的重要概念以及安装](#一文搞懂-rabbitmq-的重要概念以及安装)
- - [一 RabbitMQ 介绍](#一-rabbitmq-介绍)
- - [1.1 RabbitMQ 简介](#11-rabbitmq-简介)
- - [1.2 RabbitMQ 核心概念](#12-rabbitmq-核心概念)
- - [1.2.1 Producer(生产者) 和 Consumer(消费者)](#121-producer生产者-和-consumer消费者)
- - [1.2.2 Exchange(交换器)](#122-exchange交换器)
- - [1.2.3 Queue(消息队列)](#123-queue消息队列)
- - [1.2.4 Broker(消息中间件的服务节点)](#124-broker消息中间件的服务节点)
- - [1.2.5 Exchange Types(交换器类型)](#125-exchange-types交换器类型)
- - [① fanout](#-fanout)
- - [② direct](#-direct)
- - [③ topic](#-topic)
- - [④ headers(不推荐)](#-headers不推荐)
- - [二 安装 RabbitMq](#二-安装-rabbitmq)
- - [2.1 安装 erlang](#21-安装-erlang)
- - [2.2 安装 RabbitMQ](#22-安装-rabbitmq)
-
-
-
-# 一文搞懂 RabbitMQ 的重要概念以及安装
+
+# RabbitMQ 入门总结
## 一 RabbitMQ 介绍
diff --git a/docs/system-design/distributed-system/message-queue/RocketMQ.md b/docs/high-performance/message-queue/rocketmq-intro.md
similarity index 99%
rename from docs/system-design/distributed-system/message-queue/RocketMQ.md
rename to docs/high-performance/message-queue/rocketmq-intro.md
index 31e36316769..2fbacfabec4 100644
--- a/docs/system-design/distributed-system/message-queue/RocketMQ.md
+++ b/docs/high-performance/message-queue/rocketmq-intro.md
@@ -1,3 +1,5 @@
+# RocketMQ入门总结
+
> 文章很长,点赞再看,养成好习惯😋😋😋
>
> [本文由 FrancisQ 老哥投稿!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485969&idx=1&sn=6bd53abde30d42a778d5a35ec104428c&chksm=cea245daf9d5cccce631f93115f0c2c4a7634e55f5bef9009fd03f5a0ffa55b745b5ef4f0530&token=294077121&lang=zh_CN#rd)
diff --git a/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md b/docs/high-performance/message-queue/rocketmq-questions.md
similarity index 82%
rename from docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md
rename to docs/high-performance/message-queue/rocketmq-questions.md
index 2a4d89acd2c..68957689c11 100644
--- a/docs/system-design/distributed-system/message-queue/RocketMQ-Questions.md
+++ b/docs/high-performance/message-queue/rocketmq-questions.md
@@ -1,25 +1,8 @@
+# RocketMQ常见问题
+
本文来自读者 [PR](https://github.com/Snailclimb/JavaGuide/pull/291)。
-
-
-- [1 单机版消息中心](#1-%E5%8D%95%E6%9C%BA%E7%89%88%E6%B6%88%E6%81%AF%E4%B8%AD%E5%BF%83)
-- [2 分布式消息中心](#2-%E5%88%86%E5%B8%83%E5%BC%8F%E6%B6%88%E6%81%AF%E4%B8%AD%E5%BF%83)
- - [2.1 问题与解决](#21-%E9%97%AE%E9%A2%98%E4%B8%8E%E8%A7%A3%E5%86%B3)
- - [2.1.1 消息丢失的问题](#211-%E6%B6%88%E6%81%AF%E4%B8%A2%E5%A4%B1%E7%9A%84%E9%97%AE%E9%A2%98)
- - [2.1.2 同步落盘怎么才能快](#212-%E5%90%8C%E6%AD%A5%E8%90%BD%E7%9B%98%E6%80%8E%E4%B9%88%E6%89%8D%E8%83%BD%E5%BF%AB)
- - [2.1.3 消息堆积的问题](#213-%E6%B6%88%E6%81%AF%E5%A0%86%E7%A7%AF%E7%9A%84%E9%97%AE%E9%A2%98)
- - [2.1.4 定时消息的实现](#214-%E5%AE%9A%E6%97%B6%E6%B6%88%E6%81%AF%E7%9A%84%E5%AE%9E%E7%8E%B0)
- - [2.1.5 顺序消息的实现](#215-%E9%A1%BA%E5%BA%8F%E6%B6%88%E6%81%AF%E7%9A%84%E5%AE%9E%E7%8E%B0)
- - [2.1.6 分布式消息的实现](#216-%E5%88%86%E5%B8%83%E5%BC%8F%E6%B6%88%E6%81%AF%E7%9A%84%E5%AE%9E%E7%8E%B0)
- - [2.1.7 消息的 push 实现](#217-%E6%B6%88%E6%81%AF%E7%9A%84-push-%E5%AE%9E%E7%8E%B0)
- - [2.1.8 消息重复发送的避免](#218-%E6%B6%88%E6%81%AF%E9%87%8D%E5%A4%8D%E5%8F%91%E9%80%81%E7%9A%84%E9%81%BF%E5%85%8D)
- - [2.1.9 广播消费与集群消费](#219-%E5%B9%BF%E6%92%AD%E6%B6%88%E8%B4%B9%E4%B8%8E%E9%9B%86%E7%BE%A4%E6%B6%88%E8%B4%B9)
- - [2.1.10 RocketMQ 不使用 ZooKeeper 作为注册中心的原因,以及自制的 NameServer 优缺点?](#2110-rocketmq-%E4%B8%8D%E4%BD%BF%E7%94%A8-zookeeper-%E4%BD%9C%E4%B8%BA%E6%B3%A8%E5%86%8C%E4%B8%AD%E5%BF%83%E7%9A%84%E5%8E%9F%E5%9B%A0%E4%BB%A5%E5%8F%8A%E8%87%AA%E5%88%B6%E7%9A%84-nameserver-%E4%BC%98%E7%BC%BA%E7%82%B9)
- - [2.1.11 其它](#2111-%E5%85%B6%E5%AE%83)
-- [3 参考](#3-%E5%8F%82%E8%80%83)
-
-
-
-# 1 单机版消息中心
+
+## 1 单机版消息中心
一个消息中心,最基本的需要支持多生产者、多消费者,例如下:
@@ -127,40 +110,40 @@ class Broker {
4. 没有使用多个队列(即多个 LinkedBlockingQueue),RocketMQ 的顺序消息是通过生产者和消费者同时使用同一个 MessageQueue 来实现,但是如果我们只有一个 MessageQueue,那我们天然就支持顺序消息
5. 没有使用 MappedByteBuffer 来实现文件映射从而使消息数据落盘非常的快(实际 RocketMQ 使用的是 FileChannel+DirectBuffer)
-# 2 分布式消息中心
+## 2 分布式消息中心
-## 2.1 问题与解决
+### 2.1 问题与解决
-### 2.1.1 消息丢失的问题
+#### 2.1.1 消息丢失的问题
1. 当你系统需要保证百分百消息不丢失,你可以使用生产者每发送一个消息,Broker 同步返回一个消息发送成功的反馈消息
2. 即每发送一个消息,同步落盘后才返回生产者消息发送成功,这样只要生产者得到了消息发送生成的返回,事后除了硬盘损坏,都可以保证不会消息丢失
3. 但是这同时引入了一个问题,同步落盘怎么才能快?
-### 2.1.2 同步落盘怎么才能快
+#### 2.1.2 同步落盘怎么才能快
1. 使用 FileChannel + DirectBuffer 池,使用堆外内存,加快内存拷贝
2. 使用数据和索引分离,当消息需要写入时,使用 commitlog 文件顺序写,当需要定位某个消息时,查询index 文件来定位,从而减少文件IO随机读写的性能损耗
-### 2.1.3 消息堆积的问题
+#### 2.1.3 消息堆积的问题
1. 后台定时任务每隔72小时,删除旧的没有使用过的消息信息
2. 根据不同的业务实现不同的丢弃任务,具体参考线程池的 AbortPolicy,例如FIFO/LRU等(RocketMQ没有此策略)
3. 消息定时转移,或者对某些重要的 TAG 型(支付型)消息真正落库
-### 2.1.4 定时消息的实现
+#### 2.1.4 定时消息的实现
1. 实际 RocketMQ 没有实现任意精度的定时消息,它只支持某些特定的时间精度的定时消息
2. 实现定时消息的原理是:创建特定时间精度的 MessageQueue,例如生产者需要定时1s之后被消费者消费,你只需要将此消息发送到特定的 Topic,例如:MessageQueue-1 表示这个 MessageQueue 里面的消息都会延迟一秒被消费,然后 Broker 会在 1s 后发送到消费者消费此消息,使用 newSingleThreadScheduledExecutor 实现
-### 2.1.5 顺序消息的实现
+#### 2.1.5 顺序消息的实现
1. 与定时消息同原理,生产者生产消息时指定特定的 MessageQueue ,消费者消费消息时,消费特定的 MessageQueue,其实单机版的消息中心在一个 MessageQueue 就天然支持了顺序消息
2. 注意:同一个 MessageQueue 保证里面的消息是顺序消费的前提是:消费者是串行的消费该 MessageQueue,因为就算 MessageQueue 是顺序的,但是当并行消费时,还是会有顺序问题,但是串行消费也同时引入了两个问题:
>1. 引入锁来实现串行
>2. 前一个消费阻塞时后面都会被阻塞
-### 2.1.6 分布式消息的实现
+#### 2.1.6 分布式消息的实现
1. 需要前置知识:2PC
2. RocketMQ4.3 起支持,原理为2PC,即两阶段提交,prepared->commit/rollback
@@ -168,31 +151,31 @@ class Broker {
>注意,就算是事务消息最后回滚了也不会物理删除,只会逻辑删除该消息
-### 2.1.7 消息的 push 实现
+#### 2.1.7 消息的 push 实现
1. 注意,RocketMQ 已经说了自己会有低延迟问题,其中就包括这个消息的 push 延迟问题
2. 因为这并不是真正的将消息主动的推送到消费者,而是 Broker 定时任务每5s将消息推送到消费者
3. pull模式需要我们手动调用consumer拉消息,而push模式则只需要我们提供一个listener即可实现对消息的监听,而实际上,RocketMQ的push模式是基于pull模式实现的,它没有实现真正的push。
4. push方式里,consumer把轮询过程封装了,并注册MessageListener监听器,取到消息后,唤醒MessageListener的consumeMessage()来消费,对用户而言,感觉消息是被推送过来的。
-### 2.1.8 消息重复发送的避免
+#### 2.1.8 消息重复发送的避免
1. RocketMQ 会出现消息重复发送的问题,因为在网络延迟的情况下,这种问题不可避免的发生,如果非要实现消息不可重复发送,那基本太难,因为网络环境无法预知,还会使程序复杂度加大,因此默认允许消息重复发送
2. RocketMQ 让使用者在消费者端去解决该问题,即需要消费者端在消费消息时支持幂等性的去消费消息
3. 最简单的解决方案是每条消费记录有个消费状态字段,根据这个消费状态字段来判断是否消费或者使用一个集中式的表,来存储所有消息的消费状态,从而避免重复消费
4. 具体实现可以查询关于消息幂等消费的解决方案
-### 2.1.9 广播消费与集群消费
+#### 2.1.9 广播消费与集群消费
1. 消息消费区别:广播消费,订阅该 Topic 的消息者们都会消费**每个**消息。集群消费,订阅该 Topic 的消息者们只会有一个去消费**某个**消息
2. 消息落盘区别:具体表现在消息消费进度的保存上。广播消费,由于每个消费者都独立的去消费每个消息,因此每个消费者各自保存自己的消息消费进度。而集群消费下,订阅了某个 Topic,而旗下又有多个 MessageQueue,每个消费者都可能会去消费不同的 MessageQueue,因此总体的消费进度保存在 Broker 上集中的管理
-### 2.1.10 RocketMQ 不使用 ZooKeeper 作为注册中心的原因,以及自制的 NameServer 优缺点?
+#### 2.1.10 RocketMQ 不使用 ZooKeeper 作为注册中心的原因,以及自制的 NameServer 优缺点?
1. ZooKeeper 作为支持顺序一致性的中间件,在某些情况下,它为了满足一致性,会丢失一定时间内的可用性,RocketMQ 需要注册中心只是为了发现组件地址,在某些情况下,RocketMQ 的注册中心可以出现数据不一致性,这同时也是 NameServer 的缺点,因为 NameServer 集群间互不通信,它们之间的注册信息可能会不一致
2. 另外,当有新的服务器加入时,NameServer 并不会立马通知到 Producer,而是由 Producer 定时去请求 NameServer 获取最新的 Broker/Consumer 信息(这种情况是通过 Producer 发送消息时,负载均衡解决)
-### 2.1.11 其它
+#### 2.1.11 其它
![][1]
@@ -203,7 +186,7 @@ class Broker {
4. Broker 同步双写和异步双写中 Master 和 Slave 的交互
5. Broker 在 4.5.0 版本更新中引入了基于 Raft 协议的多副本选举,之前这是商业版才有的特性 [ISSUE-1046][2]
-# 3 参考
+## 3 参考
1. 《RocketMQ技术内幕》:https://blog.csdn.net/prestigeding/article/details/85233529
2. 关于 RocketMQ 对 MappedByteBuffer 的一点优化:https://lishoubo.github.io/2017/09/27/MappedByteBuffer%E7%9A%84%E4%B8%80%E7%82%B9%E4%BC%98%E5%8C%96/
diff --git "a/docs/system-design/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md" "b/docs/high-performance/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md"
similarity index 100%
rename from "docs/system-design/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md"
rename to "docs/high-performance/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md"
index f2c0a8e3baa..4937d9fd7f3 100644
--- "a/docs/system-design/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md"
+++ "b/docs/high-performance/\350\257\273\345\206\231\345\210\206\347\246\273&\345\210\206\345\272\223\345\210\206\350\241\250.md"
@@ -1,3 +1,5 @@
+# 读写分离&分库分表
+
大家好呀!今天和小伙伴们聊聊读写分离以及分库分表。
相信很多小伙伴们对于这两个概念已经比较熟悉了,这篇文章全程都是大白话的形式,希望能够给你带来不一样的感受。
@@ -8,8 +10,6 @@
_个人能力有限。如果文章有任何需要补充/完善/修改的地方,欢迎在评论区指出,共同进步!_
-# 读写分离&分库分表
-
## 读写分离
### 何为读写分离?
diff --git "a/docs/high-performance/\350\264\237\350\275\275\345\235\207\350\241\241.md" "b/docs/high-performance/\350\264\237\350\275\275\345\235\207\350\241\241.md"
new file mode 100644
index 00000000000..a9d98b2cea5
--- /dev/null
+++ "b/docs/high-performance/\350\264\237\350\275\275\345\235\207\350\241\241.md"
@@ -0,0 +1,13 @@
+# 负载均衡
+
+负载均衡系统通常用于将任务比如用户请求处理分配到多个服务器处理以提高网站、应用或者数据库的性能和可靠性。
+
+常见的负载均衡系统包括 3 种:
+
+1. **DNS 负载均衡** :一般用来实现地理级别的均衡。
+2. **硬件负载均衡** : 通过单独的硬件设备比如 F5 来实现负载均衡功能(硬件的价格一般很贵)。
+3. **软件负载均衡** :通过负载均衡软件比如 Nginx 来实现负载均衡功能。
+
+## 推荐阅读
+
+- [《凤凰架构》-负载均衡](http://icyfenix.cn/architect-perspective/general-architecture/diversion-system/load-balancing.html)
diff --git a/docs/idea-tutorial/idea-plugins/camel-case.md b/docs/idea-tutorial/idea-plugins/camel-case.md
new file mode 100644
index 00000000000..5456378f4b2
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/camel-case.md
@@ -0,0 +1,27 @@
+---
+title: Camel Case:命名之间快速切换
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+非常有用!这个插件可以实现包含6种常见命名格式之间的切换。并且,你还可以对转换格式进行相关配置(转换格式),如下图所示:
+
+
+
+有了这个插件之后,你只需要使用快捷键 `shift+option+u(mac)` / `shift+alt+u` 对准你要修改的变量或者方法名字,就能实现在多种格式之间切换了,如下图所示:
+
+
+
+如果你突然忘记快捷键的话,可以直接在IDEA的菜单栏的 Edit 部分找到。
+
+
+
+使用这个插件对开发效率提升高吗?拿我之前项目组的情况举个例子:
+
+我之前有一个项目组的测试名字是驼峰这种形式: `ShouldReturnTicketWhenRobotSaveBagGiven1LockersWith2FreeSpace` 。但是,使用驼峰形式命名测试方法的名字不太明显,一般建议用下划线_的形式: `should_return_ticket_when_robot_save_bag_given_1_lockers_with_2_free_space`
+
+如果我们不用这个插件,而是手动去一个一个改的话,工作量想必会很大,而且正确率也会因为手工的原因降低。
+
+>
diff --git a/docs/idea-tutorial/idea-plugins/code-glance.md b/docs/idea-tutorial/idea-plugins/code-glance.md
new file mode 100644
index 00000000000..9345ab427bb
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/code-glance.md
@@ -0,0 +1,11 @@
+---
+title: CodeGlance:代码微型地图
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+CodeGlance提供一个代码的微型地图,当你的类比较多的时候可以帮忙你快速定位到要去的位置。这个插件在我们日常做普通开发的时候用处不大,不过,在你阅读源码的时候还是很有用的,如下图所示:
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/code-statistic.md b/docs/idea-tutorial/idea-plugins/code-statistic.md
new file mode 100644
index 00000000000..1d60c81bad6
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/code-statistic.md
@@ -0,0 +1,39 @@
+---
+title: Statistic:项目代码统计
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+编程是一个很奇妙的事情,大部分的我们把大部分时间实际都花在了复制粘贴,而后修改代码上面。
+
+很多时候,我们并不关注代码质量,只要功能能实现,我才不管一个类的代码有多长、一个方法的代码有多长。
+
+因此,我们经常会碰到让自己想要骂街的项目,不过,说真的,你自己写的代码也有极大可能被后者 DISS。
+
+为了快速分析项目情况,判断这个项目是不是一个“垃圾”项目,有一个方法挺简单的。
+
+那就是**对代码的总行数、单个文件的代码行数、注释行数等信息进行统计。**
+
+**怎么统计呢?**
+
+首先想到的是 Excel 。不过,显然太麻烦了。
+
+**有没有专门用于代码统计的工具呢?**
+
+基于Perl语言开发的cloc(count lines of code)或许可以满足你的要求。
+
+**有没有什么更简单的办法呢?**
+
+如果你使用的是 IDEA 进行开发的话,推荐你可以使用一下 **Statistic** 这个插件。
+
+有了这个插件之后你可以非常直观地看到你的项目中所有类型的文件的信息比如数量、大小等等,可以帮助你更好地了解你们的项目。
+
+
+
+你还可以使用它看所有类的总行数、有效代码行数、注释行数、以及有效代码比重等等这些东西。
+
+
+
+如果,你担心插件过多影响IDEA速度的话,可以只在有代码统计需求的时候开启这个插件,其他时间禁用它就完事了!
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/git-commit-template.md b/docs/idea-tutorial/idea-plugins/git-commit-template.md
new file mode 100644
index 00000000000..c75dae11c79
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/git-commit-template.md
@@ -0,0 +1,19 @@
+---
+title: Git Commit Template:提交代码格式规范
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+没有安装这个插件之前,我们使用IDEA提供的Commit功能提交代码是下面这样的:
+
+
+
+使用了这个插件之后是下面这样的,提供了一个commit信息模板的输入框:
+
+
+
+完成之后的效果是这样的:
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/gson-format.md b/docs/idea-tutorial/idea-plugins/gson-format.md
new file mode 100644
index 00000000000..56750e1cb05
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/gson-format.md
@@ -0,0 +1,32 @@
+---
+title: GsonFormat:JSON转对象
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+GsonFormat 这个插件可以根据Gson库使用的要求,将JSONObject格式的String 解析成实体类。
+
+> 说明:2021.x 版本以上的 IDEA 可以使用:GsonFormatPlus
+
+这个插件使用起来非常简单,我们新建一个类,然后在类中使用快捷键 `option + s`(Mac)或`alt + s` (win)调出操作窗口(**必须在类中使用快捷键才有效**),如下图所示。
+
+
+
+这个插件是一个国人几年前写的,不过已经很久没有更新了,可能会因为IDEA的版本问题有一些小Bug。而且,这个插件无法将JSON转换为Kotlin(这个其实无关痛痒,IDEA自带的就有Java转Kotlin的功能)。
+
+
+
+另外一个与之相似的插件是 **:RoboPOJOGenerator** ,这个插件的更新频率比较快。
+
+`File-> new -> Generate POJO from JSON`
+
+
+
+然后将JSON格式的数据粘贴进去之后,配置相关属性之后选择“*Generate*”
+
+
+
+
+
diff --git a/docs/idea-tutorial/idea-plugins/idea-features-trainer.md b/docs/idea-tutorial/idea-plugins/idea-features-trainer.md
new file mode 100644
index 00000000000..a5cb4960c4d
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/idea-features-trainer.md
@@ -0,0 +1,17 @@
+---
+title: IDE Features Trainer:IDEA 交互式教程
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+**有了这个插件之后,你可以在 IDE 中以交互方式学习IDEA最常用的快捷方式和最基本功能。** 非常非常非常方便!强烈建议大家安装一个,尤其是刚开始使用IDEA的朋友。
+
+当我们安装了这个插件之后,你会发现我们的IDEA 编辑器的右边多了一个“**Learn**”的选项,我们点击这个选项就可以看到如下界面。
+
+
+
+我们选择“Editor Basics”进行,然后就可以看到如下界面,这样你就可以按照指示来练习了!非常不错!
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/idea-themes.md b/docs/idea-tutorial/idea-plugins/idea-themes.md
new file mode 100644
index 00000000000..ca38f19f51f
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/idea-themes.md
@@ -0,0 +1,99 @@
+---
+title: IDEA主题推荐
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+经常有小伙伴问我:“Guide哥,你的IDEA 主题怎么这么好看,能推荐一下不?”。就实在有点不耐烦了,才索性写了这篇文章。
+
+在这篇文章中,我精选了几个比较是和 Java 编码的 IDEA 主题供小伙伴们选择。另外,我自己用的是 One Dark theme 这款。
+
+**注意:以下主题按照使用人数降序排序。**
+
+## [Material Theme UI](https://plugins.jetbrains.com/plugin/8006-material-theme-ui)
+
+**推荐指数** :⭐⭐⭐⭐
+
+这是 IDEA 中使用人数最多的一款主题。
+
+当你安装完这个插件之后,你会发现这个主题本身又提供了多种相关的主题供你选择。
+
+
+
+ **Material Deep Ocean** 这款的效果图如下。默认的字体是真的小,小伙伴们需要自行调整一下。
+
+
+
+## [One Dark theme](https://plugins.jetbrains.com/plugin/11938-one-dark-theme)
+
+**推荐指数** :⭐⭐⭐⭐⭐
+
+我比较喜欢的一款(*黄色比较多?*)。 没有花里花哨,简单大气,看起来比较舒服。颜色搭配也很棒,适合编码!
+
+这款主题的效果图如下。
+
+
+
+## [Gradianto](https://plugins.jetbrains.com/plugin/12334-gradianto)
+
+**推荐指数** :⭐⭐⭐⭐⭐
+
+Gradianto这个主题的目标是在保持页面色彩比较层次分明的情况下,让我们因为代码而疲惫的双眼更加轻松。
+
+Gradianto附带了自然界的渐变色,看着挺舒服的。另外,这个主题本身也提供了多种相关的主题供你选择。
+
+
+
+**Gradianto Nature Green** 的效果图如下。
+
+
+
+## [Dark Purple Theme](https://plugins.jetbrains.com/plugin/12100-dark-purple-theme)
+
+**推荐指数** :⭐⭐⭐⭐⭐
+
+这是一款紫色色调的深色主题,喜欢紫色的小伙伴不要错过。
+
+这个主题的效果图如下。个人觉得整体颜色搭配的是比较不错的,适合编码!
+
+
+
+## [Hiberbee Theme](https://plugins.jetbrains.com/plugin/12118-hiberbee-theme)
+
+**推荐指数** :⭐⭐⭐⭐⭐
+
+一款受到了 Monokai Pro 和 MacOS Mojave启发的主题,是一款色彩层次分明的深色主题。
+
+这个主题的效果图如下。看着也是非常赞!适合编码!
+
+
+
+上面推荐的都是偏暗色系的主题,这里我再推荐两款浅色系的主题。
+
+## [Gray Theme](https://plugins.jetbrains.com/plugin/12103-gray-theme)
+
+**推荐指数** :⭐⭐⭐
+
+这是一款对比度比较低的一款浅色主题,不太适合代码阅读,毕竟这款主题是专门为在IntelliJ IDE中使用Markdown而设计的。
+
+这个主题的效果图如下。
+
+
+
+## [Roboticket Light Theme](https://plugins.jetbrains.com/plugin/12191-roboticket-light-theme)
+
+**推荐指数** :⭐⭐⭐
+
+这是一款对比度比较低的浅色主题,不太适合代码阅读。
+
+这个主题的效果图如下。
+
+
+
+## 后记
+
+我个人还是比较偏爱深色系的主题。
+
+小伙伴们比较喜欢哪款主题呢?可以在评论区简单聊聊不?如果你还有其他比较喜欢的主题也可以在评论区说出来供大家参考哦!
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/improve-code.md b/docs/idea-tutorial/idea-plugins/improve-code.md
new file mode 100644
index 00000000000..91b31b4e232
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/improve-code.md
@@ -0,0 +1,153 @@
+---
+title: IDEA 代码优化插件推荐
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+ - 代码优化
+---
+
+## Lombok:帮你简化代码
+
+之前没有推荐这个插件的原因是觉得已经是人手必备的了。如果你要使用 Lombok 的话,不光是要安装这个插件,你的项目也要引入相关的依赖。
+
+```xml
+
+ org.projectlombok
+ lombok
+ true
+
+```
+
+使用 Lombok 能够帮助我们少写很多代码比如 Getter/Setter、Constructor等等。
+
+关于Lombok的使用,可以查看这篇文章:[《十分钟搞懂Java效率工具Lombok使用与原理》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485385&idx=2&sn=a7c3fb4485ffd8c019e5541e9b1580cd&chksm=cea24802f9d5c1144eee0da52cfc0cc5e8ee3590990de3bb642df4d4b2a8cd07f12dd54947b9&token=1667678311&lang=zh_CN#rd)。
+
+
+## Codota:代码智能提示
+
+我一直在用的一个插件,可以说非常好用了(*我身边的很多大佬平时写代码也会用这个插件*)。
+
+Codota 这个插件用于智能代码补全,它基于数百万Java程序,能够根据程序上下文提示补全代码。相比于IDEA自带的智能提示来说,Codota 的提示更加全面一些。
+
+如果你觉得 IDEA 插件安装的太多比较卡顿的话,不用担心!Codota 插件还有一个对应的在线网站([https://www.codota.com/code](https://www.codota.com/code)),在这个网站上你可以根据代码关键字搜索相关代码示例,非常不错!
+
+我在工作中经常会用到,说实话确实给我带来了很大便利,比如我们搜索 `Files.readAllLines`相关的代码,搜索出来的结果如下图所示:
+
+
+
+另外,Codota 插件的基础功能都是免费的。你的代码也不会被泄露,这点你不用担心。
+
+简单来看看 Codota 插件的骚操作吧!
+
+### 代码智能补全
+
+我们使用`HttpUrlConnection ` 建立一个网络连接是真的样的:
+
+
+
+我们创建线程池现在变成下面这样:
+
+
+
+上面只是为了演示这个插件的强大,实际上创建线程池不推荐使用这种方式, 推荐使用 `ThreadPoolExecutor` 构造函数创建线程池。我下面要介绍的一个阿里巴巴的插件-**Alibaba Java Code Guidelines** 就检测出来了这个问题,所以,`Executors`下面用波浪线标记了出来。
+
+### 代码智能搜索
+
+除了,在写代码的时候智能提示之外。你还可以直接选中代码然后搜索相关代码示例。
+
+
+
+## Alibaba Java Code Guidelines:阿里巴巴 Java 代码规范
+
+阿里巴巴 Java 代码规范,对应的Github地址为:[https://github.com/alibaba/p3c](https://github.com/alibaba/p3c ) 。非常推荐安装!
+
+安装完成之后建议将与语言替换成中文,提示更加友好一点。
+
+
+
+根据官方描述:
+
+> 目前这个插件实现了开发手册中的的53条规则,大部分基于PMD实现,其中有4条规则基于IDEA实现,并且基于IDEA [Inspection](https://www.jetbrains.com/help/idea/code-inspection.html)实现了实时检测功能。部分规则实现了Quick Fix功能,对于可以提供Quick Fix但没有提供的,我们会尽快实现,也欢迎有兴趣的同学加入进来一起努力。 目前插件检测有两种模式:实时检测、手动触发。
+
+上述提到的开发手册也就是在Java开发领域赫赫有名的《阿里巴巴Java开发手册》。
+
+### 手动配置检测规则
+
+你还可以手动配置相关 inspection规则:
+
+
+
+### 使用效果
+
+这个插件会实时检测出我们的代码不匹配它的规则的地方,并且会给出修改建议。比如我们按照下面的方式去创建线程池的话,这个插件就会帮我们检测出来,如下图所示。
+
+
+
+这个可以对应上 《阿里巴巴Java开发手册》 这本书关于创建线程池的方式说明。
+
+
+
+## CheckStyle: Java代码格式规范
+
+### 为何需要CheckStyle插件?
+
+**CheckStyle 几乎是 Java 项目开发必备的一个插件了,它会帮助我们检查 Java 代码的格式是否有问题比如变量命名格式是否有问题、某一行代码的长度是否过长等等。**
+
+在项目上,**通过项目开发人员自我约束来规范代码格式必然是不靠谱的!** 因此,我们非常需要这样一款工具来帮助我们规范代码格式。
+
+如果你看过我写的轮子的话,可以发现我为每一个项目都集成了 CheckStyle,并且设置了 **Git Commit 钩子**,保证在提交代码之前代码格式没有问题。
+
+> **Guide哥造的轮子**(*代码简洁,结构清晰,欢迎学习,欢迎一起完善*):
+>
+> 1. [guide-rpc-framework](https://github.com/Snailclimb/guide-rpc-framework) :A custom RPC framework implemented by Netty+Kyro+Zookeeper.(一款基于 Netty+Kyro+Zookeeper 实现的自定义 RPC 框架-附详细实现过程和相关教程)
+> 2. [jsoncat](https://github.com/Snailclimb/jsoncat) :仿 Spring Boot 但不同于 Spring Boot 的一个轻量级的 HTTP 框架
+>
+> **Git 钩子**: Git 能在特定的重要动作比如commit、push发生时触发自定义脚本。 钩子都被存储在 Git 目录下的 `hooks` 子目录中。 也即绝大部分项目中的 `.git/hooks` 。
+
+### 如何在Maven/Gradle项目中集成 Checksytle?
+
+一般情况下,我们都是将其集成在项目中,并设置相应的 Git 钩子。网上有相应的介绍文章,这里就不多提了。
+
+如果你觉得网上的文章不直观的话,可以参考我上面提到了两个轮子:
+
+1. [guide-rpc-framework](https://github.com/Snailclimb/guide-rpc-framework) :Maven项目集成 Checksytle。
+2. [jsoncat](https://github.com/Snailclimb/jsoncat) :Gradle项目集成 Checksytle。
+
+如果你在项目中集成了 Checksytle 的话,每次检测会生成一个 HTML格式的文件告诉你哪里的代码格式不对,这样看着非常不直观。通过 Checksytle插件的话可以非常直观的将项目中存在格式问题的地方显示出来。
+
+
+
+如果你只是自己在本地使用,并不想在项目中集成 Checksytle 的话也可以,只需要下载一个 Checksytle插件就足够了。
+
+### 如何安装?
+
+我们直接在 IDEA 的插件市场即可找到这个插件。我这里已经安装好了。
+
+
+
+安装插件之后重启 IDEA,你会发现就可以在底部菜单栏找到 CheckStyle 了。
+
+
+
+### 如何自定义检测规则?
+
+如果你需要自定义代码格式检测规则的话,可以按照如下方式进行配置(你可以导入用于自定义检测规则的`CheckStyle.xml`文件)。
+
+
+
+### 使用效果
+
+配置完成之后,按照如下方式使用这个插件!
+
+
+
+可以非常清晰的看到:CheckStyle 插件已经根据我们自定义的规则将项目中的代码存在格式问题的地方都检测了出来。
+
+## SonarLint:帮你优化代码
+
+SonarLint 帮助你发现代码的错误和漏洞,就像是代码拼写检查器一样,SonarLint 可以实时显示出代码的问题,并提供清晰的修复指导,以便你提交代码之前就可以解决它们。
+
+
+
+并且,很多项目都集成了 SonarQube,SonarLint 可以很方便地与 SonarQube 集成。
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/interface-beautification.md b/docs/idea-tutorial/idea-plugins/interface-beautification.md
new file mode 100644
index 00000000000..3f3f62fb679
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/interface-beautification.md
@@ -0,0 +1,67 @@
+---
+title: IDEA 界面美化插件推荐
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+ - 代码优化
+---
+
+
+## Background Image Plus:背景图片
+
+我这里推荐使用国人 Jack Chu 基于 Background Image Plus 开发的最新版本,适用于 2021.x 版本的 IDEA。
+
+前面几个下载量比较高的,目前都还未支持 2021.x 版本的 IDEA。
+
+
+
+通过这个插件,你可以将 IDEA 背景设置为指定的图片,支持随机背景。
+
+效果图如下:
+
+
+
+如果你想要设置随机背景的话,可以通过 IDEA 设置页 **Settings** -> **Appearance & Behaviour** -> **Background Image Plus** 自定义设置项,随机显示目录下的图片为背景图。
+
+## Power Mode II : 代码特效
+
+使用了这个插件之后,写代码会自带特效,适用于 2021.x 版本的 IDEA。 2021.x 版本之前,可以使用 **activate-power-mode** 。
+
+
+
+你可以通过 IDEA 设置页 **Settings** -> **Appearance & Behaviour** -> **Power Mode II** 自定义设置项。
+
+
+
+## Nyan Progress Bar : 进度条美化
+
+可以让你拥有更加漂亮的进度条。
+
+
+
+## Grep Console:控制台输出处理
+
+可以说是必备的一个 IDEA 插件,非常实用!
+
+这个插件主要的功能有两个:
+
+**1. 自定义设置控制台输出颜色**
+
+我们可以在设置中进行相关的配置:
+
+
+
+配置完成之后的 log warn 的效果对比图如下:
+
+
+
+**2. 过滤控制台输出**
+
+
+
+## Rainbow Brackets : 彩虹括号
+
+使用各种鲜明的颜色来展示你的括号,效果图如下。可以看出代码层级变得更加清晰了,可以说非常实用友好了!
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/jclasslib.md b/docs/idea-tutorial/idea-plugins/jclasslib.md
new file mode 100644
index 00000000000..c5f29d2b657
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/jclasslib.md
@@ -0,0 +1,93 @@
+---
+title: jclasslib :一款IDEA字节码查看神器
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+ - 字节码
+---
+
+由于后面要分享的一篇文章中用到了这篇文章要推荐的一个插件,所以这里分享一下。非常实用!你会爱上它的!
+
+
+
+**开始推荐 IDEA 字节码查看神器之前,先来回顾一下 Java 字节码是啥。**
+
+## 何为 Java 字节码?
+
+Java 虚拟机(JVM)是运行 Java 字节码的虚拟机。JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。
+
+**什么是字节码?采用字节码的好处是什么?**
+
+> 在 Java 中,JVM 可以理解的代码就叫做`字节码`(即扩展名为 `.class` 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。
+
+**Java 程序从源代码到运行一般有下面 3 步:**
+
+
+
+## 为什么要查看 Java 字节码?
+
+我们在平时学习的时候,经常需要查看某个 java 类的字节码文件。查看字节码文件更容易让我们搞懂 java 代码背后的原理比如搞懂 java 中的各种语法糖的本质。
+
+## 如何查看 Java 字节码?
+
+如果我们通过命令行来查看某个 class 的字节码文件的话,可以直接通过 `javap` 命令,不过这种方式太原始了,效率十分低,并且看起来不直观。
+
+下面介绍两种使用 IDEA 查看类对应字节码文件的方式(_`javap`这种方式就不提了_)。
+
+我们以这段代码作为案例:
+
+```java
+public class Main {
+ public static void main(String[] args) {
+ Integer i = null;
+ Boolean flag = false;
+ System.out.println(flag ? 0 : i);
+ }
+}
+```
+
+上面这段代码由于使用三目运算符不当导致诡异了 NPE 异常。为了搞清楚事情的原因,我们来看其对应的字节码。
+
+### 使用 IDEA 自带功能
+
+我们点击 `View -> Show Bytecode` 即可通过 IDEA 查看某个类对应的字节码文件。
+
+> 需要注意的是:**查看某个类对应的字节码文件之前确保它已经被编译过。**
+
+
+
+稍等几秒钟之后,你就可以直观到看到对应的类的字节码内容了。
+
+
+
+从字节码中可以看出,我圈出来的位置发生了 **拆箱操作** 。
+
+> - **装箱**:将基本类型用它们对应的引用类型包装起来;
+> - **拆箱**:将包装类型转换为基本数据类型;
+
+详细解释下就是:`flag ? 0 : i` 这行代码中,0 是基本数据类型 int,返回数据的时候 i 会被强制拆箱成 int 类型,由于 i 的值是 null,因此就抛出了 NPE 异常。
+
+```java
+Integer i = null;
+Boolean flag = false;
+System.out.println(flag ? 0 : i);
+```
+
+如果,我们把代码中 `flag` 变量的值修改为 true 的话,就不会存在 NPE 问题了,因为会直接返回 0,不会进行拆箱操作。
+
+### 使用 IDEA 插件 jclasslib(推荐)
+
+相比于 IDEA 自带的查看类字节的功能,我更推荐 `jclasslib` 这个插件,非常棒!
+
+**使用 `jclasslib` 不光可以直观地查看某个类对应的字节码文件,还可以查看类的基本信息、常量池、接口、属性、函数等信息。**
+
+
+
+我们直接在 IDEA 的插件市场即可找到这个插件。我这里已经安装好了。
+
+
+
+安装完成之后,重启 IDEA。点击`View -> Show Bytecode With jclasslib` 即可通过`jclasslib` 查看某个类对应的字节码文件。
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/maven-helper.md b/docs/idea-tutorial/idea-plugins/maven-helper.md
new file mode 100644
index 00000000000..d2b064a9934
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/maven-helper.md
@@ -0,0 +1,19 @@
+---
+title: Maven Helper:解决 Maven 依赖冲突问题
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+ - Maven
+---
+
+
+**Maven Helper** 主要用来分析 Maven 项目的相关依赖,可以帮助我们解决 Maven 依赖冲突问题。
+
+
+
+**何为依赖冲突?**
+
+说白了就是你的项目使用的 2 个 jar 包引用了同一个依赖 h,并且 h 的版本还不一样,这个时候你的项目就存在两个不同版本的 h。这时 Maven 会依据依赖路径最短优先原则,来决定使用哪个版本的 Jar 包,而另一个无用的 Jar 包则未被使用,这就是所谓的依赖冲突。
+
+大部分情况下,依赖冲突可能并不会对系统造成什么异常,因为 Maven 始终选择了一个 Jar 包来使用。但是,不排除在某些特定条件下,会出现类似找不到类的异常,所以,只要存在依赖冲突,在我看来,最好还是解决掉,不要给系统留下隐患。
diff --git a/docs/idea-tutorial/idea-plugins/others.md b/docs/idea-tutorial/idea-plugins/others.md
new file mode 100644
index 00000000000..da505ff8dfe
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/others.md
@@ -0,0 +1,21 @@
+---
+title: 其他
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+1. **leetcode editor** :提供在线 Leetcode 刷题功能,比较方便我们刷题,不过我试用之后发现有一些小 bug,个人感觉还是直接在网站找题目刷来的痛快一些。
+2. **A Search with Github** :直接通过 Github搜索相关代码。
+3. **stackoverflow** : 选中相关内容后单击右键即可快速跳转到 stackoverflow 。
+4. **CodeStream** :让code review变得更加容易。
+5. **Code screenshots** :代码片段保存为图片。
+6. **GitToolBox** :Git工具箱
+7. **OK, Gradle!** :搜索Java库用于Gradle项目
+8. **Java Stream Debugger** : Java8 Stream调试器
+9. **EasyCode** : Easycode 可以直接对数据的表生成entity、controller、service、dao、mapper无需任何编码,简单而强大。更多内容可以查看这篇文章:[《懒人 IDEA 插件插件:EasyCode 一键帮你生成所需代码~》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247486205&idx=1&sn=0ff2f87f0d82a1bd9c0c44328ef69435&chksm=cea24536f9d5cc20c6cc7669f0d4167d747fe8b8c05a64546c0162d694aa96044a2862e24b57&token=1862674725&lang=zh_CN#rd)
+10. **JFormDesigner** :Swing GUI 在线编辑器。
+11. **VisualVM Launcher** : Java性能分析神器。
+12. ......
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Codota1.gif b/docs/idea-tutorial/idea-plugins/pictures/Codota1.gif
new file mode 100644
index 00000000000..7b2947fe3a0
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Codota1.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Codota2.png b/docs/idea-tutorial/idea-plugins/pictures/Codota2.png
new file mode 100644
index 00000000000..0fe37e36047
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Codota2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Codota3.png b/docs/idea-tutorial/idea-plugins/pictures/Codota3.png
new file mode 100644
index 00000000000..44d1093e492
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Codota3.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Codota4.gif b/docs/idea-tutorial/idea-plugins/pictures/Codota4.gif
new file mode 100644
index 00000000000..1322b60f5e0
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Codota4.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/GsonFormat1.png b/docs/idea-tutorial/idea-plugins/pictures/GsonFormat1.png
new file mode 100644
index 00000000000..c8e678acb68
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/GsonFormat1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/GsonFormat2.gif b/docs/idea-tutorial/idea-plugins/pictures/GsonFormat2.gif
new file mode 100644
index 00000000000..7c371162d9e
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/GsonFormat2.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer1.png b/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer1.png
new file mode 100644
index 00000000000..27f888a9499
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer2.png b/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer2.png
new file mode 100644
index 00000000000..6d59082c281
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/IDE-Features-Trainer2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/JavaStreamDebugger.gif b/docs/idea-tutorial/idea-plugins/pictures/JavaStreamDebugger.gif
new file mode 100644
index 00000000000..6e910e72ed5
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/JavaStreamDebugger.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Presentation-Assistant.gif b/docs/idea-tutorial/idea-plugins/pictures/Presentation-Assistant.gif
new file mode 100644
index 00000000000..335523ea5f9
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Presentation-Assistant.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit1.png b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit1.png
new file mode 100644
index 00000000000..5a69bc0595a
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit2.png b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit2.png
new file mode 100644
index 00000000000..6c8aefd7638
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit3.png b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit3.png
new file mode 100644
index 00000000000..b6cf628e76a
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit3.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit4.png b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit4.png
new file mode 100644
index 00000000000..be15f46bdd2
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RestfulToolkit4.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator1.png b/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator1.png
new file mode 100644
index 00000000000..c2d7704766b
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator2.png b/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator2.png
new file mode 100644
index 00000000000..4334b3db390
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/RoboPOJOGenerator2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Statistic1.png b/docs/idea-tutorial/idea-plugins/pictures/Statistic1.png
new file mode 100644
index 00000000000..47521ee25dd
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Statistic1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/Statistic2.png b/docs/idea-tutorial/idea-plugins/pictures/Statistic2.png
new file mode 100644
index 00000000000..f815aa1c722
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/Statistic2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case1.png b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case1.png
new file mode 100644
index 00000000000..7fbbbba97e5
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case2.gif b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case2.gif
new file mode 100644
index 00000000000..9565231e9d7
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case2.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case3.png b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case3.png
new file mode 100644
index 00000000000..d4b2fd27ab3
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/camel-case/camel-case3.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/check-style.png b/docs/idea-tutorial/idea-plugins/pictures/check-style.png
new file mode 100644
index 00000000000..e0c17b64096
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/check-style.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/code-glance.png b/docs/idea-tutorial/idea-plugins/pictures/code-glance.png
new file mode 100644
index 00000000000..afdf1a1bca0
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/code-glance.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template1.png b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template1.png
new file mode 100644
index 00000000000..26da6cd1b06
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template2.png b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template2.png
new file mode 100644
index 00000000000..c0e436432a5
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template3.png b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template3.png
new file mode 100644
index 00000000000..17f81a23469
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/git-commit-template/Git-Commit-Template3.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console.gif b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console.gif
new file mode 100644
index 00000000000..293c134207f
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console2.png b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console2.png
new file mode 100644
index 00000000000..aa338d615ee
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console3.png b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console3.png
new file mode 100644
index 00000000000..411128ed121
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/grep-console/grep-console3.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/maver-helper.png b/docs/idea-tutorial/idea-plugins/pictures/maver-helper.png
new file mode 100644
index 00000000000..35a3f6e083f
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/maver-helper.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines1.png b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines1.png
new file mode 100644
index 00000000000..67c3571d836
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines1.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines2.png b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines2.png
new file mode 100644
index 00000000000..e4b1dc8c9a8
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines3.png b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines3.png
new file mode 100644
index 00000000000..5213aff02ca
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/p3c/Alibaba-Java-Code-Guidelines3.png differ
diff --git "a/docs/idea-tutorial/idea-plugins/pictures/p3c/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214-\347\272\277\347\250\213\346\261\240\345\210\233\345\273\272.png" "b/docs/idea-tutorial/idea-plugins/pictures/p3c/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214-\347\272\277\347\250\213\346\261\240\345\210\233\345\273\272.png"
new file mode 100644
index 00000000000..4d18c60b055
Binary files /dev/null and "b/docs/idea-tutorial/idea-plugins/pictures/p3c/\351\230\277\351\207\214\345\267\264\345\267\264\345\274\200\345\217\221\346\211\213\345\206\214-\347\272\277\347\250\213\346\261\240\345\210\233\345\273\272.png" differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/power-mode/Power-Mode-II.gif b/docs/idea-tutorial/idea-plugins/pictures/power-mode/Power-Mode-II.gif
new file mode 100644
index 00000000000..026c32e947e
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/power-mode/Power-Mode-II.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/rainbow-brackets.png b/docs/idea-tutorial/idea-plugins/pictures/rainbow-brackets.png
new file mode 100644
index 00000000000..6529899a3ed
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/rainbow-brackets.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions.png b/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions.png
new file mode 100644
index 00000000000..cf765cb6d0e
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions.png differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions2.gif b/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions2.gif
new file mode 100644
index 00000000000..93ae62cf6c2
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/save-actions/save-actions2.gif differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/translation/translation1.jpg b/docs/idea-tutorial/idea-plugins/pictures/translation/translation1.jpg
new file mode 100644
index 00000000000..7b512c115b1
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/translation/translation1.jpg differ
diff --git a/docs/idea-tutorial/idea-plugins/pictures/translation/translation2.png b/docs/idea-tutorial/idea-plugins/pictures/translation/translation2.png
new file mode 100644
index 00000000000..c92664718dd
Binary files /dev/null and b/docs/idea-tutorial/idea-plugins/pictures/translation/translation2.png differ
diff --git a/docs/idea-tutorial/idea-plugins/rest-devlop.md b/docs/idea-tutorial/idea-plugins/rest-devlop.md
new file mode 100644
index 00000000000..329552b33b2
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/rest-devlop.md
@@ -0,0 +1,96 @@
+---
+title: RestfulToolkit:RESTful Web 服务辅助开发工具
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+开始推荐这个 IDEA 插件之前,我觉得有必要花一小会时间简单聊聊 **REST** 这个我们经常打交道的概念。
+
+## REST 相关概念解读
+
+### 何为 REST?
+
+REST 即 **REpresentational State Transfer** 的缩写。这个词组的翻译过来就是"**表现层状态转化**"。
+
+这样理解起来甚是晦涩,实际上 REST 的全称是 **Resource Representational State Transfer** ,直白地翻译过来就是 **“资源”在网络传输中以某种“表现形式”进行“状态转移”** 。
+
+**有没有感觉很难理解?**
+
+没关系,看了我对 REST 涉及到的一些概念的解读之后你没准就能理解了!
+
+- **资源(Resource)** :我们可以把真实的对象数据称为资源。一个资源既可以是一个集合,也可以是单个个体。比如我们的班级 classes 是代表一个集合形式的资源,而特定的 class 代表单个个体资源。每一种资源都有特定的 URI(统一资源定位符)与之对应,如果我们需要获取这个资源,访问这个 URI 就可以了,比如获取特定的班级:`/class/12`。另外,资源也可以包含子资源,比如 `/classes/classId/teachers`:列出某个指定班级的所有老师的信息
+- **表现形式(Representational)**:"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式比如 json,xml,image,txt 等等叫做它的"表现层/表现形式"。
+- **状态转移(State Transfer)** :大家第一眼看到这个词语一定会很懵逼?内心 BB:这尼玛是啥啊? **大白话来说 REST 中的状态转移更多地描述的服务器端资源的状态,比如你通过增删改查(通过 HTTP 动词实现)引起资源状态的改变。** (HTTP 协议是一个无状态的,所有的资源状态都保存在服务器端)
+
+### 何为 RESTful 架构?
+
+满足 REST 风格的架构设计就可以称为 RESTful 架构:
+
+1. 每一个 URI 代表一种资源;
+2. 客户端和服务器之间,传递这种资源的某种表现形式比如 json,xml,image,txt 等等;
+3. 客户端通过特定的 HTTP 动词,对服务器端资源进行操作,实现"表现层状态转化"。
+
+### 何为 RESTful Web 服务?
+
+基于 REST 架构的 Web 服务就被称为 RESTful Web 服务。
+
+## RESTful Web 服务辅助开发工具
+
+### 安装
+
+这个插件的名字叫做 “**RestfulToolkit**” 。我们直接在 IDEA 的插件市场即可找到这个插件。如下图所示。
+
+> 如果你因为网络问题没办法使用 IDEA 自带的插件市场的话,也可以通过[IDEA 插件市场的官网](https://plugins.jetbrains.com/idea)手动下载安装。
+
+
+
+### 简单使用
+
+#### URL 跳转到对应方法
+
+根据 URL 直接跳转到对应的方法定义 (Windows: `ctrl+\` or `ctrl+alt+n` Mac:`command+\` or `command+alt+n` )并且提供了一个服务的树形可视化显示窗口。 如下图所示。
+
+
+
+#### 作为 HTTP 请求工具
+
+这个插件还可以作为一个简单的 http 请求工具来使用。如下图所示。
+
+
+
+#### 复制生成 URL、复制方法参数...
+
+这个插件还提供了生成 URL、查询参数、请求体(RequestBody)等功能。
+
+举个例子。我们选中 `Controller` 中的某个请求对应的方法右击,你会发现多了几个可选项。当你选择`Generate & Copy Full URL`的话,就可以把整个请求的路径直接复制下来。eg:`http://localhost:9333/api/users?pageNum=1&pageSize=1` 。
+
+
+
+#### 将 Java 类转换为对应的 JSON 格式
+
+这个插件还为 Java 类上添加了 **Convert to JSON** 功能 。
+
+我们选中的某个类对应的方法然后右击,你会发现多了几个可选项。
+
+
+
+当我们选择`Convert to JSON`的话,你会得到如下 json 类型的数据:
+
+```json
+{
+ "username": "demoData",
+ "password": "demoData",
+ "rememberMe": true
+}
+```
+
+## 后记
+
+RESTFulToolkit 原作者不更新了,IDEA.201 及以上版本不再适配。
+
+因此,国内就有一个大佬参考 RESTFulToolkit 开发了一款类似的插件——RestfulTool(功能较少一些,不过够用了)。
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/save-actions.md b/docs/idea-tutorial/idea-plugins/save-actions.md
new file mode 100644
index 00000000000..fc149ad301b
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/save-actions.md
@@ -0,0 +1,23 @@
+---
+title: Save Actions:优化文件保存
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+真必备插件!可以帮助我们在保存文件的时候:
+
+1. 优化导入;
+2. 格式化代码;
+3. 执行一些quick fix
+4. ......
+
+这个插件是支持可配置的,我的配置如下:
+
+
+
+实际使用效果如下:
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/sequence-diagram.md b/docs/idea-tutorial/idea-plugins/sequence-diagram.md
new file mode 100644
index 00000000000..050d6161163
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/sequence-diagram.md
@@ -0,0 +1,91 @@
+---
+title: SequenceDiagram:一键可以生成时序图
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+
+在平时的学习/工作中,我们会经常面临如下场景:
+
+1. 阅读别人的代码
+2. 阅读框架源码
+3. 阅读自己很久之前写的代码。
+
+千万不要觉得工作就是单纯写代码,实际工作中,你会发现你的大部分时间实际都花在了阅读和理解已有代码上。
+
+为了能够更快更清晰地搞清对象之间的调用关系,我经常需要用到序列图。手动画序列图还是很麻烦费时间的,不过 IDEA 提供了一个叫做**SequenceDiagram** 的插件帮助我们解决这个问题。通过 SequenceDiagram 这个插件,我们一键可以生成时序图。
+
+## 何为序列图?
+
+网上对于序列图的定义有很多,我觉得都不太好理解,太抽象了。最神奇的是,大部分文章对于序列图的定义竟然都是一模一样,看来大家是充分发挥了写代码的“精髓”啊!
+
+我还是简单说一说我的理解吧!不过,说实话,我自己对于 Sequence Diagram 也不是很明朗。下面的描述如有问题和需要完善的地方,还请指出。
+
+> **序列图**(Sequence Diagram),亦称为**循序图**,是一种[UML](https://zh.m.wikipedia.org/wiki/UML)行为图。表示系统执行某个方法/操作(如登录操作)时,对象之间的顺序调用关系。
+>
+> 这个顺序调用关系可以这样理解:你需要执行系统中某个对象 a 提供的方法/操作 login(登录),但是这个对象又依赖了对象 b 提供的方法 getUser(获取用户)。因此,这里就有了 a -> b 调用关系之说。
+
+再举两个例子来说一下!
+
+下图是微信支付的业务流程时序图。这个图描述了微信支付相关角色(顾客,商家...)在微信支付场景下,基础支付和支付的的顺序调用关系。
+
+
+
+下图是我写的一个 HTTP 框架中的执行某个方法的序列图。这个图描述了我们在调用 `InterceptorFactory`类的 `loadInterceptors()` 方法的时候,所涉及到的类之间的调用关系。
+
+
+
+另外,国内一般更喜欢称呼序列图为"时序图"。
+
+- 如果你按照纯翻译的角度来说, sequence 这个单词并无"时间"的意思,只有序列,顺序等意思,因此也有人说“时序图”的说法是不准确的。
+- 如果从定义角度来说,时序图这个描述是没问题的。因为 Sequence Diagram 中每条消息的触发时机确实是按照时间顺序执行的。
+
+我觉得称呼 Sequence Diagram 为时序图或者序列图都是没问题的,不用太纠结。
+
+## 哪些场景下需要查看类的时序图?
+
+我们在很多场景下都需要时序图,比如说:
+
+1. **阅读源码** :阅读源码的时候,你可能需要查看调用目标方法涉及的相关类的调用关系。特别是在代码的调用层级比较多的时候,对于我们理解源码非常有用。(_题外话:实际工作中,大部分时间实际我们都花在了阅读理解已有代码上。_)
+2. **技术文档编写** :我们在写项目介绍文档的时候,为了让别人更容易理解你的代码,你需要根据核心方法为相关的类生成时序图来展示他们之间的调用关系。
+3. **梳理业务流程** :当我们的系统业务流程比较复杂的时候,我们可以通过序列图将系统中涉及的重要的角色和对象的之间关系可视化出来。
+4. ......
+
+## 如何使用 IDEA 根据类中方法生成时序图?
+
+**通过 SequenceDiagram 这个插件,我们一键可以生成时序图。**
+
+并且,你还可以:
+
+1. 点击时序图中的类/方法即可跳转到对应的地方。
+2. 从时序图中删除对应的类或者方法。
+3. 将生成的时序图导出为 PNG 图片格式。
+
+### 安装
+
+我们直接在 IDEA 的插件市场即可找到这个插件。我这里已经安装好了。
+
+> 如果你因为网络问题没办法使用 IDEA 自带的插件市场的话,也可以通过[IDEA 插件市场的官网](https://plugins.jetbrains.com/idea)手动下载安装。
+
+
+
+### 简单使用
+
+1. 选中方法名(注意不要选类名),然后点击鼠标右键,选择 **Sequence Diagram** 选项即可!
+
+
+
+2. 配置生成的序列图的一些基本的参数比如调用深度之后,我们点击 ok 即可!
+
+
+
+你还可以通过生成的时序图来定位到相关的代码,这对于我们阅读源码的时候尤其有帮助!
+
+
+
+时序图生成完成之后,你还可以选择将其导出为图片。
+
+
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/shortcut-key.md b/docs/idea-tutorial/idea-plugins/shortcut-key.md
new file mode 100644
index 00000000000..c7e585290e7
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/shortcut-key.md
@@ -0,0 +1,56 @@
+---
+title: IDEA 快捷键相关插件
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+相信我!下面这两个一定是IDEA必备的插件。
+
+## Key Promoter X:快捷键提示
+
+这个插件的功能主要是**在你本可以使用快捷键操作的地方提醒你用快捷键操作。**
+
+举个例子。我直接点击tab栏下的菜单打开 Version Control(版本控制) 的话,这个插件就会提示你可以用快捷键 `command+9`或者`shift+command+9`打开。如下图所示。
+
+
+
+除了这个很棒的功能之外,这个插件还有一个功能我觉得非常棒。
+
+它可以展示出哪些快捷键你忘记使用的次数最多!这样的话,你可以给予你忘记次数最多的那些快捷键更多的关注。
+
+我忘记最多的快捷键是debug的时候经常使用的 F8(Step Over)。如下图所示。
+
+
+
+关于快捷键,很多人不愿意去记,觉得单纯靠鼠标就完全够了。
+
+让我来说的话!我觉得如果你偶尔使用一两次 IDEA 的话,你完全没有必要纠结快捷键。
+
+但是,如果 IDEA 是你开发的主力,你经常需要使用的话,相信我,掌握常用的一些快捷键真的很重要!
+
+不说多的,**熟练掌握IDEA的一些最常见的快捷键,你的工作效率至少提升 30 %。**
+
+**除了工作效率的提升之外,使用快捷键会让我们显得更加专业。**
+
+你在使用快捷键进行操作的时候,是很帅,很酷啊!但是,当你用 IDEA 给别人演示一些操作的时候,你使用了快捷键的话,别人可能根本不知道你进行了什么快捷键操作。
+
+**怎么解决这个问题呢?**
+
+很简单!这个时候就轮到 **Presentation Assistant** 这个插件上场了!
+
+## Presentation Assistant:快捷键展示
+
+安装这个插件之后,你使用的快捷键操作都会被可视化地展示出来,非常适合自己在录制视频或者给别人展示代码的时候使用。
+
+举个例子。我使用快捷键 `command+9`打开 Version Control ,使用了这个插件之后的效果如下图所示。
+
+
+
+从上图可以很清晰地看到,IDEA 的底部中间的位置将我刚刚所使用的快捷键给展示了出来。
+
+并且,**这个插件会展示出 Mac 和 Win/Linux 两种不同的版本的快捷键。**
+
+因此,不论你的操作系统是 Mac 还是 Win/Linux ,这款插件都能满足你的需求。
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-plugins/translation.md b/docs/idea-tutorial/idea-plugins/translation.md
new file mode 100644
index 00000000000..7de2619a3b5
--- /dev/null
+++ b/docs/idea-tutorial/idea-plugins/translation.md
@@ -0,0 +1,28 @@
+---
+title: Translation:翻译
+category: IDEA指南
+tag:
+ - IDEA
+ - IDEA插件
+---
+
+
+有了这个插件之后,你再也不用在编码的时候打开浏览器查找某个单词怎么拼写、某句英文注释什么意思了。
+
+并且,这个插件支持多种翻译源:
+
+1. Google 翻译
+2. Youdao 翻译
+3. Baidu 翻译
+
+除了翻译功能之外还提供了语音朗读、单词本等实用功能。这个插件的Github地址是:[https://github.com/YiiGuxing/TranslationPlugin](https://github.com/YiiGuxing/TranslationPlugin) (貌似是国人开发的,很赞)。
+
+**使用方法很简单!选中你要翻译的单词或者句子,使用快捷键 `command+ctrl+u(mac)` / `shift+ctrl+y(win/linux)`** (如果你忘记了快捷的话,鼠标右键操作即可!)
+
+
+
+**如果需要快速打开翻译框,使用快捷键`command+ctrl+i(mac)`/`ctrl + shift + o(win/linux)`**
+
+
+
+如果你需要将某个重要的单词添加到生词本的话,只需要点击单词旁边的收藏按钮即可!
\ No newline at end of file
diff --git a/docs/idea-tutorial/idea-tips/idea-plug-in-development-intro.md b/docs/idea-tutorial/idea-tips/idea-plug-in-development-intro.md
new file mode 100644
index 00000000000..8f8822c5946
--- /dev/null
+++ b/docs/idea-tutorial/idea-tips/idea-plug-in-development-intro.md
@@ -0,0 +1,213 @@
+# IDEA 插件开发入门
+
+我这个人没事就喜欢推荐一些好用的 [IDEA 插件](https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1319419426898329600&__biz=Mzg2OTA0Njk0OA==#wechat_redirect)给大家。这些插件极大程度上提高了我们的生产效率以及编码舒适度。
+
+**不知道大家有没有想过自己开发一款 IDEA 插件呢?**
+
+我自己想过,但是没去尝试过。刚好有一位读者想让我写一篇入门 IDEA 开发的文章,所以,我在周末就花了一会时间简单了解一下。
+
+
+
+不过,**这篇文章只是简单带各位小伙伴入门一下 IDEA 插件开发**,个人精力有限,暂时不会深入探讨太多。如果你已经有 IDEA 插件开发的相关经验的话,这篇文章就可以不用看了,因为会浪费你 3 分钟的时间。
+
+好的废话不多说!咱们直接开始!
+
+## 01 新建一个基于 Gradle 的插件项目
+
+这里我们基于 Gradle 进行插件开发,这也是 IntelliJ 官方的推荐的插件开发解决方案。
+
+**第一步,选择 Gradle 项目类型并勾选上相应的依赖。**
+
+
+
+**第二步,填写项目相关的属性比如 GroupId、ArtifactId。**
+
+
+
+**第三步,静静等待项目下载相关依赖。**
+
+第一次创建 IDEA 插件项目的话,这一步会比较慢。因为要下载 IDEA 插件开发所需的 SDK 。
+
+## 02 插件项目结构概览
+
+新建完成的项目结构如下图所示。
+
+
+
+这里需要额外注意的是下面这两个配置文件。
+
+**`plugin.xml` :插件的核心配置文件。通过它可以配置插件名称、插件介绍、插件作者信息、Action 等信息。**
+
+```xml
+
+ github.javaguide.my-first-idea-plugin
+
+ Beauty
+
+ JavaGuide
+
+
+ 这尼玛是什么垃圾插件!!!
+ ]]>
+
+
+ com.intellij.modules.platform
+
+
+
+
+
+
+
+
+
+```
+
+**`build.gradle` :项目依赖配置文件。通过它可以配置项目第三方依赖、插件版本、插件版本更新记录等信息。**
+
+```groovy
+plugins {
+ id 'java'
+ id 'org.jetbrains.intellij' version '0.6.3'
+}
+
+group 'github.javaguide'
+// 当前插件版本
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+// 项目依赖
+dependencies {
+ testCompile group: 'junit', name: 'junit', version: '4.12'
+}
+
+// See https://github.com/JetBrains/gradle-intellij-plugin/
+// 当前开发该插件的 IDEA 版本
+intellij {
+ version '2020.1.2'
+}
+patchPluginXml {
+ // 版本更新记录
+ changeNotes """
+ Add change notes here.
+ most HTML tags may be used """
+}
+```
+
+没有开发过 IDEA 插件的小伙伴直接看这两个配置文件内容可能会有点蒙。所以,我专门找了一个 IDEA 插件市场提供的现成插件来说明一下。小伙伴们对照下面这张图来看下面的配置文件内容就非常非常清晰了。
+
+
+
+这就非常贴心了!如果这都不能让你点赞,我要这文章有何用!
+
+
+
+## 03 手动创建 Action
+
+我们可以把 Action 看作是 IDEA 提高的事件响应处理器,通过 Action 我们可以自定义一些事件处理逻辑/动作。比如说你点击某个菜单的时候,我们进行一个展示对话框的操作。
+
+**第一步,右键`java`目录并选择 new 一个 Action**
+
+![]()
+
+**第二步,配置 Action 相关信息比如展示名称。**
+
+![配置动作属性 (1)]()
+
+创建完成之后,我们的 `plugin.xml` 的 ``节点下会自动生成我们刚刚创建的 Action 信息:
+
+```xml
+
+
+
+
+
+
+```
+
+并且 `java` 目录下为生成一个叫做 `HelloAction` 的类。并且,这个类继承了 `AnAction` ,并覆盖了 `actionPerformed()` 方法。这个 `actionPerformed` 方法就好比 JS 中的 `onClick` 方法,会在你点击的时候被触发对应的动作。
+
+我简单对`actionPerformed` 方法进行了修改,添加了一行代码。这行代码很简单,就是显示 1 个对话框并展示一些信息。
+
+```java
+public class HelloAction extends AnAction {
+
+ @Override
+ public void actionPerformed(AnActionEvent e) {
+ //显示对话框并展示对应的信息
+ Messages.showInfoMessage("素材不够,插件来凑!", "Hello");
+ }
+}
+
+```
+
+另外,我们上面也说了,每个动作都会归属到一个 Group 中,这个 Group 可以简单看作 IDEA 中已经存在的菜单。
+
+举个例子。我上面创建的 Action 的所属 Group 是 **ToolsMenu(Tools)** 。这样的话,我们创建的 Action 所在的位置就在 Tools 这个菜单下。
+
+
+
+再举个例子。加入我上面创建的 Action 所属的 Group 是**MainMenu** (IDEA 最上方的主菜单栏)下的 **FileMenu(File)** 的话。
+
+```xml
+
+
+
+
+
+
+```
+
+我们创建的 Action 所在的位置就在 File 这个菜单下。
+
+
+
+## 04 验收成果
+
+点击 `Gradle -> runIde` 就会启动一个默认了这个插件的 IDEA。然后,你可以在这个 IDEA 上实际使用这个插件了。
+
+
+
+效果如下:
+
+
+
+我们点击自定义的 Hello Action 的话就会弹出一个对话框并展示出我们自定义的信息。
+
+
+
+## 05 完善一下
+
+想要弄点界面花里胡哨一下, 我们还可以通过 Swing 来写一个界面。
+
+这里我们简单实现一个聊天机器人。代码的话,我是直接参考的我大二刚学 Java 那会写的一个小项目(_当时写的代码实在太烂了!就很菜!_)。
+
+
+
+首先,你需要在[图灵机器人官网](http://www.tuling123.com/ "图灵机器人官网")申请一个机器人。(_其他机器人也一样,感觉这个图灵机器人没有原来好用了,并且免费调用次数也不多_)
+
+
+
+然后,简单写一个方法来请求调用机器人。由于代码比较简单,我这里就不放出来了,大家简单看一下效果就好。
+
+
+
+## 06 深入学习
+
+如果你想要深入学习的 IDEA 插件的话,可以看一下官网文档:[https://jetbrains.org/intellij/sdk/docs/basics/basics.html ](https://jetbrains.org/intellij/sdk/docs/basics/basics.html "https://jetbrains.org/intellij/sdk/docs/basics/basics.html") 。
+
+这方面的资料还是比较少的。除了官方文档的话,你还可以简单看看下面这几篇文章:
+
+- [8 条经验轻松上手 IDEA 插件开发](https://developer.aliyun.com/article/777850?spm=a2c6h.12873581.0.dArticle777850.118d6446r096V4&groupCode=alitech "8 条经验轻松上手 IDEA 插件开发")
+- [IDEA 插件开发入门教程](https://blog.xiaohansong.com/idea-plugin-development.html "IDEA 插件开发入门教程")
+
+## 07 后记
+
+我们开发 IDEA 插件主要是为了让 IDEA 更加好用,比如有些框架使用之后可以减少重复代码的编写、有些主题类型的插件可以让你的 IDEA 更好看。
+
+我这篇文章的这个案例说实话只是为了让大家简单入门一下 IDEA 开发,没有任何实际应用意义。**如果你想要开发一个不错的 IDEA 插件的话,还要充分发挥想象,利用 IDEA 插件平台的能力。**
diff --git a/docs/idea-tutorial/idea-tips/idea-refractor-intro.md b/docs/idea-tutorial/idea-tips/idea-refractor-intro.md
new file mode 100644
index 00000000000..7c3d4a66590
--- /dev/null
+++ b/docs/idea-tutorial/idea-tips/idea-refractor-intro.md
@@ -0,0 +1,75 @@
+# IDEA 重构入门
+
+我们在使用 IDEA 进行重构之前,先介绍一个方便我们进行重构的快捷键:`ctrl+t(mac)/ctrl+shift+alt+t`(如果忘记快捷键的话,鼠标右键也能找到重构选项),使用这个快捷键可以快速调出常用重构的选项,如下图所示:
+
+
+
+### 重命名(rename)
+
+快捷键:**Shift + F6(mac) / Shift + F6(windows/Linux):** 对类、变量或者方法名重命名。
+
+
+
+### 提取相关重构手段
+
+这部分的快捷键实际很好记忆,我是这样记忆的:
+
+前面两个键位是 `command + option(mac) / ctrl + alt (Windows/Linux)` 是固定的,只有后面一个键位会变比如Extract constant (提取变量)就是 c(constant)、Extract variable (提取变量)就是 v(variable)。
+
+#### 提取常量(extract constant)
+
+1. **使用场景** :提取未经过定义就直接出现的常量。提取常量使得你的编码更易读,避免硬编码。
+2. **快捷键:** `command + option+ c(mac)/ ctrl + alt + c(Windows/Linux)`
+
+**示例:**
+
+
+
+#### 提取参数(exact parameter)
+
+1. **使用场景** :提取参数到方法中。
+2. **快捷键:** `command + option+ p(mac)/ ctrl + alt + p(Windows/Linux)`
+
+
+
+#### 提取变量(exact variable)
+
+1. **使用场景** :提取多次出现的表达式。
+2. **快捷键:** `command + option+ v(mac) / ctrl + alt + v(Windows/Linux) `
+
+**示例:**
+
+
+
+#### 提取属性(exact field)
+
+1. **使用场景** :把当前表达式提取成为类的一个属性。
+2. **快捷键:** `command + option+ f(mac) / ctrl + alt + f(Windows/Linux) `
+
+**示例:**
+
+
+
+
+**示例:**
+
+
+
+#### 提取方法(exact method)
+
+1. **使用场景** :1个或者多个表达式可以提取为一个方法。 提取方法也能使得你的编码更易读,更加语义化。
+2. **快捷键:** `command + option+ m(mac)/ ctrl + alt + m(Windows/Linux)`
+
+**示例:**
+
+
+
+#### 提取接口(exact interface)
+
+1. **使用场景** :想要把一个类中的1个或多个方法提取到一个接口中的时候。
+2. **快捷键:** `command + option+ m(mac)/ ctrl + alt + m(Windows/Linux)`
+
+**示例:**
+
+
+
diff --git a/docs/idea-tutorial/idea-tips/idea-source-code-reading-skills.md b/docs/idea-tutorial/idea-tips/idea-source-code-reading-skills.md
new file mode 100644
index 00000000000..0064598c423
--- /dev/null
+++ b/docs/idea-tutorial/idea-tips/idea-source-code-reading-skills.md
@@ -0,0 +1,189 @@
+# IDEA源码阅读技巧
+
+项目有个新来了一个小伙伴,他看我查看项目源代码的时候,各种骚操作“花里胡哨”的。于是他向我请教,想让我分享一下我平时使用 IDEA 看源码的小技巧。
+
+## 基本操作
+
+这一部分的内容主要是一些我平时看源码的时候常用的快捷键/小技巧!非常好用!
+
+掌握这些快捷键/小技巧,看源码的效率提升一个等级!
+
+### 查看当前类的层次结构
+
+| 使用频率 | 相关快捷键 |
+| -------- | ---------- |
+| ⭐⭐⭐⭐⭐ | `Ctrl + H` |
+
+平时,我们阅读源码的时候,经常需要查看类的层次结构。就比如我们遇到抽象类或者接口的时候,经常需要查看其被哪些类实现。
+
+拿 Spring 源码为例,`BeanDefinition` 是一个关于 Bean 属性/定义的接口。
+
+```java
+public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
+ ......
+}
+```
+
+如果我们需要查看 `BeanDefinition` 被哪些类实现的话,只需要把鼠标移动到 `BeanDefinition` 类名上,然后使用快捷键 `Ctrl + H` 即可。
+
+
+
+同理,如果你想查看接口 `BeanDefinition` 继承的接口 `AttributeAccessor` 被哪些类实现的话,只需要把鼠标移动到 `AttributeAccessor` 类名上,然后使用快捷键 `Ctrl + H` 即可。
+
+### 查看类结构
+
+| 使用频率 | 相关快捷键 |
+| -------- | ------------------------------------- |
+| ⭐⭐⭐⭐ | `Alt + 7`(Win) / `Command +7` (Mac) |
+
+类结构可以让我们快速了解到当前类的方法、变量/常量,非常使用!
+
+我们在对应的类的任意位置使用快捷键 `Alt + 7`(Win) / `Command +7` (Mac)即可。
+
+
+
+### 快速检索类
+
+| 使用频率 | 相关快捷键 |
+| -------- | ---------------------------------------- |
+| ⭐⭐⭐⭐⭐ | `Ctrl + N` (Win) / `Command + O` (Mac) |
+
+使用快捷键 `Ctrl + N` (Win) / `Command + O` (Mac)可以快速检索类/文件。
+
+
+
+### 关键字检索
+
+| 使用频率 | 相关快捷键 |
+| -------- | ---------- |
+| ⭐⭐⭐⭐⭐ | 见下文 |
+
+- 当前文件下检索 : `Ctrl + F` (Win) / `Command + F` (Mac)
+- 全局的文本检索 : `Ctrl + Shift + F` (Win) / `Command + Shift + F` (Mac)
+
+### 查看方法/类的实现类
+
+| 使用频率 | 相关快捷键 |
+| -------- | -------------------------------------------------- |
+| ⭐⭐⭐⭐ | `Ctrl + Alt + B` (Win) / `Command + Alt + B` (Mac) |
+
+如果我们想直接跳转到某个方法/类的实现类,直接在方法名或者类名上使用快捷键 `Ctrl + Alt + B/鼠标左键` (Win) / `Command + Alt + B/鼠标左键` (Mac) 即可。
+
+如果对应的方法/类只有一个实现类的话,会直接跳转到对应的实现类。
+
+比如 `BeanDefinition` 接口的 `getBeanClassName()` 方法只被 `AbstractBeanDefinition` 抽象类实现,我们对这个方法使用快捷键就可以直接跳转到 `AbstractBeanDefinition` 抽象类中对应的实现方法。
+
+```java
+public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
+ @Nullable
+ String getBeanClassName();
+ ......
+}
+```
+
+如果对应的方法/类有多个实现类的话,IDEA 会弹出一个选择框让你选择。
+
+比如 `BeanDefinition` 接口的 `getParentName()` 方法就有多个不同的实现。
+
+
+
+### 查看方法被使用的情况
+
+| 使用频率 | 相关快捷键 |
+| -------- | ---------- |
+| ⭐⭐⭐⭐ | `Alt + F7` |
+
+我们可以通过直接在方法名上使用快捷键 `Alt + F7` 来查看这个方法在哪些地方被调用过。
+
+
+
+### 查看最近使用的文件
+
+| 使用频率 | 相关快捷键 |
+| -------- | -------------------------------------- |
+| ⭐⭐⭐⭐⭐ | `Ctrl + E`(Win) / `Command +E` (Mac) |
+
+你可以通过快捷键 `Ctrl + E`(Win) / `Command +E` (Mac)来显示 IDEA 最近使用的一些文件。
+
+
+
+### 查看图表形式的类继承链
+
+| 使用频率 | 相关快捷键 |
+| -------- | ------------------------ |
+| ⭐⭐⭐⭐ | 相关快捷键较多,不建议记 |
+
+点击类名 **右键** ,选择 **Shw Diagrams** 即可查看图表形式的类继承链。
+
+
+
+你还可以对图表进行一些操作。比如,你可以点击图表中具体的类 **右键**,然后选择显示它的实现类或者父类。
+
+
+
+再比如你还可以选择是否显示类中的属性、方法、内部类等等信息。
+
+
+
+如果你想跳转到对应类的源码的话,直接点击图表中具体的类 **右键** ,然后选择 **Jump to Source** 。
+
+
+
+## 插件推荐
+
+### 一键生成方法的序列图
+
+**序列图**(Sequence Diagram),亦称为**循序图**,是一种 UML 行为图。表示系统执行某个方法/操作(如登录操作)时,对象之间的顺序调用关系。
+
+这个顺序调用关系可以这样理解:你需要执行系统中某个对象 a 提供的方法/操作 login(登录),但是这个对象又依赖了对象 b 提供的方法 getUser(获取用户)。因此,这里就有了 a -> b 调用关系之说。
+
+我们可以通过 **SequenceDiagram** 这个插件一键生成方法的序列图。
+
+> 如果你因为网络问题没办法使用 IDEA 自带的插件市场的话,也可以通过 IDEA 插件市场的官网手动下载安装。
+
+
+
+**如何使用呢?**
+
+1、选中方法名(注意不要选类名),然后点击鼠标右键,选择 **Sequence Diagram** 选项即可!
+
+
+
+2、配置生成的序列图的一些基本的参数比如调用深度之后,我们点击 ok 即可!
+
+
+
+3、你还可以通过生成的时序图来定位到相关的代码,这对于我们阅读源码的时候尤其有帮助!
+
+
+
+4、时序图生成完成之后,你还可以选择将其导出为图片。
+
+
+
+相关阅读:[《安利一个 IDEA 骚操作:一键生成方法的序列图》](https://mp.weixin.qq.com/s/SG1twZczqdup_EQAOmNERg) 。
+
+### 项目代码统计
+
+为了快速分析项目情况,我们可以对项目的 **代码的总行数、单个文件的代码行数、注释行数等信息进行统计。**
+
+**Statistic** 这个插件来帮助我们实现这一需求。
+
+
+
+有了这个插件之后你可以非常直观地看到你的项目中所有类型的文件的信息比如数量、大小等等,可以帮助你更好地了解你们的项目。
+
+
+
+你还可以使用它看所有类的总行数、有效代码行数、注释行数、以及有效代码比重等等这些东西。
+
+
+
+如果,你担心插件过多影响 IDEA 速度的话,可以只在有代码统计需求的时候开启这个插件,其他时间禁用它就完事了!
+
+相关阅读:[快速识别烂项目!试试这款项目代码统计 IDEA 插件](https://mp.weixin.qq.com/s/fVEeMW6elhu79I-rTZB40A)
+
+
+
+
+
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/exact-field.gif b/docs/idea-tutorial/idea-tips/pictures/exact/exact-field.gif
new file mode 100644
index 00000000000..770df36522d
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/exact-field.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/exact-interface.gif b/docs/idea-tutorial/idea-tips/pictures/exact/exact-interface.gif
new file mode 100644
index 00000000000..678b93de0a8
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/exact-interface.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/exact-method.gif b/docs/idea-tutorial/idea-tips/pictures/exact/exact-method.gif
new file mode 100644
index 00000000000..3748903e21d
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/exact-method.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/exact-parameter.gif b/docs/idea-tutorial/idea-tips/pictures/exact/exact-parameter.gif
new file mode 100644
index 00000000000..578b5ccca83
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/exact-parameter.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/exact-variable.gif b/docs/idea-tutorial/idea-tips/pictures/exact/exact-variable.gif
new file mode 100644
index 00000000000..7326761ef55
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/exact-variable.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/exact/extract-constant.gif b/docs/idea-tutorial/idea-tips/pictures/exact/extract-constant.gif
new file mode 100644
index 00000000000..6752a385e74
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/exact/extract-constant.gif differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/refractor-help.png b/docs/idea-tutorial/idea-tips/pictures/refractor-help.png
new file mode 100644
index 00000000000..032319487ae
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/refractor-help.png differ
diff --git a/docs/idea-tutorial/idea-tips/pictures/rename.gif b/docs/idea-tutorial/idea-tips/pictures/rename.gif
new file mode 100644
index 00000000000..c8a61b12863
Binary files /dev/null and b/docs/idea-tutorial/idea-tips/pictures/rename.gif differ
diff --git a/docs/idea-tutorial/readme.md b/docs/idea-tutorial/readme.md
new file mode 100644
index 00000000000..a5297b6bbed
--- /dev/null
+++ b/docs/idea-tutorial/readme.md
@@ -0,0 +1,11 @@
+---
+icon: creative
+category: IDEA指南
+---
+
+# IntelliJ IDEA 使用指南 | 必备插件推荐 | 插件开发入门 | 重构小技巧 | 源码阅读技巧
+
+分享一下自己使用 IDEA 的一些经验,希望对大家有帮助!
+
+- Github 地址:https://github.com/CodingDocs/awesome-idea-tutorial
+- 码云地址:https://gitee.com/SnailClimb/awesome-idea-tutorial (Github 无法访问或者访问速度比较慢的小伙伴可以看码云上的对应内容)
diff --git "a/docs/java/basis/BIO,NIO,AIO\346\200\273\347\273\223.md" "b/docs/java/basis/BIO,NIO,AIO\346\200\273\347\273\223.md"
deleted file mode 100644
index 33a7ac50873..00000000000
--- "a/docs/java/basis/BIO,NIO,AIO\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,347 +0,0 @@
-熟练掌握 BIO,NIO,AIO 的基本概念以及一些常见问题是你准备面试的过程中不可或缺的一部分,另外这些知识点也是你学习 Netty 的基础。
-
-
-
-- [BIO,NIO,AIO 总结](#bionioaio-总结)
- - [1. BIO \(Blocking I/O\)](#1-bio-blocking-io)
- - [1.1 传统 BIO](#11-传统-bio)
- - [1.2 伪异步 IO](#12-伪异步-io)
- - [1.3 代码示例](#13-代码示例)
- - [1.4 总结](#14-总结)
- - [2. NIO \(New I/O\)](#2-nio-new-io)
- - [2.1 NIO 简介](#21-nio-简介)
- - [2.2 NIO的特性/NIO与IO区别](#22-nio的特性nio与io区别)
- - [1)Non-blocking IO(非阻塞IO)](#1non-blocking-io非阻塞io)
- - [2)Buffer\(缓冲区\)](#2buffer缓冲区)
- - [3)Channel \(通道\)](#3channel-通道)
- - [4)Selectors\(选择器\)](#4selector-选择器)
- - [2.3 NIO 读数据和写数据方式](#23-nio-读数据和写数据方式)
- - [2.4 NIO核心组件简单介绍](#24-nio核心组件简单介绍)
- - [2.5 代码示例](#25-代码示例)
- - [3. AIO \(Asynchronous I/O\)](#3-aio-asynchronous-io)
- - [参考](#参考)
-
-
-
-
-# BIO,NIO,AIO 总结
-
- Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码。只需要使用Java的API就可以了。
-
-在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞。
-
-关于同步和异步的概念解读困扰着很多程序员,大部分的解读都会带有自己的一点偏见。参考了 [Stackoverflow](https://stackoverflow.com/questions/748175/asynchronous-vs-synchronous-execution-what-does-it-really-mean)相关问题后对原有答案进行了进一步完善:
-
-> When you execute something synchronously, you wait for it to finish before moving on to another task. When you execute something asynchronously, you can move on to another task before it finishes.
->
-> 当你同步执行某项任务时,你需要等待其完成才能继续执行其他任务。当您异步执行某项任务时,你可以在它完成之前继续执行其他任务。
-
-- **同步** :两个同步任务相互依赖,并且一个任务必须以依赖于另一任务的某种方式执行。 比如在`A->B`事件模型中,你需要先完成 A 才能执行B。 再换句话说,同步调用中被调用者未处理完请求之前,调用不返回,调用者会一直等待结果的返回。
-- **异步**: 两个异步的任务是完全独立的,一方的执行不需要等待另外一方的执行。再换句话说,异步调用中一调用就返回结果不需要等待结果返回,当结果返回的时候通过回调函数或者其他方式拿着结果再做相关事情。
-
-**阻塞和非阻塞**
-
-- **阻塞:** 阻塞就是发起一个请求,调用者一直等待请求结果返回,也就是当前线程会被挂起,无法从事其他任务,只有当条件就绪才能继续。
-- **非阻塞:** 非阻塞就是发起一个请求,调用者不用一直等着结果返回,可以先去干其他事情。
-
-**如何区分 “同步/异步 ”和 “阻塞/非阻塞” 呢?**
-
-同步/异步是从行为角度描述事物的,而阻塞和非阻塞描述的当前事物的状态(等待调用结果时的状态)。
-
-## 1. BIO (Blocking I/O)
-
-同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。
-
-### 1.1 传统 BIO
-
-BIO通信(一请求一应答)模型图如下(图源网络,原出处不明):
-
-
-
-采用 **BIO 通信模型** 的服务端,通常由一个独立的 Acceptor 线程负责监听客户端的连接。我们一般通过在`while(true)` 循环中服务端会调用 `accept()` 方法等待接收客户端的连接的方式监听请求,一旦接收到一个连接请求,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成, 不过可以通过多线程来支持多个客户端的连接,如上图所示。
-
-如果要让 **BIO 通信模型** 能够同时处理多个客户端请求,就必须使用多线程(主要原因是`socket.accept()`、`socket.read()`、`socket.write()` 涉及的三个主要函数都是同步阻塞的),也就是说它在接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端,线程销毁。这就是典型的 **一请求一应答通信模型** 。我们可以设想一下如果这个连接不做任何事情的话就会造成不必要的线程开销,不过可以通过 **线程池机制** 改善,线程池还可以让线程的创建和回收成本相对较低。使用`FixedThreadPool` 可以有效的控制了线程的最大数量,保证了系统有限的资源的控制,实现了N(客户端请求数量):M(处理客户端请求的线程数量)的伪异步I/O模型(N 可以远远大于 M),下面一节"伪异步 BIO"中会详细介绍到。
-
-**我们再设想一下当客户端并发访问量增加后这种模型会出现什么问题?**
-
-在 Java 虚拟机中,线程是宝贵的资源,线程的创建和销毁成本很高,除此之外,线程的切换成本也是很高的。尤其在 Linux 这样的操作系统中,线程本质上就是一个进程,创建和销毁线程都是重量级的系统函数。如果并发访问量增加会导致线程数急剧膨胀可能会导致线程堆栈溢出、创建新线程失败等问题,最终导致进程宕机或者僵死,不能对外提供服务。
-
-### 1.2 伪异步 IO
-
-为了解决同步阻塞I/O面临的一个链路需要一个线程处理的问题,后来有人对它的线程模型进行了优化一一一后端通过一个线程池来处理多个客户端的请求接入,形成客户端个数M:线程池最大线程数N的比例关系,其中M可以远远大于N.通过线程池可以灵活地调配线程资源,设置线程的最大值,防止由于海量并发接入导致线程耗尽。
-
-伪异步IO模型图(图源网络,原出处不明):
-
-
-
-采用线程池和任务队列可以实现一种叫做伪异步的 I/O 通信框架,它的模型图如上图所示。当有新的客户端接入时,将客户端的 Socket 封装成一个Task(该任务实现java.lang.Runnable接口)投递到后端的线程池中进行处理,JDK 的线程池维护一个消息队列和 N 个活跃线程,对消息队列中的任务进行处理。由于线程池可以设置消息队列的大小和最大线程数,因此,它的资源占用是可控的,无论多少个客户端并发访问,都不会导致资源的耗尽和宕机。
-
-伪异步I/O通信框架采用了线程池实现,因此避免了为每个请求都创建一个独立线程造成的线程资源耗尽问题。不过因为它的底层仍然是同步阻塞的BIO模型,因此无法从根本上解决问题。
-
-### 1.3 代码示例
-
-下面代码中演示了BIO通信(一请求一应答)模型。我们会在客户端创建多个线程依次连接服务端并向其发送"当前时间+:hello world",服务端会为每个客户端线程创建一个线程来处理。代码示例出自闪电侠的博客,原地址如下:
-
-[https://www.jianshu.com/p/a4e03835921a](https://www.jianshu.com/p/a4e03835921a)
-
-**客户端**
-
-```java
-/**
- *
- * @author 闪电侠
- * @date 2018年10月14日
- * @Description:客户端
- */
-public class IOClient {
-
- public static void main(String[] args) {
- // TODO 创建多个线程,模拟多个客户端连接服务端
- new Thread(() -> {
- try {
- Socket socket = new Socket("127.0.0.1", 3333);
- while (true) {
- try {
- socket.getOutputStream().write((new Date() + ": hello world").getBytes());
- Thread.sleep(2000);
- } catch (Exception e) {
- }
- }
- } catch (IOException e) {
- }
- }).start();
-
- }
-
-}
-
-```
-
-**服务端**
-
-```java
-/**
- * @author 闪电侠
- * @date 2018年10月14日
- * @Description: 服务端
- */
-public class IOServer {
-
- public static void main(String[] args) throws IOException {
- // TODO 服务端处理客户端连接请求
- ServerSocket serverSocket = new ServerSocket(3333);
-
- // 接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理
- new Thread(() -> {
- while (true) {
- try {
- // 阻塞方法获取新的连接
- Socket socket = serverSocket.accept();
-
- // 每一个新的连接都创建一个线程,负责读取数据
- new Thread(() -> {
- try {
- int len;
- byte[] data = new byte[1024];
- InputStream inputStream = socket.getInputStream();
- // 按字节流方式读取数据
- while ((len = inputStream.read(data)) != -1) {
- System.out.println(new String(data, 0, len));
- }
- } catch (IOException e) {
- }
- }).start();
-
- } catch (IOException e) {
- }
-
- }
- }).start();
-
- }
-
-}
-```
-
-### 1.4 总结
-
-在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池本身就是一个天然的漏斗,可以缓冲一些系统处理不了的连接或请求。但是,当面对十万甚至百万级连接的时候,传统的 BIO 模型是无能为力的。因此,我们需要一种更高效的 I/O 处理模型来应对更高的并发量。
-
-## 2. NIO (New I/O)
-
-### 2.1 NIO 简介
-
- NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。
-
-NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 `Socket` 和 `ServerSocket` 相对应的 `SocketChannel` 和 `ServerSocketChannel` 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。
-
-### 2.2 NIO的特性/NIO与IO区别
-
-如果是在面试中回答这个问题,我觉得首先肯定要从 NIO 流是非阻塞 IO 而 IO 流是阻塞 IO 说起。然后,可以从 NIO 的3个核心组件/特性为 NIO 带来的一些改进来分析。如果,你把这些都回答上了我觉得你对于 NIO 就有了更为深入一点的认识,面试官问到你这个问题,你也能很轻松的回答上来了。
-
-#### 1)Non-blocking IO(非阻塞IO)
-
-**IO流是阻塞的,NIO流是不阻塞的。**
-
-Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。
-
-Java IO的各种流是阻塞的。这意味着,当一个线程调用 `read()` 或 `write()` 时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了
-
-#### 2)Buffer(缓冲区)
-
-**IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。**
-
-Buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I/O中·可以将数据直接写入或者将数据直接读到 Stream 对象中。虽然 Stream 中也有 Buffer 开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而 NIO 却是直接读到 Buffer 中进行操作。
-
-在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。
-
-最常用的缓冲区是 ByteBuffer,一个 ByteBuffer 提供了一组功能用于操作 byte 数组。除了ByteBuffer,还有其他的一些缓冲区,事实上,每一种Java基本类型(除了Boolean类型)都对应有一种缓冲区。
-
-#### 3)Channel (通道)
-
-NIO 通过Channel(通道) 进行读写。
-
-通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。
-
-#### 4)Selector (选择器)
-
-NIO有选择器,而IO没有。
-
-选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。
-
-
-
-### 2.3 NIO 读数据和写数据方式
-通常来说NIO中的所有IO都是从 Channel(通道) 开始的。
-
-- 从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
-- 从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。
-
-数据读取和写入操作图示:
-
-
-
-
-### 2.4 NIO核心组件简单介绍
-
-NIO 包含下面几个核心的组件:
-
-- Channel(通道)
-- Buffer(缓冲区)
-- Selector(选择器)
-
-整个NIO体系包含的类远远不止这三个,只能说这三个是NIO体系的“核心API”。我们上面已经对这三个概念进行了基本的阐述,这里就不多做解释了。
-
-### 2.5 代码示例
-
-代码示例出自闪电侠的博客,原地址如下:
-
-[https://www.jianshu.com/p/a4e03835921a](https://www.jianshu.com/p/a4e03835921a)
-
-客户端 IOClient.java 的代码不变,我们对服务端使用 NIO 进行改造。以下代码较多而且逻辑比较复杂,大家看看就好。
-
-```java
-/**
- *
- * @author 闪电侠
- * @date 2019年2月21日
- * @Description: NIO 改造后的服务端
- */
-public class NIOServer {
- public static void main(String[] args) throws IOException {
- // 1. serverSelector负责轮询是否有新的连接,服务端监测到新的连接之后,不再创建一个新的线程,
- // 而是直接将新连接绑定到clientSelector上,这样就不用 IO 模型中 1w 个 while 循环在死等
- Selector serverSelector = Selector.open();
- // 2. clientSelector负责轮询连接是否有数据可读
- Selector clientSelector = Selector.open();
-
- new Thread(() -> {
- try {
- // 对应IO编程中服务端启动
- ServerSocketChannel listenerChannel = ServerSocketChannel.open();
- listenerChannel.socket().bind(new InetSocketAddress(3333));
- listenerChannel.configureBlocking(false);
- listenerChannel.register(serverSelector, SelectionKey.OP_ACCEPT);
-
- while (true) {
- // 监测是否有新的连接,这里的1指的是阻塞的时间为 1ms
- if (serverSelector.select(1) > 0) {
- Set set = serverSelector.selectedKeys();
- Iterator keyIterator = set.iterator();
-
- while (keyIterator.hasNext()) {
- SelectionKey key = keyIterator.next();
-
- if (key.isAcceptable()) {
- try {
- // (1) 每来一个新连接,不需要创建一个线程,而是直接注册到clientSelector
- SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
- clientChannel.configureBlocking(false);
- clientChannel.register(clientSelector, SelectionKey.OP_READ);
- } finally {
- keyIterator.remove();
- }
- }
-
- }
- }
- }
- } catch (IOException ignored) {
- }
- }).start();
- new Thread(() -> {
- try {
- while (true) {
- // (2) 批量轮询是否有哪些连接有数据可读,这里的1指的是阻塞的时间为 1ms
- if (clientSelector.select(1) > 0) {
- Set set = clientSelector.selectedKeys();
- Iterator keyIterator = set.iterator();
-
- while (keyIterator.hasNext()) {
- SelectionKey key = keyIterator.next();
-
- if (key.isReadable()) {
- try {
- SocketChannel clientChannel = (SocketChannel) key.channel();
- ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
- // (3) 面向 Buffer
- clientChannel.read(byteBuffer);
- byteBuffer.flip();
- System.out.println(
- Charset.defaultCharset().newDecoder().decode(byteBuffer).toString());
- } finally {
- keyIterator.remove();
- key.interestOps(SelectionKey.OP_READ);
- }
- }
-
- }
- }
- }
- } catch (IOException ignored) {
- }
- }).start();
-
- }
-}
-```
-
-为什么大家都不愿意用 JDK 原生 NIO 进行开发呢?从上面的代码中大家都可以看出来,是真的难用!除了编程复杂、编程模型难之外,它还有以下让人诟病的问题:
-
-- JDK 的 NIO 底层由 epoll 实现,该实现饱受诟病的空轮询 bug 会导致 cpu 飙升 100%
-- 项目庞大之后,自行实现的 NIO 很容易出现各类 bug,维护成本较高,上面这一坨代码我都不能保证没有 bug
-
-Netty 的出现很大程度上改善了 JDK 原生 NIO 所存在的一些让人难以忍受的问题。
-
-### 3. AIO (Asynchronous I/O)
-
-AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
-
-AIO 是异步IO的缩写,虽然 NIO 在网络操作中,提供了非阻塞的方法,但是 NIO 的 IO 行为还是同步的。对于 NIO 来说,我们的业务线程是在 IO 操作准备好时,得到通知,接着就由这个线程自行进行 IO 操作,IO操作本身是同步的。(除了 AIO 其他的 IO 类型都是同步的,这一点可以从底层IO线程模型解释,推荐一篇文章:[《漫话:如何给女朋友解释什么是Linux的五种IO模型?》](https://mp.weixin.qq.com/s?__biz=Mzg3MjA4MTExMw==&mid=2247484746&idx=1&sn=c0a7f9129d780786cabfcac0a8aa6bb7&source=41#wechat_redirect) )
-
-查阅网上相关资料,我发现就目前来说 AIO 的应用还不是很广泛,Netty 之前也尝试使用过 AIO,不过又放弃了。
-
-## 参考
-
-- 《Netty 权威指南》第二版
-- https://zhuanlan.zhihu.com/p/23488863 (美团技术团队)
diff --git "a/docs/java/basis/BigDecimal\350\247\243\345\206\263\346\265\256\347\202\271\346\225\260\350\277\220\347\256\227\347\262\276\345\272\246\344\270\242\345\244\261\351\227\256\351\242\230.md" "b/docs/java/basis/BigDecimal\350\247\243\345\206\263\346\265\256\347\202\271\346\225\260\350\277\220\347\256\227\347\262\276\345\272\246\344\270\242\345\244\261\351\227\256\351\242\230.md"
new file mode 100644
index 00000000000..5f788f087e8
--- /dev/null
+++ "b/docs/java/basis/BigDecimal\350\247\243\345\206\263\346\265\256\347\202\271\346\225\260\350\277\220\347\256\227\347\262\276\345\272\246\344\270\242\345\244\261\351\227\256\351\242\230.md"
@@ -0,0 +1,69 @@
+## BigDecimal 介绍
+
+`BigDecimal` 可以实现对浮点数的运算,不会造成精度丢失。
+
+那为什么浮点数 `float` 或 `double` 运算的时候会有精度丢失的风险呢?
+
+这是因为计算机是二进制的,浮点数没有办法用二进制精确表示。
+
+## BigDecimal 的用处
+
+《阿里巴巴Java开发手册》中提到:**浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals 来判断。** 具体原理和浮点数的编码方式有关,这里就不多提了,我们下面直接上实例:
+
+```java
+float a = 1.0f - 0.9f;
+float b = 0.9f - 0.8f;
+System.out.println(a);// 0.100000024
+System.out.println(b);// 0.099999964
+System.out.println(a == b);// false
+```
+具有基本数学知识的我们很清楚的知道输出并不是我们想要的结果(**精度丢失**),我们如何解决这个问题呢?一种很常用的方法是:**使用 BigDecimal 来定义浮点数的值,再进行浮点数的运算操作。**
+
+```java
+BigDecimal a = new BigDecimal("1.0");
+BigDecimal b = new BigDecimal("0.9");
+BigDecimal c = new BigDecimal("0.8");
+
+BigDecimal x = a.subtract(b);
+BigDecimal y = b.subtract(c);
+
+System.out.println(x); /* 0.1 */
+System.out.println(y); /* 0.1 */
+System.out.println(Objects.equals(x, y)); /* true */
+```
+
+## BigDecimal 常见方法
+
+## 大小比较
+
+`a.compareTo(b)` : 返回 -1 表示 `a` 小于 `b`,0 表示 `a` 等于 `b` , 1表示 `a` 大于 `b`。
+
+```java
+BigDecimal a = new BigDecimal("1.0");
+BigDecimal b = new BigDecimal("0.9");
+System.out.println(a.compareTo(b));// 1
+```
+### 保留几位小数
+
+通过 `setScale`方法设置保留几位小数以及保留规则。保留规则有挺多种,不需要记,IDEA会提示。
+
+```java
+BigDecimal m = new BigDecimal("1.255433");
+BigDecimal n = m.setScale(3,BigDecimal.ROUND_HALF_DOWN);
+System.out.println(n);// 1.255
+```
+
+## BigDecimal 的使用注意事项
+
+注意:我们在使用BigDecimal时,为了防止精度丢失,推荐使用它的 **BigDecimal(String)** 构造方法来创建对象。《阿里巴巴Java开发手册》对这部分内容也有提到如下图所示。
+
+
+
+## 总结
+
+BigDecimal 主要用来操作(大)浮点数,BigInteger 主要用来操作大整数(超过 long 类型)。
+
+BigDecimal 的实现利用到了 BigInteger, 所不同的是 BigDecimal 加入了小数位的概念
+
+
+
diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md" "b/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md"
deleted file mode 100644
index a1d414d4294..00000000000
--- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206\347\226\221\351\232\276\347\202\271.md"
+++ /dev/null
@@ -1,137 +0,0 @@
-## 正确使用 equals 方法
-
-Object的equals方法容易抛空指针异常,应使用常量或确定有值的对象来调用 equals。
-
-举个例子:
-
-```java
-// 不能使用一个值为null的引用类型变量来调用非静态方法,否则会抛出异常
-String str = null;
-if (str.equals("SnailClimb")) {
- ...
-} else {
- ..
-}
-```
-
-运行上面的程序会抛出空指针异常,但是我们把第二行的条件判断语句改为下面这样的话,就不会抛出空指针异常,else 语句块得到执行。:
-
-```java
-"SnailClimb".equals(str);// false
-```
-不过更推荐使用 `java.util.Objects#equals`(JDK7 引入的工具类)。
-
-```java
-Objects.equals(null,"SnailClimb");// false
-```
-我们看一下`java.util.Objects#equals`的源码就知道原因了。
-```java
-public static boolean equals(Object a, Object b) {
- // 可以避免空指针异常。如果a=null的话此时a.equals(b)就不会得到执行,避免出现空指针异常。
- return (a == b) || (a != null && a.equals(b));
-}
-```
-
-**注意:**
-
-Reference:[Java中equals方法造成空指针异常的原因及解决方案](https://blog.csdn.net/tick_tock97/article/details/72824894)
-
-- 每种原始类型都有默认值一样,如int默认值为 0,boolean 的默认值为 false,null 是任何引用类型的默认值,不严格的说是所有 Object 类型的默认值。
-- 可以使用 == 或者 != 操作来比较null值,但是不能使用其他算法或者逻辑操作。在Java中`null == null`将返回true。
-- 不能使用一个值为null的引用类型变量来调用非静态方法,否则会抛出异常
-
-## 整型包装类值的比较
-
-所有整型包装类对象值的比较必须使用equals方法。
-
-先看下面这个例子:
-
-```java
-Integer i1 = 40;
-Integer i2 = new Integer(40);
-System.out.println(i1==i2);//false
-```
-
-`Integer i1=40` 这一行代码会发生装箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。因此,输出 false 。
-
-记住:**所有整型包装类对象之间值的比较,全部使用 `equals()` 方法比较**。
-
-
-
-**注意:** 如果你的IDE(IDEA/Eclipse)上安装了阿里巴巴的p3c插件,这个插件如果检测到你用 ==的话会报错提示,推荐安装一个这个插件,很不错。
-
-## BigDecimal
-
-### BigDecimal 的用处
-
-《阿里巴巴Java开发手册》中提到:**浮点数之间的等值判断,基本数据类型不能用==来比较,包装数据类型不能用 equals 来判断。** 具体原理和浮点数的编码方式有关,这里就不多提了,我们下面直接上实例:
-
-```java
-float a = 1.0f - 0.9f;
-float b = 0.9f - 0.8f;
-System.out.println(a);// 0.100000024
-System.out.println(b);// 0.099999964
-System.out.println(a == b);// false
-```
-具有基本数学知识的我们很清楚的知道输出并不是我们想要的结果(**精度丢失**),我们如何解决这个问题呢?一种很常用的方法是:**使用 BigDecimal 来定义浮点数的值,再进行浮点数的运算操作。**
-
-```java
-BigDecimal a = new BigDecimal("1.0");
-BigDecimal b = new BigDecimal("0.9");
-BigDecimal c = new BigDecimal("0.8");
-
-BigDecimal x = a.subtract(b);
-BigDecimal y = b.subtract(c);
-
-System.out.println(x); /* 0.1 */
-System.out.println(y); /* 0.1 */
-System.out.println(Objects.equals(x, y)); /* true */
-```
-
-### BigDecimal 的大小比较
-
-`a.compareTo(b)` : 返回 -1 表示 `a` 小于 `b`,0 表示 `a` 等于 `b` , 1表示 `a` 大于 `b`。
-
-```java
-BigDecimal a = new BigDecimal("1.0");
-BigDecimal b = new BigDecimal("0.9");
-System.out.println(a.compareTo(b));// 1
-```
-### BigDecimal 保留几位小数
-
-通过 `setScale`方法设置保留几位小数以及保留规则。保留规则有挺多种,不需要记,IDEA会提示。
-
-```java
-BigDecimal m = new BigDecimal("1.255433");
-BigDecimal n = m.setScale(3,BigDecimal.ROUND_HALF_DOWN);
-System.out.println(n);// 1.255
-```
-
-### BigDecimal 的使用注意事项
-
-注意:我们在使用BigDecimal时,为了防止精度丢失,推荐使用它的 **BigDecimal(String)** 构造方法来创建对象。《阿里巴巴Java开发手册》对这部分内容也有提到如下图所示。
-
-
-
-### 总结
-
-BigDecimal 主要用来操作(大)浮点数,BigInteger 主要用来操作大整数(超过 long 类型)。
-
-BigDecimal 的实现利用到了 BigInteger, 所不同的是 BigDecimal 加入了小数位的概念
-
-## 基本数据类型与包装数据类型的使用标准
-
-Reference:《阿里巴巴Java开发手册》
-
-- 【强制】所有的 POJO 类属性必须使用包装数据类型。
-- 【强制】RPC 方法的返回值和参数必须使用包装数据类型。
-- 【推荐】所有的局部变量使用基本数据类型。
-
-比如我们如果自定义了一个Student类,其中有一个属性是成绩score,如果用Integer而不用int定义,一次考试,学生可能没考,值是null,也可能考了,但考了0分,值是0,这两个表达的状态明显不一样.
-
-**说明** :POJO 类属性没有初值是提醒使用者在需要使用时,必须自己显式地进行赋值,任何 NPE 问题,或者入库检查,都由使用者来保证。
-
-**正例** : 数据库的查询结果可能是 null,因为自动拆箱,用基本数据类型接收有 NPE 风险。
-
-**反例** : 比如显示成交总额涨跌情况,即正负 x%,x 为基本数据类型,调用的 RPC 服务,调用不成功时,返回的是默认值,页面显示为 0%,这是不合理的,应该显示成中划线。所以包装数据类型的 null 值,能够表示额外的信息,如:远程调用失败,异常退出。
-
diff --git "a/docs/java/basis/Java\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227\346\200\273\347\273\223.md" "b/docs/java/basis/Java\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227\346\200\273\347\273\223.md"
deleted file mode 100644
index 5958debc452..00000000000
--- "a/docs/java/basis/Java\345\270\270\350\247\201\345\205\263\351\224\256\345\255\227\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,352 +0,0 @@
-
-
-- [final,static,this,super 关键字总结](#finalstaticthissuper-关键字总结)
- - [final 关键字](#final-关键字)
- - [static 关键字](#static-关键字)
- - [this 关键字](#this-关键字)
- - [super 关键字](#super-关键字)
- - [参考](#参考)
-- [static 关键字详解](#static-关键字详解)
- - [static 关键字主要有以下四种使用场景](#static-关键字主要有以下四种使用场景)
- - [修饰成员变量和成员方法\(常用\)](#修饰成员变量和成员方法常用)
- - [静态代码块](#静态代码块)
- - [静态内部类](#静态内部类)
- - [静态导包](#静态导包)
- - [补充内容](#补充内容)
- - [静态方法与非静态方法](#静态方法与非静态方法)
- - [static{}静态代码块与{}非静态代码块\(构造代码块\)](#static静态代码块与非静态代码块构造代码块)
- - [参考](#参考-1)
-
-
-
-# final,static,this,super 关键字总结
-
-## final 关键字
-
-**final 关键字,意思是最终的、不可修改的,最见不得变化 ,用来修饰类、方法和变量,具有以下特点:**
-
-1. **final 修饰的类不能被继承,final 类中的所有成员方法都会被隐式的指定为 final 方法;**
-
-2. **final 修饰的方法不能被重写;**
-
-3. **final 修饰的变量是常量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能让其指向另一个对象。**
-
-说明:使用 final 方法的原因有两个。第一个原因是把方法锁定,以防任何继承类修改它的含义;第二个原因是效率。在早期的 Java 实现版本中,会将 final 方法转为内嵌调用。但是如果方法过于庞大,可能看不到内嵌调用带来的任何性能提升(现在的 Java 版本已经不需要使用 final 方法进行这些优化了)。类中所有的 private 方法都隐式地指定为 final。
-
-## static 关键字
-
-**static 关键字主要有以下四种使用场景:**
-
-1. **修饰成员变量和成员方法:** 被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被 static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。调用格式:`类名.静态变量名` `类名.静态方法名()`
-2. **静态代码块:** 静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块—>非静态代码块—>构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
-3. **静态内部类(static 修饰类的话只能修饰内部类):** 静态内部类与非静态内部类之间存在一个最大的区别: 非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:1. 它的创建是不需要依赖外围类的创建。2. 它不能使用任何外围类的非 static 成员变量和方法。
-4. **静态导包(用来导入类中的静态资源,1.5 之后的新特性):** 格式为:`import static` 这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法。
-
-## this 关键字
-
-this 关键字用于引用类的当前实例。 例如:
-
-```java
-class Manager {
- Employees[] employees;
-
- void manageEmployees() {
- int totalEmp = this.employees.length;
- System.out.println("Total employees: " + totalEmp);
- this.report();
- }
-
- void report() { }
-}
-```
-
-在上面的示例中,this 关键字用于两个地方:
-
-- this.employees.length:访问类 Manager 的当前实例的变量。
-- this.report():调用类 Manager 的当前实例的方法。
-
-此关键字是可选的,这意味着如果上面的示例在不使用此关键字的情况下表现相同。 但是,使用此关键字可能会使代码更易读或易懂。
-
-## super 关键字
-
-super 关键字用于从子类访问父类的变量和方法。 例如:
-
-```java
-public class Super {
- protected int number;
-
- protected showNumber() {
- System.out.println("number = " + number);
- }
-}
-
-public class Sub extends Super {
- void bar() {
- super.number = 10;
- super.showNumber();
- }
-}
-```
-
-在上面的例子中,Sub 类访问父类成员变量 number 并调用其父类 Super 的 `showNumber()` 方法。
-
-**使用 this 和 super 要注意的问题:**
-
-- 在构造器中使用 `super()` 调用父类中的其他构造方法时,该语句必须处于构造器的首行,否则编译器会报错。另外,this 调用本类中的其他构造方法时,也要放在首行。
-- this、super 不能用在 static 方法中。
-
-**简单解释一下:**
-
-被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享。而 this 代表对本类对象的引用,指向本类对象;而 super 代表对父类对象的引用,指向父类对象;所以, **this 和 super 是属于对象范畴的东西,而静态方法是属于类范畴的东西**。
-
-## 参考
-
-- https://www.codejava.net/java-core/the-java-language/java-keywords
-- https://blog.csdn.net/u013393958/article/details/79881037
-
-# static 关键字详解
-
-## static 关键字主要有以下四种使用场景
-
-1. 修饰成员变量和成员方法
-2. 静态代码块
-3. 修饰类(只能修饰内部类)
-4. 静态导包(用来导入类中的静态资源,1.5 之后的新特性)
-
-### 修饰成员变量和成员方法(常用)
-
-被 static 修饰的成员属于类,不属于单个这个类的某个对象,被类中所有对象共享,可以并且建议通过类名调用。被 static 声明的成员变量属于静态成员变量,静态变量 存放在 Java 内存区域的方法区。
-
-方法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做 Non-Heap(非堆),目的应该是与 Java 堆区分开来。
-
-HotSpot 虚拟机中方法区也常被称为 “永久代”,本质上两者并不等价。仅仅是因为 HotSpot 虚拟机设计团队用永久代来实现方法区而已,这样 HotSpot 虚拟机的垃圾收集器就可以像管理 Java 堆一样管理这部分内存了。但是这并不是一个好主意,因为这样更容易遇到内存溢出问题。
-
-调用格式:
-
-- `类名.静态变量名`
-- `类名.静态方法名()`
-
-如果变量或者方法被 private 则代表该属性或者该方法只能在类的内部被访问而不能在类的外部被访问。
-
-测试方法:
-
-```java
-public class StaticBean {
-
- String name;
- //静态变量
- static int age;
-
- public StaticBean(String name) {
- this.name = name;
- }
- //静态方法
- static void sayHello() {
- System.out.println("Hello i am java");
- }
- @Override
- public String toString() {
- return "StaticBean{"+
- "name=" + name + ",age=" + age +
- "}";
- }
-}
-```
-
-```java
-public class StaticDemo {
-
- public static void main(String[] args) {
- StaticBean staticBean = new StaticBean("1");
- StaticBean staticBean2 = new StaticBean("2");
- StaticBean staticBean3 = new StaticBean("3");
- StaticBean staticBean4 = new StaticBean("4");
- StaticBean.age = 33;
- System.out.println(staticBean + " " + staticBean2 + " " + staticBean3 + " " + staticBean4);
- //StaticBean{name=1,age=33} StaticBean{name=2,age=33} StaticBean{name=3,age=33} StaticBean{name=4,age=33}
- StaticBean.sayHello();//Hello i am java
- }
-
-}
-```
-
-### 静态代码块
-
-静态代码块定义在类中方法外, 静态代码块在非静态代码块之前执行(静态代码块 —> 非静态代码块 —> 构造方法)。 该类不管创建多少对象,静态代码块只执行一次.
-
-静态代码块的格式是
-
-```
-static {
-语句体;
-}
-```
-
-一个类中的静态代码块可以有多个,位置可以随便放,它不在任何的方法体内,JVM 加载类时会执行这些静态的代码块,如果静态代码块有多个,JVM 将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。
-
-
-
-静态代码块对于定义在它之后的静态变量,可以赋值,但是不能访问.
-
-### 静态内部类
-
-静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:
-
-1. 它的创建是不需要依赖外围类的创建。
-2. 它不能使用任何外围类的非 static 成员变量和方法。
-
-Example(静态内部类实现单例模式)
-
-```java
-public class Singleton {
-
- //声明为 private 避免调用默认构造方法创建对象
- private Singleton() {
- }
-
- // 声明为 private 表明静态内部该类只能在该 Singleton 类中被访问
- private static class SingletonHolder {
- private static final Singleton INSTANCE = new Singleton();
- }
-
- public static Singleton getUniqueInstance() {
- return SingletonHolder.INSTANCE;
- }
-}
-```
-
-当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 `getUniqueInstance()`方法从而触发 `SingletonHolder.INSTANCE` 时 SingletonHolder 才会被加载,此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
-
-这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
-
-### 静态导包
-
-格式为:import static
-
-这两个关键字连用可以指定导入某个类中的指定静态资源,并且不需要使用类名调用类中静态成员,可以直接使用类中静态成员变量和成员方法
-
-```java
-
-
- //将Math中的所有静态资源导入,这时候可以直接使用里面的静态方法,而不用通过类名进行调用
- //如果只想导入单一某个静态方法,只需要将*换成对应的方法名即可
-
-import static java.lang.Math.*;//换成import static java.lang.Math.max;具有一样的效果
-
-public class Demo {
- public static void main(String[] args) {
-
- int max = max(1,2);
- System.out.println(max);
- }
-}
-
-```
-
-## 补充内容
-
-### 静态方法与非静态方法
-
-静态方法属于类本身,非静态方法属于从该类生成的每个对象。 如果您的方法执行的操作不依赖于其类的各个变量和方法,请将其设置为静态(这将使程序的占用空间更小)。 否则,它应该是非静态的。
-
-Example
-
-```java
-class Foo {
- int i;
- public Foo(int i) {
- this.i = i;
- }
-
- public static String method1() {
- return "An example string that doesn't depend on i (an instance variable)";
-
- }
-
- public int method2() {
- return this.i + 1; //Depends on i
- }
-
-}
-```
-
-你可以像这样调用静态方法:`Foo.method1()`。 如果您尝试使用这种方法调用 method2 将失败。 但这样可行
-
-```java
-Foo bar = new Foo(1);
-bar.method2();
-```
-
-总结:
-
-- 在外部调用静态方法时,可以使用”类名.方法名”的方式,也可以使用”对象名.方法名”的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
-- 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制
-
-### `static{}`静态代码块与`{}`非静态代码块(构造代码块)
-
-相同点: 都是在 JVM 加载类时且在构造方法执行之前执行,在类中都可以定义多个,定义多个时按定义的顺序执行,一般在代码块中对一些 static 变量进行赋值。
-
-不同点: 静态代码块在非静态代码块之前执行(静态代码块 -> 非静态代码块 -> 构造方法)。静态代码块只在第一次 new 执行一次,之后不再执行,而非静态代码块在每 new 一次就执行一次。 非静态代码块可在普通方法中定义(不过作用不大);而静态代码块不行。
-
-> **🐛 修正(参见: [issue #677](https://github.com/Snailclimb/JavaGuide/issues/677))** :静态代码块可能在第一次 new 对象的时候执行,但不一定只在第一次 new 的时候执行。比如通过 `Class.forName("ClassDemo")`创建 Class 对象的时候也会执行,即 new 或者 `Class.forName("ClassDemo")` 都会执行静态代码块。
-
-一般情况下,如果有些代码比如一些项目最常用的变量或对象必须在项目启动的时候就执行的时候,需要使用静态代码块,这种代码是主动执行的。如果我们想要设计不需要创建对象就可以调用类中的方法,例如:`Arrays` 类,`Character` 类,`String` 类等,就需要使用静态方法, 两者的区别是 静态代码块是自动执行的而静态方法是被调用的时候才执行的.
-
-Example:
-
-```java
-public class Test {
- public Test() {
- System.out.print("默认构造方法!--");
- }
-
- //非静态代码块
- {
- System.out.print("非静态代码块!--");
- }
-
- //静态代码块
- static {
- System.out.print("静态代码块!--");
- }
-
- private static void test() {
- System.out.print("静态方法中的内容! --");
- {
- System.out.print("静态方法中的代码块!--");
- }
-
- }
-
- public static void main(String[] args) {
- Test test = new Test();
- Test.test();//静态代码块!--静态方法中的内容! --静态方法中的代码块!--
- }
-}
-```
-
-上述代码输出:
-
-```
-静态代码块!--非静态代码块!--默认构造方法!--静态方法中的内容! --静态方法中的代码块!--
-```
-
-当只执行 `Test.test();` 时输出:
-
-```
-静态代码块!--静态方法中的内容! --静态方法中的代码块!--
-```
-
-当只执行 `Test test = new Test();` 时输出:
-
-```
-静态代码块!--非静态代码块!--默认构造方法!--
-```
-
-非静态代码块与构造函数的区别是: 非静态代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化,因为构造函数是可以多个的,运行哪个构造函数就会建立什么样的对象,但无论建立哪个对象,都会先执行相同的构造代码块。也就是说,构造代码块中定义的是不同对象共性的初始化内容。
-
-### 参考
-
-- https://blog.csdn.net/chen13579867831/article/details/78995480
-- https://www.cnblogs.com/chenssy/p/3388487.html
-- https://www.cnblogs.com/Qian123/p/5713440.html
diff --git "a/docs/java/basis/IO\346\250\241\345\236\213.md" "b/docs/java/basis/io\346\250\241\345\236\213\350\257\246\350\247\243.md"
similarity index 99%
rename from "docs/java/basis/IO\346\250\241\345\236\213.md"
rename to "docs/java/basis/io\346\250\241\345\236\213\350\257\246\350\247\243.md"
index 6091a8fe4b5..231da542c35 100644
--- "a/docs/java/basis/IO\346\250\241\345\236\213.md"
+++ "b/docs/java/basis/io\346\250\241\345\236\213\350\257\246\350\247\243.md"
@@ -1,3 +1,11 @@
+---
+title: IO模型详解
+category: Java
+tag:
+ - Java基础
+---
+
+
IO 模型这块确实挺难理解的,需要太多计算机底层知识。写这篇文章用了挺久,就非常希望能把我所知道的讲出来吧!希望朋友们能有收获!为了写这篇文章,还翻看了一下《UNIX 网络编程》这本书,太难了,我滴乖乖!心痛~
_个人能力有限。如果文章有任何需要补充/完善/修改的地方,欢迎在评论区指出,共同进步!_
@@ -120,3 +128,4 @@ AIO 也就是 NIO 2。Java 7 中引入了 NIO 的改进版 NIO 2,它是异步 IO
- 10 分钟看懂, Java NIO 底层原理:https://www.cnblogs.com/crazymakercircle/p/10225159.html
- IO 模型知多少 | 理论篇:https://www.cnblogs.com/sheng-jie/p/how-much-you-know-about-io-models.html
- 《UNIX 网络编程 卷 1;套接字联网 API 》6.2 节 IO 模型
+
diff --git "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/java/basis/java\345\237\272\347\241\200\347\237\245\350\257\206\346\200\273\347\273\223.md"
similarity index 93%
rename from "docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
rename to "docs/java/basis/java\345\237\272\347\241\200\347\237\245\350\257\206\346\200\273\347\273\223.md"
index 6b04bbe5c4b..867bfb63867 100644
--- "a/docs/java/basis/Java\345\237\272\347\241\200\347\237\245\350\257\206.md"
+++ "b/docs/java/basis/java\345\237\272\347\241\200\347\237\245\350\257\206\346\200\273\347\273\223.md"
@@ -1,71 +1,9 @@
-
-
-
-
-- [基础概念与常识](#基础概念与常识)
- - [Java 语言有哪些特点?](#java-语言有哪些特点)
- - [JVM vs JDK vs JRE](#jvm-vs-jdk-vs-jre)
- - [JVM](#jvm)
- - [JDK 和 JRE](#jdk-和-jre)
- - [为什么说 Java 语言“编译与解释并存”?](#为什么说-java-语言编译与解释并存)
- - [Oracle JDK 和 OpenJDK 的对比](#oracle-jdk-和-openjdk-的对比)
- - [Java 和 C++的区别?](#java-和-c的区别)
- - [import java 和 javax 有什么区别?](#import-java-和-javax-有什么区别)
-- [基本语法](#基本语法)
- - [字符型常量和字符串常量的区别?](#字符型常量和字符串常量的区别)
- - [注释](#注释)
- - [标识符和关键字的区别是什么?](#标识符和关键字的区别是什么)
- - [Java 中有哪些常见的关键字?](#java-中有哪些常见的关键字)
- - [自增自减运算符](#自增自减运算符)
- - [continue、break、和 return 的区别是什么?](#continue-break-和-return-的区别是什么)
- - [Java 泛型了解么?什么是类型擦除?介绍一下常用的通配符?](#java-泛型了解么什么是类型擦除介绍一下常用的通配符)
- - [==和 equals 的区别](#和-equals-的区别)
- - [hashCode()与 equals()](#hashcode与-equals)
-- [基本数据类型](#基本数据类型)
- - [Java 中的几种基本数据类型是什么?对应的包装类型是什么?各自占用多少字节呢?](#java-中的几种基本数据类型是什么对应的包装类型是什么各自占用多少字节呢)
- - [自动装箱与拆箱](#自动装箱与拆箱)
- - [8 种基本类型的包装类和常量池](#8-种基本类型的包装类和常量池)
-- [方法(函数)](#方法函数)
- - [什么是方法的返回值?](#什么是方法的返回值)
- - [方法有哪几种类型?](#方法有哪几种类型)
- - [在一个静态方法内调用一个非静态成员为什么是非法的?](#在一个静态方法内调用一个非静态成员为什么是非法的)
- - [静态方法和实例方法有何不同?](#静态方法和实例方法有何不同)
- - [为什么 Java 中只有值传递?](#为什么-java-中只有值传递)
- - [重载和重写的区别](#重载和重写的区别)
- - [重载](#重载)
- - [重写](#重写)
- - [深拷贝 vs 浅拷贝](#深拷贝-vs-浅拷贝)
-- [Java 面向对象](#java-面向对象)
- - [面向对象和面向过程的区别](#面向对象和面向过程的区别)
- - [成员变量与局部变量的区别有哪些?](#成员变量与局部变量的区别有哪些)
- - [创建一个对象用什么运算符?对象实体与对象引用有何不同?](#创建一个对象用什么运算符对象实体与对象引用有何不同)
- - [对象的相等与指向他们的引用相等,两者有什么不同?](#对象的相等与指向他们的引用相等两者有什么不同)
- - [一个类的构造方法的作用是什么? 若一个类没有声明构造方法,该程序能正确执行吗? 为什么?](#一个类的构造方法的作用是什么-若一个类没有声明构造方法该程序能正确执行吗-为什么)
- - [构造方法有哪些特点?是否可被 override?](#构造方法有哪些特点是否可被-override)
- - [面向对象三大特征](#面向对象三大特征)
- - [封装](#封装)
- - [继承](#继承)
- - [多态](#多态)
- - [String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?](#string-stringbuffer-和-stringbuilder-的区别是什么-string-为什么是不可变的)
- - [Object 类的常见方法总结](#object-类的常见方法总结)
-- [反射](#反射)
- - [何为反射?](#何为反射)
- - [反射机制优缺点](#反射机制优缺点)
- - [反射的应用场景](#反射的应用场景)
-- [异常](#异常)
- - [Java 异常类层次结构图](#java-异常类层次结构图)
- - [Throwable 类常用方法](#throwable-类常用方法)
- - [try-catch-finally](#try-catch-finally)
- - [使用 `try-with-resources` 来代替`try-catch-finally`](#使用-try-with-resources-来代替try-catch-finally)
-- [I\O 流](#io-流)
- - [什么是序列化?什么是反序列化?](#什么是序列化什么是反序列化)
- - [Java 序列化中如果有些字段不想进行序列化,怎么办?](#java-序列化中如果有些字段不想进行序列化怎么办)
- - [获取用键盘输入常用的两种方法](#获取用键盘输入常用的两种方法)
- - [Java 中 IO 流分为几种?](#java-中-io-流分为几种)
- - [既然有了字节流,为什么还要有字符流?](#既然有了字节流为什么还要有字符流)
-- [4. 参考](#4-参考)
-
-
+---
+title: Java基础知识&面试题总结
+category: Java
+tag:
+ - Java基础
+---
## 基础概念与常识
@@ -1428,8 +1366,9 @@ Java IO 流共涉及 40 多个类,这些类看上去很杂乱,但实际上
回答:字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还算是非常耗时,并且,如果我们不知道编码类型就很容易出现乱码问题。所以, I/O 流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。
-## 4. 参考
+## 参考
- https://stackoverflow.com/questions/1906445/what-is-the-difference-between-jdk-and-jre
- https://www.educba.com/oracle-vs-openjdk/
- https://stackoverflow.com/questions/22358071/differences-between-oracle-jdk-and-openjdk 基础概念与常识
+
diff --git "a/docs/java/basis/\344\273\243\347\220\206\346\250\241\345\274\217\350\257\246\350\247\243.md" "b/docs/java/basis/\344\273\243\347\220\206\346\250\241\345\274\217\350\257\246\350\247\243.md"
index 8106d30503e..0006caed0aa 100644
--- "a/docs/java/basis/\344\273\243\347\220\206\346\250\241\345\274\217\350\257\246\350\247\243.md"
+++ "b/docs/java/basis/\344\273\243\347\220\206\346\250\241\345\274\217\350\257\246\350\247\243.md"
@@ -1,26 +1,9 @@
-> 本文首更于[《从零开始手把手教你实现一个简单的RPC框架》](https://t.zsxq.com/iIUv7Mn) 。
-
-
-
-
-
-- [1. 代理模式](#1-代理模式)
-- [2. 静态代理](#2-静态代理)
-- [3. 动态代理](#3-动态代理)
- - [3.1. JDK 动态代理机制](#31-jdk-动态代理机制)
- - [3.1.1. 介绍](#311-介绍)
- - [3.1.2. JDK 动态代理类使用步骤](#312-jdk-动态代理类使用步骤)
- - [3.1.3. 代码示例](#313-代码示例)
- - [3.2. CGLIB 动态代理机制](#32-cglib-动态代理机制)
- - [3.2.1. 介绍](#321-介绍)
- - [3.2.2. CGLIB 动态代理类使用步骤](#322-cglib-动态代理类使用步骤)
- - [3.2.3. 代码示例](#323-代码示例)
- - [3.3. JDK 动态代理和 CGLIB 动态代理对比](#33-jdk-动态代理和-cglib-动态代理对比)
-- [4. 静态代理和动态代理的对比](#4-静态代理和动态代理的对比)
-- [5. 总结](#5-总结)
-
-
-
+---
+title: 代理详解!静态代理+JDK/CGLIB 动态代理实战
+category: Java
+tag:
+ - Java基础
+---
## 1. 代理模式
@@ -418,3 +401,4 @@ after method send
这篇文章中主要介绍了代理模式的两种实现:静态代理以及动态代理。涵盖了静态代理和动态代理实战、静态代理和动态代理的区别、JDK 动态代理和 Cglib 动态代理区别等内容。
文中涉及到的所有源码,你可以在这里找到:[https://github.com/Snailclimb/guide-rpc-framework-learning/tree/master/src/main/java/github/javaguide/proxy](https://github.com/Snailclimb/guide-rpc-framework-learning/tree/master/src/main/java/github/javaguide/proxy) 。
+
diff --git "a/docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266.md" "b/docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266\350\257\246\350\247\243.md"
similarity index 98%
rename from "docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266.md"
rename to "docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266\350\257\246\350\247\243.md"
index d6fe42631a5..cac029638e4 100644
--- "a/docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266.md"
+++ "b/docs/java/basis/\345\217\215\345\260\204\346\234\272\345\210\266\350\257\246\350\247\243.md"
@@ -1,3 +1,10 @@
+---
+title: 反射机制详解!
+category: Java
+tag:
+ - Java基础
+---
+
## 何为反射?
如果说大家研究过框架的底层原理或者咱们自己写过框架的话,一定对反射这个概念不陌生。
@@ -87,8 +94,6 @@ Class clazz = ClassLoader.loadClass("cn.javaguide.TargetObject");
### 反射的一些基本操作
-**简单用代码演示一下反射的一些操作!**
-
1.创建一个我们要使用反射操作的类 `TargetObject`。
```java
@@ -174,3 +179,4 @@ value is JavaGuide
```java
Class> tagetClass = Class.forName("cn.javaguide.TargetObject");
```
+
diff --git "a/docs/java/basis/\347\224\250\345\245\275Java\344\270\255\347\232\204\346\236\232\344\270\276\347\234\237\347\232\204\346\262\241\346\234\211\351\202\243\344\271\210\347\256\200\345\215\225.md" "b/docs/java/basis/\347\224\250\345\245\275Java\344\270\255\347\232\204\346\236\232\344\270\276\347\234\237\347\232\204\346\262\241\346\234\211\351\202\243\344\271\210\347\256\200\345\215\225.md"
deleted file mode 100644
index c17fcba98fe..00000000000
--- "a/docs/java/basis/\347\224\250\345\245\275Java\344\270\255\347\232\204\346\236\232\344\270\276\347\234\237\347\232\204\346\262\241\346\234\211\351\202\243\344\271\210\347\256\200\345\215\225.md"
+++ /dev/null
@@ -1,557 +0,0 @@
-> 最近重看 Java 枚举,看到这篇觉得还不错的文章,于是简单翻译和完善了一些内容,分享给大家,希望你们也能有所收获。另外,不要忘了文末还有补充哦!
->
-> ps: 这里发一篇枚举的文章,也是因为后面要发一篇非常实用的关于 SpringBoot 全局异常处理的比较好的实践,里面就用到了枚举。
->
-> 这篇文章由 JavaGuide 翻译,公众号: JavaGuide,原文地址:https://www.baeldung.com/a-guide-to-java-enums 。
->
-> 转载请注明上面这段文字。
-
-## 1.概览
-
-在本文中,我们将看到什么是 Java 枚举,它们解决了哪些问题以及如何在实践中使用 Java 枚举实现一些设计模式。
-
-enum关键字在 java5 中引入,表示一种特殊类型的类,其总是继承java.lang.Enum类,更多内容可以自行查看其[官方文档](https://docs.oracle.com/javase/6/docs/api/java/lang/Enum.html)。
-
-枚举在很多时候会和常量拿来对比,可能因为本身我们大量实际使用枚举的地方就是为了替代常量。那么这种方式有什么优势呢?
-
-**以这种方式定义的常量使代码更具可读性,允许进行编译时检查,预先记录可接受值的列表,并避免由于传入无效值而引起的意外行为。**
-
-下面示例定义一个简单的枚举类型 pizza 订单的状态,共有三种 ORDERED, READY, DELIVERED状态:
-
-```java
-package shuang.kou.enumdemo.enumtest;
-
-public enum PizzaStatus {
- ORDERED,
- READY,
- DELIVERED;
-}
-```
-
-**简单来说,我们通过上面的代码避免了定义常量,我们将所有和 pizza 订单的状态的常量都统一放到了一个枚举类型里面。**
-
-```java
-System.out.println(PizzaStatus.ORDERED.name());//ORDERED
-System.out.println(PizzaStatus.ORDERED);//ORDERED
-System.out.println(PizzaStatus.ORDERED.name().getClass());//class java.lang.String
-System.out.println(PizzaStatus.ORDERED.getClass());//class shuang.kou.enumdemo.enumtest.PizzaStatus
-```
-
-## 2.自定义枚举方法
-
-现在我们对枚举是什么以及如何使用它们有了基本的了解,让我们通过在枚举上定义一些额外的API方法,将上一个示例提升到一个新的水平:
-
-```java
-public class Pizza {
- private PizzaStatus status;
- public enum PizzaStatus {
- ORDERED,
- READY,
- DELIVERED;
- }
-
- public boolean isDeliverable() {
- return getStatus() == PizzaStatus.READY;
- }
-
- // Methods that set and get the status variable.
-}
-```
-
-## 3.使用 == 比较枚举类型
-
-由于枚举类型确保JVM中仅存在一个常量实例,因此我们可以安全地使用 `==` 运算符比较两个变量,如上例所示;此外,`==` 运算符可提供编译时和运行时的安全性。
-
-首先,让我们看一下以下代码段中的运行时安全性,其中 `==` 运算符用于比较状态,并且如果两个值均为null 都不会引发 NullPointerException。相反,如果使用equals方法,将抛出 NullPointerException:
-
-```java
-Pizza.PizzaStatus pizza = null;
-System.out.println(pizza.equals(Pizza.PizzaStatus.DELIVERED));//空指针异常
-System.out.println(pizza == Pizza.PizzaStatus.DELIVERED);//正常运行
-```
-
-对于编译时安全性,我们看另一个示例,两个不同枚举类型进行比较:
-
-```java
-if (Pizza.PizzaStatus.DELIVERED.equals(TestColor.GREEN)); // 编译正常
-if (Pizza.PizzaStatus.DELIVERED == TestColor.GREEN); // 编译失败,类型不匹配
-```
-
-## 4.在 switch 语句中使用枚举类型
-
-```java
-public int getDeliveryTimeInDays() {
- switch (status) {
- case ORDERED:
- return 5;
- case READY:
- return 2;
- case DELIVERED:
- return 0;
- }
- return 0;
-}
-```
-
-## 5.枚举类型的属性,方法和构造函数
-
-> 文末有我(JavaGuide)的补充。
-
-你可以通过在枚举类型中定义属性,方法和构造函数让它变得更加强大。
-
-下面,让我们扩展上面的示例,实现从比萨的一个阶段到另一个阶段的过渡,并了解如何摆脱之前使用的if语句和switch语句:
-
-```java
-public class Pizza {
-
- private PizzaStatus status;
- public enum PizzaStatus {
- ORDERED (5){
- @Override
- public boolean isOrdered() {
- return true;
- }
- },
- READY (2){
- @Override
- public boolean isReady() {
- return true;
- }
- },
- DELIVERED (0){
- @Override
- public boolean isDelivered() {
- return true;
- }
- };
-
- private int timeToDelivery;
-
- public boolean isOrdered() {return false;}
-
- public boolean isReady() {return false;}
-
- public boolean isDelivered(){return false;}
-
- public int getTimeToDelivery() {
- return timeToDelivery;
- }
-
- PizzaStatus (int timeToDelivery) {
- this.timeToDelivery = timeToDelivery;
- }
- }
-
- public boolean isDeliverable() {
- return this.status.isReady();
- }
-
- public void printTimeToDeliver() {
- System.out.println("Time to delivery is " +
- this.getStatus().getTimeToDelivery());
- }
-
- // Methods that set and get the status variable.
-}
-```
-
-下面这段代码展示它是如何 work 的:
-
-```java
-@Test
-public void givenPizaOrder_whenReady_thenDeliverable() {
- Pizza testPz = new Pizza();
- testPz.setStatus(Pizza.PizzaStatus.READY);
- assertTrue(testPz.isDeliverable());
-}
-```
-
-## 6.EnumSet and EnumMap
-
-### 6.1. EnumSet
-
-`EnumSet` 是一种专门为枚举类型所设计的 `Set` 类型。
-
-与`HashSet`相比,由于使用了内部位向量表示,因此它是特定 `Enum` 常量集的非常有效且紧凑的表示形式。
-
-它提供了类型安全的替代方法,以替代传统的基于int的“位标志”,使我们能够编写更易读和易于维护的简洁代码。
-
-`EnumSet` 是抽象类,其有两个实现:`RegularEnumSet` 、`JumboEnumSet`,选择哪一个取决于实例化时枚举中常量的数量。
-
-在很多场景中的枚举常量集合操作(如:取子集、增加、删除、`containsAll`和`removeAll`批操作)使用`EnumSet`非常合适;如果需要迭代所有可能的常量则使用`Enum.values()`。
-
-```java
-public class Pizza {
-
- private static EnumSet undeliveredPizzaStatuses =
- EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
-
- private PizzaStatus status;
-
- public enum PizzaStatus {
- ...
- }
-
- public boolean isDeliverable() {
- return this.status.isReady();
- }
-
- public void printTimeToDeliver() {
- System.out.println("Time to delivery is " +
- this.getStatus().getTimeToDelivery() + " days");
- }
-
- public static List getAllUndeliveredPizzas(List input) {
- return input.stream().filter(
- (s) -> undeliveredPizzaStatuses.contains(s.getStatus()))
- .collect(Collectors.toList());
- }
-
- public void deliver() {
- if (isDeliverable()) {
- PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
- .deliver(this);
- this.setStatus(PizzaStatus.DELIVERED);
- }
- }
-
- // Methods that set and get the status variable.
-}
-```
-
- 下面的测试展示了 `EnumSet` 在某些场景下的强大功能:
-
-```java
-@Test
-public void givenPizaOrders_whenRetrievingUnDeliveredPzs_thenCorrectlyRetrieved() {
- List pzList = new ArrayList<>();
- Pizza pz1 = new Pizza();
- pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
-
- Pizza pz2 = new Pizza();
- pz2.setStatus(Pizza.PizzaStatus.ORDERED);
-
- Pizza pz3 = new Pizza();
- pz3.setStatus(Pizza.PizzaStatus.ORDERED);
-
- Pizza pz4 = new Pizza();
- pz4.setStatus(Pizza.PizzaStatus.READY);
-
- pzList.add(pz1);
- pzList.add(pz2);
- pzList.add(pz3);
- pzList.add(pz4);
-
- List undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
- assertTrue(undeliveredPzs.size() == 3);
-}
-```
-
-### 6.2. EnumMap
-
-`EnumMap`是一个专门化的映射实现,用于将枚举常量用作键。与对应的 `HashMap` 相比,它是一个高效紧凑的实现,并且在内部表示为一个数组:
-
-```java
-EnumMap map;
-```
-
-让我们快速看一个真实的示例,该示例演示如何在实践中使用它:
-
-```java
-Iterator iterator = pizzaList.iterator();
-while (iterator.hasNext()) {
- Pizza pz = iterator.next();
- PizzaStatus status = pz.getStatus();
- if (pzByStatus.containsKey(status)) {
- pzByStatus.get(status).add(pz);
- } else {
- List newPzList = new ArrayList<>();
- newPzList.add(pz);
- pzByStatus.put(status, newPzList);
- }
-}
-```
-
- 下面的测试展示了 `EnumMap` 在某些场景下的强大功能:
-
-```java
-@Test
-public void givenPizaOrders_whenGroupByStatusCalled_thenCorrectlyGrouped() {
- List pzList = new ArrayList<>();
- Pizza pz1 = new Pizza();
- pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
-
- Pizza pz2 = new Pizza();
- pz2.setStatus(Pizza.PizzaStatus.ORDERED);
-
- Pizza pz3 = new Pizza();
- pz3.setStatus(Pizza.PizzaStatus.ORDERED);
-
- Pizza pz4 = new Pizza();
- pz4.setStatus(Pizza.PizzaStatus.READY);
-
- pzList.add(pz1);
- pzList.add(pz2);
- pzList.add(pz3);
- pzList.add(pz4);
-
- EnumMap> map = Pizza.groupPizzaByStatus(pzList);
- assertTrue(map.get(Pizza.PizzaStatus.DELIVERED).size() == 1);
- assertTrue(map.get(Pizza.PizzaStatus.ORDERED).size() == 2);
- assertTrue(map.get(Pizza.PizzaStatus.READY).size() == 1);
-}
-```
-
-## 7. 通过枚举实现一些设计模式
-
-### 7.1 单例模式
-
-通常,使用类实现 Singleton 模式并非易事,枚举提供了一种实现单例的简便方法。
-
-《Effective Java 》和《Java与模式》都非常推荐这种方式,使用这种方式实现枚举可以有什么好处呢?
-
-《Effective Java》
-
-> 这种方法在功能上与公有域方法相近,但是它更加简洁,无偿提供了序列化机制,绝对防止多次实例化,即使是在面对复杂序列化或者反射攻击的时候。虽然这种方法还没有广泛采用,但是单元素的枚举类型已经成为实现 Singleton的最佳方法。 —-《Effective Java 中文版 第二版》
-
-《Java与模式》
-
-> 《Java与模式》中,作者这样写道,使用枚举来实现单实例控制会更加简洁,而且无偿地提供了序列化机制,并由JVM从根本上提供保障,绝对防止多次实例化,是更简洁、高效、安全的实现单例的方式。
-
-下面的代码段显示了如何使用枚举实现单例模式:
-
-```java
-public enum PizzaDeliverySystemConfiguration {
- INSTANCE;
- PizzaDeliverySystemConfiguration() {
- // Initialization configuration which involves
- // overriding defaults like delivery strategy
- }
-
- private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
-
- public static PizzaDeliverySystemConfiguration getInstance() {
- return INSTANCE;
- }
-
- public PizzaDeliveryStrategy getDeliveryStrategy() {
- return deliveryStrategy;
- }
-}
-```
-
-如何使用呢?请看下面的代码:
-
-```java
-PizzaDeliveryStrategy deliveryStrategy = PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy();
-```
-
-通过 `PizzaDeliverySystemConfiguration.getInstance()` 获取的就是单例的 `PizzaDeliverySystemConfiguration`
-
-### 7.2 策略模式
-
-通常,策略模式由不同类实现同一个接口来实现的。
-
- 这也就意味着添加新策略意味着添加新的实现类。使用枚举,可以轻松完成此任务,添加新的实现意味着只定义具有某个实现的另一个实例。
-
-下面的代码段显示了如何使用枚举实现策略模式:
-
-```java
-public enum PizzaDeliveryStrategy {
- EXPRESS {
- @Override
- public void deliver(Pizza pz) {
- System.out.println("Pizza will be delivered in express mode");
- }
- },
- NORMAL {
- @Override
- public void deliver(Pizza pz) {
- System.out.println("Pizza will be delivered in normal mode");
- }
- };
-
- public abstract void deliver(Pizza pz);
-}
-```
-
-给 `Pizza `增加下面的方法:
-
-```java
-public void deliver() {
- if (isDeliverable()) {
- PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy()
- .deliver(this);
- this.setStatus(PizzaStatus.DELIVERED);
- }
-}
-```
-
-如何使用呢?请看下面的代码:
-
-```java
-@Test
-public void givenPizaOrder_whenDelivered_thenPizzaGetsDeliveredAndStatusChanges() {
- Pizza pz = new Pizza();
- pz.setStatus(Pizza.PizzaStatus.READY);
- pz.deliver();
- assertTrue(pz.getStatus() == Pizza.PizzaStatus.DELIVERED);
-}
-```
-
-## 8. Java 8 与枚举
-
-Pizza 类可以用Java 8重写,您可以看到方法 lambda 和Stream API如何使 `getAllUndeliveredPizzas()`和`groupPizzaByStatus()`方法变得如此简洁:
-
-`getAllUndeliveredPizzas()`:
-
-```java
-public static List getAllUndeliveredPizzas(List input) {
- return input.stream().filter(
- (s) -> !deliveredPizzaStatuses.contains(s.getStatus()))
- .collect(Collectors.toList());
-}
-```
-
-`groupPizzaByStatus()` :
-
-```java
-public static EnumMap>
- groupPizzaByStatus(List pzList) {
- EnumMap> map = pzList.stream().collect(
- Collectors.groupingBy(Pizza::getStatus,
- () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
- return map;
-}
-```
-
-## 9. Enum 类型的 JSON 表现形式
-
-使用Jackson库,可以将枚举类型的JSON表示为POJO。下面的代码段显示了可以用于同一目的的Jackson批注:
-
-```java
-@JsonFormat(shape = JsonFormat.Shape.OBJECT)
-public enum PizzaStatus {
- ORDERED (5){
- @Override
- public boolean isOrdered() {
- return true;
- }
- },
- READY (2){
- @Override
- public boolean isReady() {
- return true;
- }
- },
- DELIVERED (0){
- @Override
- public boolean isDelivered() {
- return true;
- }
- };
-
- private int timeToDelivery;
-
- public boolean isOrdered() {return false;}
-
- public boolean isReady() {return false;}
-
- public boolean isDelivered(){return false;}
-
- @JsonProperty("timeToDelivery")
- public int getTimeToDelivery() {
- return timeToDelivery;
- }
-
- private PizzaStatus (int timeToDelivery) {
- this.timeToDelivery = timeToDelivery;
- }
-}
-```
-
-我们可以按如下方式使用 `Pizza` 和 `PizzaStatus`:
-
-```java
-Pizza pz = new Pizza();
-pz.setStatus(Pizza.PizzaStatus.READY);
-System.out.println(Pizza.getJsonString(pz));
-```
-
-生成 Pizza 状态以以下JSON展示:
-
-```json
-{
- "status" : {
- "timeToDelivery" : 2,
- "ready" : true,
- "ordered" : false,
- "delivered" : false
- },
- "deliverable" : true
-}
-```
-
-有关枚举类型的JSON序列化/反序列化(包括自定义)的更多信息,请参阅[Jackson-将枚举序列化为JSON对象。](https://www.baeldung.com/jackson-serialize-enums)
-
-## 10.总结
-
-本文我们讨论了Java枚举类型,从基础知识到高级应用以及实际应用场景,让我们感受到枚举的强大功能。
-
-## 11. 补充
-
-我们在上面讲到了,我们可以通过在枚举类型中定义属性,方法和构造函数让它变得更加强大。
-
-下面我通过一个实际的例子展示一下,当我们调用短信验证码的时候可能有几种不同的用途,我们在下面这样定义:
-
-```java
-
-public enum PinType {
-
- REGISTER(100000, "注册使用"),
- FORGET_PASSWORD(100001, "忘记密码使用"),
- UPDATE_PHONE_NUMBER(100002, "更新手机号码使用");
-
- private final int code;
- private final String message;
-
- PinType(int code, String message) {
- this.code = code;
- this.message = message;
- }
-
- public int getCode() {
- return code;
- }
-
- public String getMessage() {
- return message;
- }
-
- @Override
- public String toString() {
- return "PinType{" +
- "code=" + code +
- ", message='" + message + '\'' +
- '}';
- }
-}
-```
-
-实际使用:
-
- ```java
-System.out.println(PinType.FORGET_PASSWORD.getCode());
-System.out.println(PinType.FORGET_PASSWORD.getMessage());
-System.out.println(PinType.FORGET_PASSWORD.toString());
- ```
-
-Output:
-
-```java
-100001
-忘记密码使用
-PinType{code=100001, message='忘记密码使用'}
-```
-
-这样的话,在实际使用起来就会非常灵活方便!
diff --git "a/docs/java/collection/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md" "b/docs/java/collection/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md"
deleted file mode 100644
index a8159a34367..00000000000
--- "a/docs/java/collection/LinkedList\346\272\220\347\240\201\345\210\206\346\236\220.md"
+++ /dev/null
@@ -1,517 +0,0 @@
-
-
-
-- [简介](#简介)
-- [内部结构分析](#内部结构分析)
-- [LinkedList源码分析](#linkedlist源码分析)
- - [构造方法](#构造方法)
- - [添加(add)方法](#add方法)
- - [根据位置取数据的方法](#根据位置取数据的方法)
- - [根据对象得到索引的方法](#根据对象得到索引的方法)
- - [检查链表是否包含某对象的方法:](#检查链表是否包含某对象的方法:)
- - [删除(remove/pop)方法](#删除方法)
-- [LinkedList类常用方法测试:](#linkedlist类常用方法测试)
-
-
-
-## 简介
-LinkedList 是一个实现了List接口 和Deque接口 的双端链表 。
-LinkedList底层的链表结构使它支持高效的插入和删除操作 ,另外它实现了Deque接口,使得LinkedList类也具有队列的特性;
-LinkedList不是线程安全的 ,如果想使LinkedList变成线程安全的,可以调用静态类Collections类 中的synchronizedList 方法:
-```java
-List list=Collections.synchronizedList(new LinkedList(...));
-```
-## 内部结构分析
-**如下图所示:**
-
-
-看完了图之后,我们再看LinkedList类中的一个**内部私有类Node** 就很好理解了:
-
-```java
-private static class Node {
- E item;//节点值
- Node next;//后继节点
- Node prev;//前驱节点
-
- Node(Node prev, E element, Node next) {
- this.item = element;
- this.next = next;
- this.prev = prev;
- }
- }
-```
-这个类就代表双端链表的节点Node。这个类有三个属性,分别是前驱节点,本节点的值,后继结点。
-
-## LinkedList源码分析
-### 构造方法
-**空构造方法:**
-```java
- public LinkedList() {
- }
-```
-**用已有的集合创建链表的构造方法:**
-```java
- public LinkedList(Collection extends E> c) {
- this();
- addAll(c);
- }
-```
-### add方法
-**add(E e)** 方法:将元素添加到链表尾部
-```java
-public boolean add(E e) {
- linkLast(e);//这里就只调用了这一个方法
- return true;
- }
-```
-
-```java
- /**
- * 链接使e作为最后一个元素。
- */
- void linkLast(E e) {
- final Node l = last;
- final Node newNode = new Node<>(l, e, null);
- last = newNode;//新建节点
- if (l == null)
- first = newNode;
- else
- l.next = newNode;//指向后继元素也就是指向下一个元素
- size++;
- modCount++;
- }
-```
-**add(int index,E e)**:在指定位置添加元素
-```java
-public void add(int index, E element) {
- checkPositionIndex(index); //检查索引是否处于[0-size]之间
-
- if (index == size)//添加在链表尾部
- linkLast(element);
- else//添加在链表中间
- linkBefore(element, node(index));
- }
-```
-linkBefore方法 需要给定两个参数,一个插入节点的值 ,一个指定的node ,所以我们又调用了Node(index)去找到index对应的node
-
-**addAll(Collection c ):将集合插入到链表尾部**
-
-```java
-public boolean addAll(Collection extends E> c) {
- return addAll(size, c);
- }
-```
-**addAll(int index, Collection c):** 将集合从指定位置开始插入
-```java
-public boolean addAll(int index, Collection extends E> c) {
- //1:检查index范围是否在size之内
- checkPositionIndex(index);
-
- //2:toArray()方法把集合的数据存到对象数组中
- Object[] a = c.toArray();
- int numNew = a.length;
- if (numNew == 0)
- return false;
-
- //3:得到插入位置的前驱节点和后继节点
- Node pred, succ;
- //如果插入位置为尾部,前驱节点为last,后继节点为null
- if (index == size) {
- succ = null;
- pred = last;
- }
- //否则,调用node()方法得到后继节点,再得到前驱节点
- else {
- succ = node(index);
- pred = succ.prev;
- }
-
- // 4:遍历数据将数据插入
- for (Object o : a) {
- @SuppressWarnings("unchecked") E e = (E) o;
- //创建新节点
- Node newNode = new Node<>(pred, e, null);
- //如果插入位置在链表头部
- if (pred == null)
- first = newNode;
- else
- pred.next = newNode;
- pred = newNode;
- }
-
- //如果插入位置在尾部,重置last节点
- if (succ == null) {
- last = pred;
- }
- //否则,将插入的链表与先前链表连接起来
- else {
- pred.next = succ;
- succ.prev = pred;
- }
-
- size += numNew;
- modCount++;
- return true;
- }
-```
-上面可以看出addAll方法通常包括下面四个步骤:
-1. 检查index范围是否在size之内
-2. toArray()方法把集合的数据存到对象数组中
-3. 得到插入位置的前驱和后继节点
-4. 遍历数据,将数据插入到指定位置
-
-**addFirst(E e):** 将元素添加到链表头部
-```java
- public void addFirst(E e) {
- linkFirst(e);
- }
-```
-```java
-private void linkFirst(E e) {
- final Node f = first;
- final Node newNode = new Node<>(null, e, f);//新建节点,以头节点为后继节点
- first = newNode;
- //如果链表为空,last节点也指向该节点
- if (f == null)
- last = newNode;
- //否则,将头节点的前驱指针指向新节点,也就是指向前一个元素
- else
- f.prev = newNode;
- size++;
- modCount++;
- }
-```
-**addLast(E e):** 将元素添加到链表尾部,与 **add(E e)** 方法一样
-```java
-public void addLast(E e) {
- linkLast(e);
- }
-```
-### 根据位置取数据的方法
-**get(int index):** 根据指定索引返回数据
-```java
-public E get(int index) {
- //检查index范围是否在size之内
- checkElementIndex(index);
- //调用Node(index)去找到index对应的node然后返回它的值
- return node(index).item;
- }
-```
-**获取头节点(index=0)数据方法:**
-```java
-public E getFirst() {
- final Node f = first;
- if (f == null)
- throw new NoSuchElementException();
- return f.item;
- }
-public E element() {
- return getFirst();
- }
-public E peek() {
- final Node f = first;
- return (f == null) ? null : f.item;
- }
-
-public E peekFirst() {
- final Node f = first;
- return (f == null) ? null : f.item;
- }
-```
-**区别:**
-getFirst(),element(),peek(),peekFirst()
-这四个获取头结点方法的区别在于对链表为空时的处理,是抛出异常还是返回null,其中**getFirst()** 和**element()** 方法将会在链表为空时,抛出异常
-
-element()方法的内部就是使用getFirst()实现的。它们会在链表为空时,抛出NoSuchElementException
-**获取尾节点(index=-1)数据方法:**
-```java
- public E getLast() {
- final Node l = last;
- if (l == null)
- throw new NoSuchElementException();
- return l.item;
- }
- public E peekLast() {
- final Node l = last;
- return (l == null) ? null : l.item;
- }
-```
-**两者区别:**
-**getLast()** 方法在链表为空时,会抛出**NoSuchElementException**,而**peekLast()** 则不会,只是会返回 **null**。
-### 根据对象得到索引的方法
-**int indexOf(Object o):** 从头遍历找
-```java
-public int indexOf(Object o) {
- int index = 0;
- if (o == null) {
- //从头遍历
- for (Node x = first; x != null; x = x.next) {
- if (x.item == null)
- return index;
- index++;
- }
- } else {
- //从头遍历
- for (Node x = first; x != null; x = x.next) {
- if (o.equals(x.item))
- return index;
- index++;
- }
- }
- return -1;
- }
-```
-**int lastIndexOf(Object o):** 从尾遍历找
-```java
-public int lastIndexOf(Object o) {
- int index = size;
- if (o == null) {
- //从尾遍历
- for (Node x = last; x != null; x = x.prev) {
- index--;
- if (x.item == null)
- return index;
- }
- } else {
- //从尾遍历
- for (Node x = last; x != null; x = x.prev) {
- index--;
- if (o.equals(x.item))
- return index;
- }
- }
- return -1;
- }
-```
-### 检查链表是否包含某对象的方法:
-**contains(Object o):** 检查对象o是否存在于链表中
-```java
- public boolean contains(Object o) {
- return indexOf(o) != -1;
- }
-```
-### 删除方法
-**remove()** ,**removeFirst(),pop():** 删除头节点
-```
-public E pop() {
- return removeFirst();
- }
-public E remove() {
- return removeFirst();
- }
-public E removeFirst() {
- final Node f = first;
- if (f == null)
- throw new NoSuchElementException();
- return unlinkFirst(f);
- }
-```
-**removeLast(),pollLast():** 删除尾节点
-```java
-public E removeLast() {
- final Node l = last;
- if (l == null)
- throw new NoSuchElementException();
- return unlinkLast(l);
- }
-public E pollLast() {
- final Node l = last;
- return (l == null) ? null : unlinkLast(l);
- }
-```
-**区别:** removeLast()在链表为空时将抛出NoSuchElementException,而pollLast()方法返回null。
-
-**remove(Object o):** 删除指定元素
-```java
-public boolean remove(Object o) {
- //如果删除对象为null
- if (o == null) {
- //从头开始遍历
- for (Node x = first; x != null; x = x.next) {
- //找到元素
- if (x.item == null) {
- //从链表中移除找到的元素
- unlink(x);
- return true;
- }
- }
- } else {
- //从头开始遍历
- for (Node x = first; x != null; x = x.next) {
- //找到元素
- if (o.equals(x.item)) {
- //从链表中移除找到的元素
- unlink(x);
- return true;
- }
- }
- }
- return false;
- }
-```
-当删除指定对象时,只需调用remove(Object o)即可,不过该方法一次只会删除一个匹配的对象,如果删除了匹配对象,返回true,否则false。
-
-unlink(Node x) 方法:
-```java
-E unlink(Node x) {
- // assert x != null;
- final E element = x.item;
- final Node next = x.next;//得到后继节点
- final Node prev = x.prev;//得到前驱节点
-
- //删除前驱指针
- if (prev == null) {
- first = next;//如果删除的节点是头节点,令头节点指向该节点的后继节点
- } else {
- prev.next = next;//将前驱节点的后继节点指向后继节点
- x.prev = null;
- }
-
- //删除后继指针
- if (next == null) {
- last = prev;//如果删除的节点是尾节点,令尾节点指向该节点的前驱节点
- } else {
- next.prev = prev;
- x.next = null;
- }
-
- x.item = null;
- size--;
- modCount++;
- return element;
- }
-```
-**remove(int index)**:删除指定位置的元素
-```java
-public E remove(int index) {
- //检查index范围
- checkElementIndex(index);
- //将节点删除
- return unlink(node(index));
- }
-```
-## LinkedList类常用方法测试
-
-```java
-package list;
-
-import java.util.Iterator;
-import java.util.LinkedList;
-
-public class LinkedListDemo {
- public static void main(String[] srgs) {
- //创建存放int类型的linkedList
- LinkedList linkedList = new LinkedList<>();
- /************************** linkedList的基本操作 ************************/
- linkedList.addFirst(0); // 添加元素到列表开头
- linkedList.add(1); // 在列表结尾添加元素
- linkedList.add(2, 2); // 在指定位置添加元素
- linkedList.addLast(3); // 添加元素到列表结尾
-
- System.out.println("LinkedList(直接输出的): " + linkedList);
-
- System.out.println("getFirst()获得第一个元素: " + linkedList.getFirst()); // 返回此列表的第一个元素
- System.out.println("getLast()获得第最后一个元素: " + linkedList.getLast()); // 返回此列表的最后一个元素
- System.out.println("removeFirst()删除第一个元素并返回: " + linkedList.removeFirst()); // 移除并返回此列表的第一个元素
- System.out.println("removeLast()删除最后一个元素并返回: " + linkedList.removeLast()); // 移除并返回此列表的最后一个元素
- System.out.println("After remove:" + linkedList);
- System.out.println("contains()方法判断列表是否包含1这个元素:" + linkedList.contains(1)); // 判断此列表包含指定元素,如果是,则返回true
- System.out.println("该linkedList的大小 : " + linkedList.size()); // 返回此列表的元素个数
-
- /************************** 位置访问操作 ************************/
- System.out.println("-----------------------------------------");
- linkedList.set(1, 3); // 将此列表中指定位置的元素替换为指定的元素
- System.out.println("After set(1, 3):" + linkedList);
- System.out.println("get(1)获得指定位置(这里为1)的元素: " + linkedList.get(1)); // 返回此列表中指定位置处的元素
-
- /************************** Search操作 ************************/
- System.out.println("-----------------------------------------");
- linkedList.add(3);
- System.out.println("indexOf(3): " + linkedList.indexOf(3)); // 返回此列表中首次出现的指定元素的索引
- System.out.println("lastIndexOf(3): " + linkedList.lastIndexOf(3));// 返回此列表中最后出现的指定元素的索引
-
- /************************** Queue操作 ************************/
- System.out.println("-----------------------------------------");
- System.out.println("peek(): " + linkedList.peek()); // 获取但不移除此列表的头
- System.out.println("element(): " + linkedList.element()); // 获取但不移除此列表的头
- linkedList.poll(); // 获取并移除此列表的头
- System.out.println("After poll():" + linkedList);
- linkedList.remove();
- System.out.println("After remove():" + linkedList); // 获取并移除此列表的头
- linkedList.offer(4);
- System.out.println("After offer(4):" + linkedList); // 将指定元素添加到此列表的末尾
-
- /************************** Deque操作 ************************/
- System.out.println("-----------------------------------------");
- linkedList.offerFirst(2); // 在此列表的开头插入指定的元素
- System.out.println("After offerFirst(2):" + linkedList);
- linkedList.offerLast(5); // 在此列表末尾插入指定的元素
- System.out.println("After offerLast(5):" + linkedList);
- System.out.println("peekFirst(): " + linkedList.peekFirst()); // 获取但不移除此列表的第一个元素
- System.out.println("peekLast(): " + linkedList.peekLast()); // 获取但不移除此列表的第一个元素
- linkedList.pollFirst(); // 获取并移除此列表的第一个元素
- System.out.println("After pollFirst():" + linkedList);
- linkedList.pollLast(); // 获取并移除此列表的最后一个元素
- System.out.println("After pollLast():" + linkedList);
- linkedList.push(2); // 将元素推入此列表所表示的堆栈(插入到列表的头)
- System.out.println("After push(2):" + linkedList);
- linkedList.pop(); // 从此列表所表示的堆栈处弹出一个元素(获取并移除列表第一个元素)
- System.out.println("After pop():" + linkedList);
- linkedList.add(3);
- linkedList.removeFirstOccurrence(3); // 从此列表中移除第一次出现的指定元素(从头部到尾部遍历列表)
- System.out.println("After removeFirstOccurrence(3):" + linkedList);
- linkedList.removeLastOccurrence(3); // 从此列表中移除最后一次出现的指定元素(从尾部到头部遍历列表)
- System.out.println("After removeFirstOccurrence(3):" + linkedList);
-
- /************************** 遍历操作 ************************/
- System.out.println("-----------------------------------------");
- linkedList.clear();
- for (int i = 0; i < 100000; i++) {
- linkedList.add(i);
- }
- // 迭代器遍历
- long start = System.currentTimeMillis();
- Iterator iterator = linkedList.iterator();
- while (iterator.hasNext()) {
- iterator.next();
- }
- long end = System.currentTimeMillis();
- System.out.println("Iterator:" + (end - start) + " ms");
-
- // 顺序遍历(随机遍历)
- start = System.currentTimeMillis();
- for (int i = 0; i < linkedList.size(); i++) {
- linkedList.get(i);
- }
- end = System.currentTimeMillis();
- System.out.println("for:" + (end - start) + " ms");
-
- // 另一种for循环遍历
- start = System.currentTimeMillis();
- for (Integer i : linkedList)
- ;
- end = System.currentTimeMillis();
- System.out.println("for2:" + (end - start) + " ms");
-
- // 通过pollFirst()或pollLast()来遍历LinkedList
- LinkedList temp1 = new LinkedList<>();
- temp1.addAll(linkedList);
- start = System.currentTimeMillis();
- while (temp1.size() != 0) {
- temp1.pollFirst();
- }
- end = System.currentTimeMillis();
- System.out.println("pollFirst()或pollLast():" + (end - start) + " ms");
-
- // 通过removeFirst()或removeLast()来遍历LinkedList
- LinkedList temp2 = new LinkedList<>();
- temp2.addAll(linkedList);
- start = System.currentTimeMillis();
- while (temp2.size() != 0) {
- temp2.removeFirst();
- }
- end = System.currentTimeMillis();
- System.out.println("removeFirst()或removeLast():" + (end - start) + " ms");
- }
-}
-```
diff --git "a/docs/java/collection/ArrayList\346\272\220\347\240\201+\346\211\251\345\256\271\346\234\272\345\210\266\345\210\206\346\236\220.md" b/docs/java/collection/arraylist-source-code.md
similarity index 99%
rename from "docs/java/collection/ArrayList\346\272\220\347\240\201+\346\211\251\345\256\271\346\234\272\345\210\266\345\210\206\346\236\220.md"
rename to docs/java/collection/arraylist-source-code.md
index 79ae722c309..36dfcbdbfc8 100644
--- "a/docs/java/collection/ArrayList\346\272\220\347\240\201+\346\211\251\345\256\271\346\234\272\345\210\266\345\210\206\346\236\220.md"
+++ b/docs/java/collection/arraylist-source-code.md
@@ -1,3 +1,11 @@
+---
+title: ArrayList 源码+扩容机制分析
+category: Java
+tag:
+ - Java集合
+---
+
+
## 1. ArrayList 简介
`ArrayList` 的底层是数组队列,相当于动态数组。与 Java 中的数组相比,它的容量能动态增长。在添加大量元素前,应用程序可以使用`ensureCapacity`操作来增加 `ArrayList` 实例的容量。这可以减少递增式再分配的数量。
diff --git "a/docs/java/collection/ConcurrentHashMap\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" b/docs/java/collection/concurrent-hash-map-source-code.md
similarity index 99%
rename from "docs/java/collection/ConcurrentHashMap\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md"
rename to docs/java/collection/concurrent-hash-map-source-code.md
index 89f9d24e062..6d765697df9 100644
--- "a/docs/java/collection/ConcurrentHashMap\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md"
+++ b/docs/java/collection/concurrent-hash-map-source-code.md
@@ -1,3 +1,11 @@
+---
+title: ConcurrentHashMap源码+底层数据结构分析
+category: Java
+tag:
+ - Java集合
+---
+
+
> 本文来自公众号:末读代码的投稿,原文地址:https://mp.weixin.qq.com/s/AHWzboztt53ZfFZmsSnMSw 。
上一篇文章介绍了 HashMap 源码,反响不错,也有很多同学发表了自己的观点,这次又来了,这次是 `ConcurrentHashMap ` 了,作为线程安全的HashMap ,它的使用频率也是很高。那么它的存储结构和实现原理是怎么样的呢?
diff --git "a/docs/java/collection/HashMap(JDK1.8)\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md" b/docs/java/collection/hashmap-source-code.md
similarity index 97%
rename from "docs/java/collection/HashMap(JDK1.8)\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md"
rename to docs/java/collection/hashmap-source-code.md
index e78ba116057..7996b2766d1 100644
--- "a/docs/java/collection/HashMap(JDK1.8)\346\272\220\347\240\201+\345\272\225\345\261\202\346\225\260\346\215\256\347\273\223\346\236\204\345\210\206\346\236\220.md"
+++ b/docs/java/collection/hashmap-source-code.md
@@ -1,19 +1,9 @@
-
-
-
-
-- [HashMap 简介](#hashmap-简介)
-- [底层数据结构分析](#底层数据结构分析)
- - [JDK1.8 之前](#jdk18-之前)
- - [JDK1.8 之后](#jdk18-之后)
-- [HashMap 源码分析](#hashmap-源码分析)
- - [构造方法](#构造方法)
- - [put 方法](#put-方法)
- - [get 方法](#get-方法)
- - [resize 方法](#resize-方法)
-- [HashMap 常用方法测试](#hashmap-常用方法测试)
-
-
+---
+title: HashMap源码+底层数据结构分析
+category: Java
+tag:
+ - Java集合
+---
> 感谢 [changfubai](https://github.com/changfubai) 对本文的改进做出的贡献!
diff --git "a/docs/java/collection/Java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271\346\200\273\347\273\223.md" "b/docs/java/collection/java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271.md"
similarity index 99%
rename from "docs/java/collection/Java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271\346\200\273\347\273\223.md"
rename to "docs/java/collection/java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271.md"
index 3c04c7afdca..6a65c33a264 100644
--- "a/docs/java/collection/Java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271\346\200\273\347\273\223.md"
+++ "b/docs/java/collection/java\351\233\206\345\220\210\344\275\277\347\224\250\346\263\250\346\204\217\344\272\213\351\241\271.md"
@@ -1,3 +1,10 @@
+---
+title: Java集合使用注意事项总结
+category: Java
+tag:
+ - Java集合
+---
+
这篇文章我根据《阿里巴巴 Java 开发手册》总结了关于集合使用常见的注意事项以及其具体原理。
强烈建议小伙伴们多多阅读几遍,避免自己写代码的时候出现这些低级的问题。
diff --git "a/docs/java/collection/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.md" "b/docs/java/collection/java\351\233\206\345\220\210\346\241\206\346\236\266\345\237\272\347\241\200\347\237\245\350\257\206&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 85%
rename from "docs/java/collection/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.md"
rename to "docs/java/collection/java\351\233\206\345\220\210\346\241\206\346\236\266\345\237\272\347\241\200\347\237\245\350\257\206&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index 805b29a280f..1f901750654 100644
--- "a/docs/java/collection/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.md"
+++ "b/docs/java/collection/java\351\233\206\345\220\210\346\241\206\346\236\266\345\237\272\347\241\200\347\237\245\350\257\206&\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,59 +1,14 @@
-
-
-- [1. 剖析面试最常见问题之 Java 集合框架](#1-剖析面试最常见问题之-java-集合框架)
- - [1.1. 集合概述](#11-集合概述)
- - [1.1.1. Java 集合概览](#111-java-集合概览)
- - [1.1.2. 说说 List, Set, Queue, Map 四者的区别?](#112-说说-list-set-queue-map-四者的区别)
- - [1.1.3. 集合框架底层数据结构总结](#113-集合框架底层数据结构总结)
- - [1.1.3.1. List](#1131-list)
- - [1.1.3.2. Set](#1132-set)
- - [1.1.3.3 Queue](#1133-queue)
- - [1.1.3.4. Map](#1134-map)
- - [1.1.4. 如何选用集合?](#114-如何选用集合)
- - [1.1.5. 为什么要使用集合?](#115-为什么要使用集合)
- - [1.2. Collection 子接口之 List](#12-collection-子接口之-list)
- - [1.2.1. Arraylist 和 Vector 的区别?](#121-arraylist-和-vector-的区别)
- - [1.2.2. Arraylist 与 LinkedList 区别?](#122-arraylist-与-linkedlist-区别)
- - [1.2.2.1. 补充内容:双向链表和双向循环链表](#1221-补充内容双向链表和双向循环链表)
- - [1.2.2.2. 补充内容:RandomAccess 接口](#1222-补充内容randomaccess-接口)
- - [1.2.3. 说一说 ArrayList 的扩容机制吧](#123-说一说-arraylist-的扩容机制吧)
- - [1.3. Collection 子接口之 Set](#13-collection-子接口之-set)
- - [1.3.1. comparable 和 Comparator 的区别](#131-comparable-和-comparator-的区别)
- - [1.3.1.1. Comparator 定制排序](#1311-comparator-定制排序)
- - [1.3.1.2. 重写 compareTo 方法实现按年龄来排序](#1312-重写-compareto-方法实现按年龄来排序)
- - [1.3.2. 无序性和不可重复性的含义是什么](#132-无序性和不可重复性的含义是什么)
- - [1.3.3. 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同](#133-比较-hashsetlinkedhashset-和-treeset-三者的异同)
- - [1.4 Collection 子接口之 Queue](#14-collection-子接口之-queue)
- - [1.4.1 Queue 与 Deque 的区别](#141-queue-与-deque-的区别)
- - [1.4.2 ArrayDeque 与 LinkedList 的区别](#142-arraydeque-与-linkedlist-的区别)
- - [1.4.3 说一说 PriorityQueue](#143-说一说-priorityqueue)
- - [1.5. Map 接口](#15-map-接口)
- - [1.5.1. HashMap 和 Hashtable 的区别](#151-hashmap-和-hashtable-的区别)
- - [1.5.2. HashMap 和 HashSet 区别](#152-hashmap-和-hashset-区别)
- - [1.5.3. HashMap 和 TreeMap 区别](#153-hashmap-和-treemap-区别)
- - [1.5.4. HashSet 如何检查重复](#154-hashset-如何检查重复)
- - [1.5.5. HashMap 的底层实现](#155-hashmap-的底层实现)
- - [1.5.5.1. JDK1.8 之前](#1551-jdk18-之前)
- - [1.5.5.2. JDK1.8 之后](#1552-jdk18-之后)
- - [1.5.6. HashMap 的长度为什么是 2 的幂次方](#156-hashmap-的长度为什么是-2-的幂次方)
- - [1.5.7. HashMap 多线程操作导致死循环问题](#157-hashmap-多线程操作导致死循环问题)
- - [1.5.8. HashMap 有哪几种常见的遍历方式?](#158-hashmap-有哪几种常见的遍历方式)
- - [1.5.9. ConcurrentHashMap 和 Hashtable 的区别](#159-concurrenthashmap-和-hashtable-的区别)
- - [1.5.10. ConcurrentHashMap 线程安全的具体实现方式/底层具体实现](#1510-concurrenthashmap-线程安全的具体实现方式底层具体实现)
- - [1.5.10.1. JDK1.7(上面有示意图)](#15101-jdk17上面有示意图)
- - [1.5.10.2. JDK1.8 (上面有示意图)](#15102-jdk18-上面有示意图)
- - [1.6. Collections 工具类](#16-collections-工具类)
- - [1.6.1. 排序操作](#161-排序操作)
- - [1.6.2. 查找,替换操作](#162-查找替换操作)
- - [1.6.3. 同步控制](#163-同步控制)
-
-
-
-# 1. 剖析面试最常见问题之 Java 集合框架
-
-## 1.1. 集合概述
-
-### 1.1.1. Java 集合概览
+---
+category: Java
+tag:
+ - Java集合
+---
+
+# Java集合框架基础知识&面试题总结
+
+## 集合概述
+
+### Java 集合概览
Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 `Collecton`接口,主要用于存放单一元素;另一个是 `Map` 接口,主要用于存放键值对。对于`Collection` 接口,下面又有三个主要的子接口:`List`、`Set` 和 `Queue`。
@@ -64,49 +19,49 @@ Java 集合框架如下图所示:
注:图中只列举了主要的继承派生关系,并没有列举所有关系。比方省略了`AbstractList`, `NavigableSet`等抽象类以及其他的一些辅助类,如想深入了解,可自行查看源码。
-### 1.1.2. 说说 List, Set, Queue, Map 四者的区别?
+### 说说 List, Set, Queue, Map 四者的区别?
- `List`(对付顺序的好帮手): 存储的元素是有序的、可重复的。
- `Set`(注重独一无二的性质): 存储的元素是无序的、不可重复的。
- `Queue`(实现排队功能的叫号机): 按特定的排队规则来确定先后顺序,存储的元素是有序的、可重复的。
- `Map`(用 key 来搜索的专家): 使用键值对(key-value)存储,类似于数学上的函数 y=f(x),"x" 代表 key,"y" 代表 value,key 是无序的、不可重复的,value 是无序的、可重复的,每个键最多映射到一个值。
-### 1.1.3. 集合框架底层数据结构总结
+### 集合框架底层数据结构总结
先来看一下 `Collection` 接口下面的集合。
-#### 1.1.3.1. List
+#### List
- `Arraylist`: `Object[]` 数组
- `Vector`:`Object[]` 数组
- `LinkedList`: 双向链表(JDK1.6 之前为循环链表,JDK1.7 取消了循环)
-#### 1.1.3.2. Set
+#### Set
- `HashSet`(无序,唯一): 基于 `HashMap` 实现的,底层采用 `HashMap` 来保存元素
- `LinkedHashSet`: `LinkedHashSet` 是 `HashSet` 的子类,并且其内部是通过 `LinkedHashMap` 来实现的。有点类似于我们之前说的 `LinkedHashMap` 其内部是基于 `HashMap` 实现一样,不过还是有一点点区别的
- `TreeSet`(有序,唯一): 红黑树(自平衡的排序二叉树)
-#### 1.1.3.3 Queue
+#### Queue
- `PriorityQueue`: `Object[]` 数组来实现二叉堆
- `ArrayQueue`: `Object[]` 数组 + 双指针
再来看看 `Map` 接口下面的集合。
-#### 1.1.3.4. Map
+#### Map
- `HashMap`: JDK1.8 之前 `HashMap` 由数组+链表组成的,数组是 `HashMap` 的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8 以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间
- `LinkedHashMap`: `LinkedHashMap` 继承自 `HashMap`,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,`LinkedHashMap` 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。详细可以查看:[《LinkedHashMap 源码详细分析(JDK1.8)》](https://www.imooc.com/article/22931)
- `Hashtable`: 数组+链表组成的,数组是 `Hashtable` 的主体,链表则是主要为了解决哈希冲突而存在的
- `TreeMap`: 红黑树(自平衡的排序二叉树)
-### 1.1.4. 如何选用集合?
+### 如何选用集合?
主要根据集合的特点来选用,比如我们需要根据键值获取到元素值时就选用 `Map` 接口下的集合,需要排序时选择 `TreeMap`,不需要排序时就选择 `HashMap`,需要保证线程安全就选用 `ConcurrentHashMap`。
当我们只需要存放元素值时,就选择实现`Collection` 接口的集合,需要保证元素唯一时选择实现 `Set` 接口的集合比如 `TreeSet` 或 `HashSet`,不需要就选择实现 `List` 接口的比如 `ArrayList` 或 `LinkedList`,然后再根据实现这些接口的集合的特点来选用。
-### 1.1.5. 为什么要使用集合?
+### 为什么要使用集合?
当我们需要保存一组类型相同的数据的时候,我们应该是用一个容器来保存,这个容器就是数组,但是,使用数组存储对象具有一定的弊端,
因为我们在实际开发中,存储的数据的类型是多种多样的,于是,就出现了“集合”,集合同样也是用来存储多个数据的。
@@ -114,14 +69,14 @@ Java 集合框架如下图所示:
数组的缺点是一旦声明之后,长度就不可变了;同时,声明数组时的数据类型也决定了该数组存储的数据的类型;而且,数组存储的数据是有序的、可重复的,特点单一。
但是集合提高了数据存储的灵活性,Java 集合不仅可以用来存储不同类型不同数量的对象,还可以保存具有映射关系的数据。
-## 1.2. Collection 子接口之 List
+## Collection 子接口之 List
-### 1.2.1. Arraylist 和 Vector 的区别?
+### Arraylist 和 Vector 的区别?
- `ArrayList` 是 `List` 的主要实现类,底层使用 `Object[ ]`存储,适用于频繁的查找工作,线程不安全 ;
- `Vector` 是 `List` 的古老实现类,底层使用`Object[ ]` 存储,线程安全的。
-### 1.2.2. Arraylist 与 LinkedList 区别?
+### Arraylist 与 LinkedList 区别?
1. **是否保证线程安全:** `ArrayList` 和 `LinkedList` 都是不同步的,也就是不保证线程安全;
2. **底层数据结构:** `Arraylist` 底层使用的是 **`Object` 数组**;`LinkedList` 底层使用的是 **双向链表** 数据结构(JDK1.6 之前为循环链表,JDK1.7 取消了循环。注意双向链表和双向循环链表的区别,下面有介绍到!)
@@ -131,7 +86,7 @@ Java 集合框架如下图所示:
4. **是否支持快速随机访问:** `LinkedList` 不支持高效的随机元素访问,而 `ArrayList` 支持。快速随机访问就是通过元素的序号快速获取元素对象(对应于`get(int index)`方法)。
5. **内存空间占用:** ArrayList 的空 间浪费主要体现在在 list 列表的结尾会预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消耗比 ArrayList 更多的空间(因为要存放直接后继和直接前驱以及数据)。
-#### 1.2.2.1. 补充内容:双向链表和双向循环链表
+#### 补充内容:双向链表和双向循环链表
**双向链表:** 包含两个指针,一个 prev 指向前一个节点,一个 next 指向后一个节点。
@@ -143,7 +98,7 @@ Java 集合框架如下图所示:

-#### 1.2.2.2. 补充内容:RandomAccess 接口
+#### 补充内容:RandomAccess 接口
```java
public interface RandomAccess {
@@ -166,20 +121,20 @@ public interface RandomAccess {
`ArrayList` 实现了 `RandomAccess` 接口, 而 `LinkedList` 没有实现。为什么呢?我觉得还是和底层数据结构有关!`ArrayList` 底层是数组,而 `LinkedList` 底层是链表。数组天然支持随机访问,时间复杂度为 O(1),所以称为快速随机访问。链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为 O(n),所以不支持快速随机访问。,`ArrayList` 实现了 `RandomAccess` 接口,就表明了他具有快速随机访问功能。 `RandomAccess` 接口只是标识,并不是说 `ArrayList` 实现 `RandomAccess` 接口才具有快速随机访问功能的!
-### 1.2.3. 说一说 ArrayList 的扩容机制吧
+### 说一说 ArrayList 的扩容机制吧
详见笔主的这篇文章:[通过源码一步一步分析 ArrayList 扩容机制](https://snailclimb.gitee.io/javaguide/#/docs/java/collection/ArrayList%E6%BA%90%E7%A0%81+%E6%89%A9%E5%AE%B9%E6%9C%BA%E5%88%B6%E5%88%86%E6%9E%90)
-## 1.3. Collection 子接口之 Set
+## Collection 子接口之 Set
-### 1.3.1. comparable 和 Comparator 的区别
+### comparable 和 Comparator 的区别
- `comparable` 接口实际上是出自`java.lang`包 它有一个 `compareTo(Object obj)`方法用来排序
- `comparator`接口实际上是出自 java.util 包它有一个`compare(Object obj1, Object obj2)`方法用来排序
一般我们需要对一个集合使用自定义排序时,我们就要重写`compareTo()`方法或`compare()`方法,当我们需要对某一个集合实现两种排序方式,比如一个 song 对象中的歌名和歌手名分别采用一种排序方法的话,我们可以重写`compareTo()`方法和使用自制的`Comparator`方法或者以两个 Comparator 来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的 `Collections.sort()`.
-#### 1.3.1.1. Comparator 定制排序
+#### Comparator 定制排序
```java
ArrayList arrayList = new ArrayList();
@@ -227,7 +182,7 @@ Collections.sort(arrayList):
[7, 4, 3, 3, -1, -5, -7, -9]
```
-#### 1.3.1.2. 重写 compareTo 方法实现按年龄来排序
+#### 重写 compareTo 方法实现按年龄来排序
```java
// person对象没有实现Comparable接口,所以必须实现,这样才不会出错,才可以使treemap中的数据按顺序排列
@@ -301,23 +256,21 @@ Output:
30-张三
```
-### 1.3.2. 无序性和不可重复性的含义是什么
+### 无序性和不可重复性的含义是什么
1、什么是无序性?无序性不等于随机性 ,无序性是指存储的数据在底层数组中并非按照数组索引的顺序添加 ,而是根据数据的哈希值决定的。
2、什么是不可重复性?不可重复性是指添加的元素按照 equals()判断时 ,返回 false,需要同时重写 equals()方法和 HashCode()方法。
-### 1.3.3. 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
-
-`HashSet` 是 `Set` 接口的主要实现类 ,`HashSet` 的底层是 `HashMap`,线程不安全的,可以存储 null 值;
+### 比较 HashSet、LinkedHashSet 和 TreeSet 三者的异同
-`LinkedHashSet` 是 `HashSet` 的子类,能够按照添加的顺序遍历;
+- `HashSet`、`LinkedHashSet` 和 `TreeSet` 都是 `Set` 接口的实现类,都能保证元素唯一,并且都不是线程安全的。
+- `HashSet`、`LinkedHashSet` 和 `TreeSet` 的主要区别在于底层数据结构不同。`HashSet` 的底层数据结构是哈希表(基于 `HashMap` 实现)。`LinkedHashSet` 的底层数据结构是链表和哈希表,元素的插入和取出顺序满足 FIFO。`TreeSet` 底层数据结构是红黑树,元素是有序的,排序的方式有自然排序和定制排序。
+- 底层数据结构不同又导致这三者的应用场景不同。`HashSet` 用于不需要保证元素插入和取出顺序的场景,`LinkHashSet` 用于保证元素的插入和取出顺序满足 FIFO 的场景,`TreeSet` 用于支持对元素自定义排序规则的场景。
-`TreeSet` 底层使用红黑树,元素是有序的,排序的方式有自然排序和定制排序。
+## Collection 子接口之 Queue
-## 1.4 Collection 子接口之 Queue
-
-### 1.4.1 Queue 与 Deque 的区别
+### Queue 与 Deque 的区别
`Queue` 是单端队列,只能从一端插入元素,另一端删除元素,实现上一般遵循 **先进先出(FIFO)** 规则。
@@ -345,7 +298,7 @@ Output:
事实上,`Deque` 还提供有 `push()` 和 `pop()` 等其他方法,可用于模拟栈。
-### 1.4.2 ArrayDeque 与 LinkedList 的区别
+### ArrayDeque 与 LinkedList 的区别
`ArrayDeque` 和 `LinkedList` 都实现了 `Deque` 接口,两者都具有队列的功能,但两者有什么区别呢?
@@ -359,7 +312,7 @@ Output:
从性能的角度上,选用 `ArrayDeque` 来实现队列要比 `LinkedList` 更好。此外,`ArrayDeque` 也可以用于实现栈。
-### 1.4.3 说一说 PriorityQueue
+### 说一说 PriorityQueue
`PriorityQueue` 是在 JDK1.5 中被引入的, 其与 `Queue` 的区别在于元素出队顺序是与优先级相关的,即总是优先级最高的元素先出队。
@@ -372,9 +325,9 @@ Output:
`PriorityQueue` 在面试中可能更多的会出现在手撕算法的时候,典型例题包括堆排序、求第K大的数、带权图的遍历等,所以需要会熟练使用才行。
-## 1.5. Map 接口
+## Map 接口
-### 1.5.1. HashMap 和 Hashtable 的区别
+### HashMap 和 Hashtable 的区别
1. **线程是否安全:** `HashMap` 是非线程安全的,`Hashtable` 是线程安全的,因为 `Hashtable` 内部的方法基本都经过`synchronized` 修饰。(如果你要保证线程安全的话就使用 `ConcurrentHashMap` 吧!);
2. **效率:** 因为线程安全的问题,`HashMap` 要比 `Hashtable` 效率高一点。另外,`Hashtable` 基本被淘汰,不要在代码中使用它;
@@ -419,7 +372,7 @@ Output:
}
```
-### 1.5.2. HashMap 和 HashSet 区别
+### HashMap 和 HashSet 区别
如果你看过 `HashSet` 源码的话就应该知道:`HashSet` 底层就是基于 `HashMap` 实现的。(`HashSet` 的源码非常非常少,因为除了 `clone()`、`writeObject()`、`readObject()`是 `HashSet` 自己不得不实现之外,其他方法都是直接调用 `HashMap` 中的方法。
@@ -430,7 +383,7 @@ Output:
| 调用 `put()`向 map 中添加元素 | 调用 `add()`方法向 `Set` 中添加元素 |
| `HashMap` 使用键(Key)计算 `hashcode` | `HashSet` 使用成员对象来计算 `hashcode` 值,对于两个对象来说 `hashcode` 可能相同,所以`equals()`方法用来判断对象的相等性 |
-### 1.5.3. HashMap 和 TreeMap 区别
+### HashMap 和 TreeMap 区别
`TreeMap` 和`HashMap` 都继承自`AbstractMap` ,但是需要注意的是`TreeMap`它还实现了`NavigableMap`接口和`SortedMap` 接口。
@@ -498,7 +451,7 @@ TreeMap treeMap = new TreeMap<>((person1, person2) -> {
**综上,相比于`HashMap`来说 `TreeMap` 主要多了对集合中的元素根据键排序的能力以及对集合内元素的搜索的能力。**
-### 1.5.4. HashSet 如何检查重复
+### HashSet 如何检查重复
以下内容摘自我的 Java 启蒙书《Head first java》第二版:
@@ -541,9 +494,9 @@ final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
对于引用类型(包括包装类型)来说,equals 如果没有被重写,对比它们的地址是否相等;如果 equals()方法被重写(例如 String),则比较的是地址里的内容。
-### 1.5.5. HashMap 的底层实现
+### HashMap 的底层实现
-#### 1.5.5.1. JDK1.8 之前
+#### JDK1.8 之前
JDK1.8 之前 `HashMap` 底层是 **数组和链表** 结合在一起使用也就是 **链表散列**。**HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过 (n - 1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,直接覆盖,不相同就通过拉链法解决冲突。**
@@ -582,7 +535,7 @@ static int hash(int h) {

-#### 1.5.5.2. JDK1.8 之后
+#### JDK1.8 之后
相比于之前的版本, JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树)时,将链表转化为红黑树,以减少搜索时间。
@@ -590,7 +543,7 @@ static int hash(int h) {
> TreeMap、TreeSet 以及 JDK1.8 之后的 HashMap 底层都用到了红黑树。红黑树就是为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
-### 1.5.6. HashMap 的长度为什么是 2 的幂次方
+### HashMap 的长度为什么是 2 的幂次方
为了能让 HashMap 存取高效,尽量较少碰撞,也就是要尽量把数据分配均匀。我们上面也讲到了过了,Hash 值的范围值-2147483648 到 2147483647,前后加起来大概 40 亿的映射空间,只要哈希函数映射得比较均匀松散,一般应用是很难出现碰撞的。但问题是一个 40 亿长度的数组,内存是放不下的。所以这个散列值是不能直接拿来用的。用之前还要先做对数组的长度取模运算,得到的余数才能用来要存放的位置也就是对应的数组下标。这个数组下标的计算方法是“ `(n - 1) & hash`”。(n 代表数组长度)。这也就解释了 HashMap 的长度为什么是 2 的幂次方。
@@ -598,17 +551,17 @@ static int hash(int h) {
我们首先可能会想到采用%取余的操作来实现。但是,重点来了:**“取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&)操作(也就是说 hash%length==hash&(length-1)的前提是 length 是 2 的 n 次方;)。”** 并且 **采用二进制位操作 &,相对于%能够提高运算效率,这就解释了 HashMap 的长度为什么是 2 的幂次方。**
-### 1.5.7. HashMap 多线程操作导致死循环问题
+### HashMap 多线程操作导致死循环问题
主要原因在于并发下的 Rehash 会造成元素之间会形成一个循环链表。不过,jdk 1.8 后解决了这个问题,但是还是不建议在多线程下使用 HashMap,因为多线程下使用 HashMap 还是会存在其他问题比如数据丢失。并发环境下推荐使用 ConcurrentHashMap 。
详情请查看:
-### 1.5.8. HashMap 有哪几种常见的遍历方式?
+### HashMap 有哪几种常见的遍历方式?
[HashMap 的 7 种遍历方式与性能分析!](https://mp.weixin.qq.com/s/zQBN3UvJDhRTKP6SzcZFKw)
-### 1.5.9. ConcurrentHashMap 和 Hashtable 的区别
+### ConcurrentHashMap 和 Hashtable 的区别
`ConcurrentHashMap` 和 `Hashtable` 的区别主要体现在实现线程安全的方式上不同。
@@ -635,9 +588,9 @@ static int hash(int h) {
JDK1.8 的 `ConcurrentHashMap` 不再是 **Segment 数组 + HashEntry 数组 + 链表**,而是 **Node 数组 + 链表 / 红黑树**。不过,Node 只能用于链表的情况,红黑树的情况需要使用 **`TreeNode`**。当冲突链表达到一定长度时,链表会转换成红黑树。
-### 1.5.10. ConcurrentHashMap 线程安全的具体实现方式/底层具体实现
+### ConcurrentHashMap 线程安全的具体实现方式/底层具体实现
-#### 1.5.10.1. JDK1.7(上面有示意图)
+#### JDK1.7(上面有示意图)
首先将数据分为一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据时,其他段的数据也能被其他线程访问。
@@ -652,13 +605,13 @@ static class Segment extends ReentrantLock implements Serializable {
一个 `ConcurrentHashMap` 里包含一个 `Segment` 数组。`Segment` 的结构和 `HashMap` 类似,是一种数组和链表结构,一个 `Segment` 包含一个 `HashEntry` 数组,每个 `HashEntry` 是一个链表结构的元素,每个 `Segment` 守护着一个 `HashEntry` 数组里的元素,当对 `HashEntry` 数组的数据进行修改时,必须首先获得对应的 `Segment` 的锁。
-#### 1.5.10.2. JDK1.8 (上面有示意图)
+#### JDK1.8 (上面有示意图)
`ConcurrentHashMap` 取消了 `Segment` 分段锁,采用 CAS 和 `synchronized` 来保证并发安全。数据结构跟 HashMap1.8 的结构类似,数组+链表/红黑二叉树。Java 8 在链表长度超过一定阈值(8)时将链表(寻址时间复杂度为 O(N))转换为红黑树(寻址时间复杂度为 O(log(N)))
`synchronized` 只锁定当前链表或红黑二叉树的首节点,这样只要 hash 不冲突,就不会产生并发,效率又提升 N 倍。
-## 1.6. Collections 工具类
+## Collections 工具类
Collections 工具类常用方法:
@@ -666,7 +619,7 @@ Collections 工具类常用方法:
2. 查找,替换操作
3. 同步控制(不推荐,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合)
-### 1.6.1. 排序操作
+### 排序操作
```java
void reverse(List list)//反转
@@ -677,7 +630,7 @@ void swap(List list, int i , int j)//交换两个索引位置的元素
void rotate(List list, int distance)//旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,将 list的前distance个元素整体移到后面
```
-### 1.6.2. 查找,替换操作
+### 查找,替换操作
```java
int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
@@ -689,7 +642,7 @@ int indexOfSubList(List list, List target)//统计target在list中第一次出
boolean replaceAll(List list, Object oldVal, Object newVal)//用新元素替换旧元素
```
-### 1.6.3. 同步控制
+### 同步控制
`Collections` 提供了多个`synchronizedXxx()`方法·,该方法可以将指定集合包装成线程同步的集合,从而解决多线程并发访问集合时的线程安全问题。
@@ -705,7 +658,3 @@ synchronizedList(List list)//返回指定列表支持的同步(线程安全
synchronizedMap(Map m) //返回由指定映射支持的同步(线程安全的)Map。
synchronizedSet(Set s) //返回指定 set 支持的同步(线程安全的)set。
```
-
-**《Java 面试突击》:** Java 程序员面试必备的《Java 面试突击》V3.0 PDF 版本扫码关注下面的公众号,在后台回复 **"面试突击"** 即可免费领取!
-
-
diff --git "a/docs/java/multi-thread/AQS\345\216\237\347\220\206\344\273\245\345\217\212AQS\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md" "b/docs/java/concurrent/aqs\345\216\237\347\220\206\344\273\245\345\217\212aqs\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md"
similarity index 99%
rename from "docs/java/multi-thread/AQS\345\216\237\347\220\206\344\273\245\345\217\212AQS\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/aqs\345\216\237\347\220\206\344\273\245\345\217\212aqs\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md"
index 4edc32d1ca1..43e59b4abb9 100644
--- "a/docs/java/multi-thread/AQS\345\216\237\347\220\206\344\273\245\345\217\212AQS\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/aqs\345\216\237\347\220\206\344\273\245\345\217\212aqs\345\220\214\346\255\245\347\273\204\344\273\266\346\200\273\347\273\223.md"
@@ -1,3 +1,11 @@
+---
+title: AQS 原理以及 AQS 同步组件总结
+category: Java
+tag:
+ - Java并发
+---
+
+
开始之前,先来看几道常见的面试题!建议你带着这些问题来看这篇文章:
- 何为 AQS?AQS 原理了解吗?
diff --git "a/docs/java/multi-thread/Atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md" "b/docs/java/concurrent/atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md"
similarity index 84%
rename from "docs/java/multi-thread/Atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md"
index 6140b5b031c..7628e1fe7d2 100644
--- "a/docs/java/multi-thread/Atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/atomic\345\216\237\345\255\220\347\261\273\346\200\273\347\273\223.md"
@@ -1,30 +1,12 @@
-点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
-
-> 个人觉得这一节掌握基本的使用即可!
-
-
-
-- [1 Atomic 原子类介绍](#1-atomic-原子类介绍)
-- [2 基本类型原子类](#2-基本类型原子类)
- - [2.1 基本类型原子类介绍](#21-基本类型原子类介绍)
- - [2.2 AtomicInteger 常见方法使用](#22-atomicinteger-常见方法使用)
- - [2.3 基本数据类型原子类的优势](#23-基本数据类型原子类的优势)
- - [2.4 AtomicInteger 线程安全原理简单分析](#24-atomicinteger-线程安全原理简单分析)
-- [3 数组类型原子类](#3-数组类型原子类)
- - [3.1 数组类型原子类介绍](#31-数组类型原子类介绍)
- - [3.2 AtomicIntegerArray 常见方法使用](#32-atomicintegerarray-常见方法使用)
-- [4 引用类型原子类](#4-引用类型原子类)
- - [4.1 引用类型原子类介绍](#41--引用类型原子类介绍)
- - [4.2 AtomicReference 类使用示例](#42-atomicreference-类使用示例)
- - [4.3 AtomicStampedReference 类使用示例](#43-atomicstampedreference-类使用示例)
- - [4.4 AtomicMarkableReference 类使用示例](#44-atomicmarkablereference-类使用示例)
-- [5 对象的属性修改类型原子类](#5-对象的属性修改类型原子类)
- - [5.1 对象的属性修改类型原子类介绍](#51-对象的属性修改类型原子类介绍)
- - [5.2 AtomicIntegerFieldUpdater 类使用示例](#52-atomicintegerfieldupdater-类使用示例)
-
-
-
-### 1 Atomic 原子类介绍
+---
+title: Atomic 原子类总结
+category: Java
+tag:
+ - Java并发
+---
+
+
+## Atomic 原子类介绍
Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是构成一般物质的最小单位,在化学反应中是不可分割的。在我们这里 Atomic 是指一个操作是不可中断的。即使是在多个线程一起执行的时候,一个操作一旦开始,就不会被其他线程干扰。
@@ -34,21 +16,20 @@ Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是

-根据操作的数据类型,可以将JUC包中的原子类分为4类
+根据操作的数据类型,可以将 JUC 包中的原子类分为 4 类
-**基本类型**
+**基本类型**
使用原子的方式更新基本类型
- AtomicInteger:整型原子类
- AtomicLong:长整型原子类
-- AtomicBoolean :布尔型原子类
+- AtomicBoolean :布尔型原子类
**数组类型**
使用原子的方式更新数组里的某个元素
-
- AtomicIntegerArray:整型数组原子类
- AtomicLongArray:长整型数组原子类
- AtomicReferenceArray :引用类型数组原子类
@@ -65,7 +46,7 @@ Atomic 翻译成中文是原子的意思。在化学上,我们知道原子是
- AtomicLongFieldUpdater:原子更新长整型字段的更新器
- AtomicReferenceFieldUpdater:原子更新引用类型里的字段
-> **🐛 修正(参见:[issue#626](https://github.com/Snailclimb/JavaGuide/issues/626))** : `AtomicMarkableReference` 不能解决ABA问题。
+> **🐛 修正(参见:[issue#626](https://github.com/Snailclimb/JavaGuide/issues/626))** : `AtomicMarkableReference` 不能解决 ABA 问题。
```java
/**
@@ -80,7 +61,7 @@ AtomicMarkableReference是将一个boolean值作是否有更改的标记,本
*/
public class SolveABAByAtomicMarkableReference {
-
+
private static AtomicMarkableReference atomicMarkableReference = new AtomicMarkableReference(100, false);
public static void main(String[] args) {
@@ -113,9 +94,10 @@ public class SolveABAByAtomicMarkableReference {
```
**CAS ABA 问题**
+
- 描述: 第一个线程取到了变量 x 的值 A,然后巴拉巴拉干别的事,总之就是只拿到了变量 x 的值 A。这段时间内第二个线程也取到了变量 x 的值 A,然后把变量 x 的值改为 B,然后巴拉巴拉干别的事,最后又把变量 x 的值变为 A (相当于还原了)。在这之后第一个线程终于进行了变量 x 的操作,但是此时变量 x 的值还是 A,所以 compareAndSet 操作是成功。
- 例子描述(可能不太合适,但好理解): 年初,现金为零,然后通过正常劳动赚了三百万,之后正常消费了(比如买房子)三百万。年末,虽然现金零收入(可能变成其他形式了),但是赚了钱是事实,还是得交税的!
-- 代码例子(以``` AtomicInteger ```为例)
+- 代码例子(以`AtomicInteger`为例)
```java
import java.util.concurrent.atomic.AtomicInteger;
@@ -189,19 +171,19 @@ Thread-0 ------ currentValue=1, finalValue=2, compareAndSet Result=true
下面我们来详细介绍一下这些原子类。
-### 2 基本类型原子类
+## 基本类型原子类
-#### 2.1 基本类型原子类介绍
+### 基本类型原子类介绍
使用原子的方式更新基本类型
- AtomicInteger:整型原子类
- AtomicLong:长整型原子类
-- AtomicBoolean :布尔型原子类
+- AtomicBoolean :布尔型原子类
上面三个类提供的方法几乎相同,所以我们这里以 AtomicInteger 为例子来介绍。
- **AtomicInteger 类常用方法**
+**AtomicInteger 类常用方法**
```java
public final int get() //获取当前的值
@@ -213,7 +195,7 @@ boolean compareAndSet(int expect, int update) //如果输入的数值等于预
public final void lazySet(int newValue)//最终设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
```
-#### 2.2 AtomicInteger 常见方法使用
+### AtomicInteger 常见方法使用
```java
import java.util.concurrent.atomic.AtomicInteger;
@@ -235,18 +217,18 @@ public class AtomicIntegerTest {
}
```
-#### 2.3 基本数据类型原子类的优势
+### 基本数据类型原子类的优势
通过一个简单例子带大家看一下基本数据类型原子类的优势
-**①多线程环境不使用原子类保证线程安全(基本数据类型)**
+**① 多线程环境不使用原子类保证线程安全(基本数据类型)**
```java
class Test {
private volatile int count = 0;
//若要线程安全执行执行count++,需要加锁
public synchronized void increment() {
- count++;
+ count++;
}
public int getCount() {
@@ -254,7 +236,8 @@ class Test {
}
}
```
-**②多线程环境使用原子类保证线程安全(基本数据类型)**
+
+**② 多线程环境使用原子类保证线程安全(基本数据类型)**
```java
class Test2 {
@@ -270,7 +253,8 @@ class Test2 {
}
```
-#### 2.4 AtomicInteger 线程安全原理简单分析
+
+### AtomicInteger 线程安全原理简单分析
AtomicInteger 类的部分源码:
@@ -291,16 +275,14 @@ AtomicInteger 类的部分源码:
AtomicInteger 类主要利用 CAS (compare and swap) + volatile 和 native 方法来保证原子操作,从而避免 synchronized 的高开销,执行效率大为提升。
-CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个volatile变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
-
+CAS 的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe 类的 objectFieldOffset() 方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外 value 是一个 volatile 变量,在内存中可见,因此 JVM 可以保证任何时刻任何线程总能拿到该变量的最新值。
-### 3 数组类型原子类
+## 数组类型原子类
-#### 3.1 数组类型原子类介绍
+### 数组类型原子类介绍
使用原子的方式更新数组里的某个元素
-
- AtomicIntegerArray:整形数组原子类
- AtomicLongArray:长整形数组原子类
- AtomicReferenceArray :引用类型数组原子类
@@ -318,7 +300,8 @@ public final int getAndAdd(int i, int delta) //获取 index=i 位置元素的值
boolean compareAndSet(int i, int expect, int update) //如果输入的数值等于预期值,则以原子方式将 index=i 位置的元素值设置为输入值(update)
public final void lazySet(int i, int newValue)//最终 将index=i 位置的元素设置为newValue,使用 lazySet 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
```
-#### 3.2 AtomicIntegerArray 常见方法使用
+
+### AtomicIntegerArray 常见方法使用
```java
@@ -345,9 +328,9 @@ public class AtomicIntegerArrayTest {
}
```
-### 4 引用类型原子类
+## 引用类型原子类
-#### 4.1 引用类型原子类介绍
+### 引用类型原子类介绍
基本类型原子类只能更新一个变量,如果需要原子更新多个变量,需要使用 引用类型原子类。
@@ -357,7 +340,7 @@ public class AtomicIntegerArrayTest {
上面三个类提供的方法几乎相同,所以我们这里以 AtomicReference 为例子来介绍。
-#### 4.2 AtomicReference 类使用示例
+### AtomicReference 类使用示例
```java
import java.util.concurrent.atomic.AtomicReference;
@@ -404,13 +387,15 @@ class Person {
}
```
+
上述代码首先创建了一个 Person 对象,然后把 Person 对象设置进 AtomicReference 对象中,然后调用 compareAndSet 方法,该方法就是通过 CAS 操作设置 ar。如果 ar 的值为 person 的话,则将其设置为 updatePerson。实现原理与 AtomicInteger 类中的 compareAndSet 方法相同。运行上面的代码后的输出结果如下:
```
Daisy
20
```
-#### 4.3 AtomicStampedReference 类使用示例
+
+### AtomicStampedReference 类使用示例
```java
import java.util.concurrent.atomic.AtomicStampedReference;
@@ -459,6 +444,7 @@ public class AtomicStampedReferenceDemo {
```
输出结果如下:
+
```
currentValue=0, currentStamp=0
currentValue=666, currentStamp=999, casResult=true
@@ -468,9 +454,9 @@ currentValue=0, currentStamp=0
currentValue=666, currentStamp=999, wCasResult=true
```
-#### 4.4 AtomicMarkableReference 类使用示例
+### AtomicMarkableReference 类使用示例
-``` java
+```java
import java.util.concurrent.atomic.AtomicMarkableReference;
public class AtomicMarkableReferenceDemo {
@@ -517,6 +503,7 @@ public class AtomicMarkableReferenceDemo {
```
输出结果如下:
+
```
currentValue=null, currentMark=false
currentValue=true, currentMark=true, casResult=true
@@ -526,9 +513,9 @@ currentValue=null, currentMark=false
currentValue=true, currentMark=true, wCasResult=true
```
-### 5 对象的属性修改类型原子类
+## 对象的属性修改类型原子类
-#### 5.1 对象的属性修改类型原子类介绍
+### 对象的属性修改类型原子类介绍
如果需要原子更新某个类里的某个字段时,需要用到对象的属性修改类型原子类。
@@ -540,7 +527,7 @@ currentValue=true, currentMark=true, wCasResult=true
上面三个类提供的方法几乎相同,所以我们这里以 `AtomicIntegerFieldUpdater`为例子来介绍。
-#### 5.2 AtomicIntegerFieldUpdater 类使用示例
+### AtomicIntegerFieldUpdater 类使用示例
```java
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
@@ -593,14 +580,4 @@ class User {
## Reference
-- 《Java并发编程的艺术》
-
-## 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
-
-**Java工程师必备学习资源:** 一些Java工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
-
-
\ No newline at end of file
+- 《Java 并发编程的艺术》
diff --git "a/docs/java/multi-thread/CompletableFuture\345\205\245\351\227\250.md" b/docs/java/concurrent/completablefuture-intro.md
similarity index 99%
rename from "docs/java/multi-thread/CompletableFuture\345\205\245\351\227\250.md"
rename to docs/java/concurrent/completablefuture-intro.md
index ad1a11a32b6..810d5a61708 100644
--- "a/docs/java/multi-thread/CompletableFuture\345\205\245\351\227\250.md"
+++ b/docs/java/concurrent/completablefuture-intro.md
@@ -1,3 +1,11 @@
+---
+title: CompletableFuture入门
+category: Java
+tag:
+ - Java并发
+---
+
+
自己在项目中使用 `CompletableFuture` 比较多,看到很多开源框架中也大量使用到了 `CompletableFuture` 。
因此,专门写一篇文章来介绍这个 Java 8 才被引入的一个非常有用的用于异步编程的类。
diff --git "a/docs/java/multi-thread/images/ThreadLocal\345\206\205\351\203\250\347\261\273.png" "b/docs/java/concurrent/images/ThreadLocal\345\206\205\351\203\250\347\261\273.png"
similarity index 100%
rename from "docs/java/multi-thread/images/ThreadLocal\345\206\205\351\203\250\347\261\273.png"
rename to "docs/java/concurrent/images/ThreadLocal\345\206\205\351\203\250\347\261\273.png"
diff --git "a/docs/java/multi-thread/images/interview-questions/synchronized\345\205\263\351\224\256\345\255\227.png" "b/docs/java/concurrent/images/interview-questions/synchronized\345\205\263\351\224\256\345\255\227.png"
similarity index 100%
rename from "docs/java/multi-thread/images/interview-questions/synchronized\345\205\263\351\224\256\345\255\227.png"
rename to "docs/java/concurrent/images/interview-questions/synchronized\345\205\263\351\224\256\345\255\227.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/CachedThreadPool-execute.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/CachedThreadPool-execute.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/CachedThreadPool-execute.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/CachedThreadPool-execute.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executors\345\267\245\345\205\267\347\261\273.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executors\345\267\245\345\205\267\347\261\273.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executors\345\267\245\345\205\267\347\261\273.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executors\345\267\245\345\205\267\347\261\273.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executor\346\241\206\346\236\266\347\232\204\344\275\277\347\224\250\347\244\272\346\204\217\345\233\276.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executor\346\241\206\346\236\266\347\232\204\344\275\277\347\224\250\347\244\272\346\204\217\345\233\276.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executor\346\241\206\346\236\266\347\232\204\344\275\277\347\224\250\347\244\272\346\204\217\345\233\276.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/Executor\346\241\206\346\236\266\347\232\204\344\275\277\347\224\250\347\244\272\346\204\217\345\233\276.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/FixedThreadPool.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/FixedThreadPool.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/FixedThreadPool.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/FixedThreadPool.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\211\247\350\241\214\345\221\250\346\234\237\344\273\273\345\212\241\346\255\245\351\252\244.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\211\247\350\241\214\345\221\250\346\234\237\344\273\273\345\212\241\346\255\245\351\252\244.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\211\247\350\241\214\345\221\250\346\234\237\344\273\273\345\212\241\346\255\245\351\252\244.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\211\247\350\241\214\345\221\250\346\234\237\344\273\273\345\212\241\346\255\245\351\252\244.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\234\272\345\210\266.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\234\272\345\210\266.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\234\272\345\210\266.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/ScheduledThreadPoolExecutor\346\234\272\345\210\266.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/SingleThreadExecutor.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/SingleThreadExecutor.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/SingleThreadExecutor.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/SingleThreadExecutor.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/threadpoolexecutor\346\236\204\351\200\240\345\207\275\346\225\260.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/threadpoolexecutor\346\236\204\351\200\240\345\207\275\346\225\260.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/threadpoolexecutor\346\236\204\351\200\240\345\207\275\346\225\260.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/threadpoolexecutor\346\236\204\351\200\240\345\207\275\346\225\260.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\344\273\273\345\212\241\347\232\204\346\211\247\350\241\214\347\233\270\345\205\263\346\216\245\345\217\243.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\344\273\273\345\212\241\347\232\204\346\211\247\350\241\214\347\233\270\345\205\263\346\216\245\345\217\243.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\344\273\273\345\212\241\347\232\204\346\211\247\350\241\214\347\233\270\345\205\263\346\216\245\345\217\243.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\344\273\273\345\212\241\347\232\204\346\211\247\350\241\214\347\233\270\345\205\263\346\216\245\345\217\243.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\345\233\276\350\247\243\347\272\277\347\250\213\346\261\240\345\256\236\347\216\260\345\216\237\347\220\206.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\345\233\276\350\247\243\347\272\277\347\250\213\346\261\240\345\256\236\347\216\260\345\216\237\347\220\206.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\345\233\276\350\247\243\347\272\277\347\250\213\346\261\240\345\256\236\347\216\260\345\216\237\347\220\206.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\345\233\276\350\247\243\347\272\277\347\250\213\346\261\240\345\256\236\347\216\260\345\216\237\347\220\206.png"
diff --git "a/docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\347\272\277\347\250\213\346\261\240\345\220\204\344\270\252\345\217\202\346\225\260\344\271\213\351\227\264\347\232\204\345\205\263\347\263\273.png" "b/docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\347\272\277\347\250\213\346\261\240\345\220\204\344\270\252\345\217\202\346\225\260\344\271\213\351\227\264\347\232\204\345\205\263\347\263\273.png"
similarity index 100%
rename from "docs/java/multi-thread/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\347\272\277\347\250\213\346\261\240\345\220\204\344\270\252\345\217\202\346\225\260\344\271\213\351\227\264\347\232\204\345\205\263\347\263\273.png"
rename to "docs/java/concurrent/images/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223/\347\272\277\347\250\213\346\261\240\345\220\204\344\270\252\345\217\202\346\225\260\344\271\213\351\227\264\347\232\204\345\205\263\347\263\273.png"
diff --git a/docs/java/multi-thread/images/thread-local/1.png b/docs/java/concurrent/images/thread-local/1.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/1.png
rename to docs/java/concurrent/images/thread-local/1.png
diff --git a/docs/java/multi-thread/images/thread-local/10.png b/docs/java/concurrent/images/thread-local/10.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/10.png
rename to docs/java/concurrent/images/thread-local/10.png
diff --git a/docs/java/multi-thread/images/thread-local/11.png b/docs/java/concurrent/images/thread-local/11.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/11.png
rename to docs/java/concurrent/images/thread-local/11.png
diff --git a/docs/java/multi-thread/images/thread-local/12.png b/docs/java/concurrent/images/thread-local/12.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/12.png
rename to docs/java/concurrent/images/thread-local/12.png
diff --git a/docs/java/multi-thread/images/thread-local/13.png b/docs/java/concurrent/images/thread-local/13.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/13.png
rename to docs/java/concurrent/images/thread-local/13.png
diff --git a/docs/java/multi-thread/images/thread-local/14.png b/docs/java/concurrent/images/thread-local/14.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/14.png
rename to docs/java/concurrent/images/thread-local/14.png
diff --git a/docs/java/multi-thread/images/thread-local/15.png b/docs/java/concurrent/images/thread-local/15.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/15.png
rename to docs/java/concurrent/images/thread-local/15.png
diff --git a/docs/java/multi-thread/images/thread-local/16.png b/docs/java/concurrent/images/thread-local/16.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/16.png
rename to docs/java/concurrent/images/thread-local/16.png
diff --git a/docs/java/multi-thread/images/thread-local/17.png b/docs/java/concurrent/images/thread-local/17.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/17.png
rename to docs/java/concurrent/images/thread-local/17.png
diff --git a/docs/java/multi-thread/images/thread-local/18.png b/docs/java/concurrent/images/thread-local/18.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/18.png
rename to docs/java/concurrent/images/thread-local/18.png
diff --git a/docs/java/multi-thread/images/thread-local/19.png b/docs/java/concurrent/images/thread-local/19.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/19.png
rename to docs/java/concurrent/images/thread-local/19.png
diff --git a/docs/java/multi-thread/images/thread-local/2.png b/docs/java/concurrent/images/thread-local/2.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/2.png
rename to docs/java/concurrent/images/thread-local/2.png
diff --git a/docs/java/multi-thread/images/thread-local/20.png b/docs/java/concurrent/images/thread-local/20.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/20.png
rename to docs/java/concurrent/images/thread-local/20.png
diff --git a/docs/java/multi-thread/images/thread-local/21.png b/docs/java/concurrent/images/thread-local/21.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/21.png
rename to docs/java/concurrent/images/thread-local/21.png
diff --git a/docs/java/multi-thread/images/thread-local/22.png b/docs/java/concurrent/images/thread-local/22.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/22.png
rename to docs/java/concurrent/images/thread-local/22.png
diff --git a/docs/java/multi-thread/images/thread-local/23.png b/docs/java/concurrent/images/thread-local/23.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/23.png
rename to docs/java/concurrent/images/thread-local/23.png
diff --git a/docs/java/multi-thread/images/thread-local/24.png b/docs/java/concurrent/images/thread-local/24.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/24.png
rename to docs/java/concurrent/images/thread-local/24.png
diff --git a/docs/java/multi-thread/images/thread-local/25.png b/docs/java/concurrent/images/thread-local/25.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/25.png
rename to docs/java/concurrent/images/thread-local/25.png
diff --git a/docs/java/multi-thread/images/thread-local/26.png b/docs/java/concurrent/images/thread-local/26.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/26.png
rename to docs/java/concurrent/images/thread-local/26.png
diff --git a/docs/java/multi-thread/images/thread-local/27.png b/docs/java/concurrent/images/thread-local/27.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/27.png
rename to docs/java/concurrent/images/thread-local/27.png
diff --git a/docs/java/multi-thread/images/thread-local/28.png b/docs/java/concurrent/images/thread-local/28.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/28.png
rename to docs/java/concurrent/images/thread-local/28.png
diff --git a/docs/java/multi-thread/images/thread-local/29.png b/docs/java/concurrent/images/thread-local/29.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/29.png
rename to docs/java/concurrent/images/thread-local/29.png
diff --git a/docs/java/multi-thread/images/thread-local/3.png b/docs/java/concurrent/images/thread-local/3.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/3.png
rename to docs/java/concurrent/images/thread-local/3.png
diff --git a/docs/java/multi-thread/images/thread-local/30.png b/docs/java/concurrent/images/thread-local/30.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/30.png
rename to docs/java/concurrent/images/thread-local/30.png
diff --git a/docs/java/multi-thread/images/thread-local/31.png b/docs/java/concurrent/images/thread-local/31.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/31.png
rename to docs/java/concurrent/images/thread-local/31.png
diff --git a/docs/java/multi-thread/images/thread-local/4.png b/docs/java/concurrent/images/thread-local/4.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/4.png
rename to docs/java/concurrent/images/thread-local/4.png
diff --git a/docs/java/multi-thread/images/thread-local/5.png b/docs/java/concurrent/images/thread-local/5.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/5.png
rename to docs/java/concurrent/images/thread-local/5.png
diff --git a/docs/java/multi-thread/images/thread-local/6.png b/docs/java/concurrent/images/thread-local/6.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/6.png
rename to docs/java/concurrent/images/thread-local/6.png
diff --git a/docs/java/multi-thread/images/thread-local/7.png b/docs/java/concurrent/images/thread-local/7.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/7.png
rename to docs/java/concurrent/images/thread-local/7.png
diff --git a/docs/java/multi-thread/images/thread-local/8.png b/docs/java/concurrent/images/thread-local/8.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/8.png
rename to docs/java/concurrent/images/thread-local/8.png
diff --git a/docs/java/multi-thread/images/thread-local/9.png b/docs/java/concurrent/images/thread-local/9.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-local/9.png
rename to docs/java/concurrent/images/thread-local/9.png
diff --git a/docs/java/multi-thread/images/thread-pool/19a0255a-6ef3-4835-98d1-a839d1983332.png b/docs/java/concurrent/images/thread-pool/19a0255a-6ef3-4835-98d1-a839d1983332.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-pool/19a0255a-6ef3-4835-98d1-a839d1983332.png
rename to docs/java/concurrent/images/thread-pool/19a0255a-6ef3-4835-98d1-a839d1983332.png
diff --git a/docs/java/multi-thread/images/thread-pool/1bc44c67-26ba-42ab-bcb8-4e29e6fd99b9.png b/docs/java/concurrent/images/thread-pool/1bc44c67-26ba-42ab-bcb8-4e29e6fd99b9.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-pool/1bc44c67-26ba-42ab-bcb8-4e29e6fd99b9.png
rename to docs/java/concurrent/images/thread-pool/1bc44c67-26ba-42ab-bcb8-4e29e6fd99b9.png
diff --git a/docs/java/multi-thread/images/thread-pool/5b9b814d-722a-4116-b066-43dc80fc1dc4.png b/docs/java/concurrent/images/thread-pool/5b9b814d-722a-4116-b066-43dc80fc1dc4.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-pool/5b9b814d-722a-4116-b066-43dc80fc1dc4.png
rename to docs/java/concurrent/images/thread-pool/5b9b814d-722a-4116-b066-43dc80fc1dc4.png
diff --git a/docs/java/multi-thread/images/thread-pool/b6fd95a7-4c9d-4fc6-ad26-890adb3f6c4c.png b/docs/java/concurrent/images/thread-pool/b6fd95a7-4c9d-4fc6-ad26-890adb3f6c4c.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-pool/b6fd95a7-4c9d-4fc6-ad26-890adb3f6c4c.png
rename to docs/java/concurrent/images/thread-pool/b6fd95a7-4c9d-4fc6-ad26-890adb3f6c4c.png
diff --git a/docs/java/multi-thread/images/thread-pool/ddf22709-bff5-45b4-acb7-a3f2e6798608.png b/docs/java/concurrent/images/thread-pool/ddf22709-bff5-45b4-acb7-a3f2e6798608.png
similarity index 100%
rename from docs/java/multi-thread/images/thread-pool/ddf22709-bff5-45b4-acb7-a3f2e6798608.png
rename to docs/java/concurrent/images/thread-pool/ddf22709-bff5-45b4-acb7-a3f2e6798608.png
diff --git "a/docs/java/multi-thread/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.drawio" "b/docs/java/concurrent/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.drawio"
similarity index 100%
rename from "docs/java/multi-thread/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.drawio"
rename to "docs/java/concurrent/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.drawio"
diff --git "a/docs/java/multi-thread/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.png" "b/docs/java/concurrent/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.png"
similarity index 100%
rename from "docs/java/multi-thread/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.png"
rename to "docs/java/concurrent/images/thread-pool/\347\272\277\347\250\213\346\261\240\344\275\277\347\224\250\344\270\215\345\275\223\345\257\274\350\207\264\346\255\273\351\224\201.png"
diff --git "a/docs/java/multi-thread/images/threadlocal\346\225\260\346\215\256\347\273\223\346\236\204.png" "b/docs/java/concurrent/images/threadlocal\346\225\260\346\215\256\347\273\223\346\236\204.png"
similarity index 100%
rename from "docs/java/multi-thread/images/threadlocal\346\225\260\346\215\256\347\273\223\346\236\204.png"
rename to "docs/java/concurrent/images/threadlocal\346\225\260\346\215\256\347\273\223\346\236\204.png"
diff --git "a/docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257.png" "b/docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257.png"
similarity index 100%
rename from "docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257.png"
rename to "docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/Java\345\271\266\345\217\221\347\274\226\347\250\213\347\232\204\350\211\272\346\234\257.png"
diff --git "a/docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/javaguide-\345\271\266\345\217\221.png" "b/docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/javaguide-\345\271\266\345\217\221.png"
similarity index 100%
rename from "docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/javaguide-\345\271\266\345\217\221.png"
rename to "docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/javaguide-\345\271\266\345\217\221.png"
diff --git "a/docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/java\345\271\266\345\217\221\347\274\226\347\250\213\344\271\213\347\276\216.png" "b/docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/java\345\271\266\345\217\221\347\274\226\347\250\213\344\271\213\347\276\216.png"
similarity index 100%
rename from "docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/java\345\271\266\345\217\221\347\274\226\347\250\213\344\271\213\347\276\216.png"
rename to "docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/java\345\271\266\345\217\221\347\274\226\347\250\213\344\271\213\347\276\216.png"
diff --git "a/docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\345\256\236\346\210\230Java\351\253\230\345\271\266\345\217\221\347\250\213\345\272\217\350\256\276\350\256\241.png" "b/docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\345\256\236\346\210\230Java\351\253\230\345\271\266\345\217\221\347\250\213\345\272\217\350\256\276\350\256\241.png"
similarity index 100%
rename from "docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\345\256\236\346\210\230Java\351\253\230\345\271\266\345\217\221\347\250\213\345\272\217\350\256\276\350\256\241.png"
rename to "docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\345\256\236\346\210\230Java\351\253\230\345\271\266\345\217\221\347\250\213\345\272\217\350\256\276\350\256\241.png"
diff --git "a/docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\346\267\261\345\205\245\346\265\205\345\207\272Java\345\244\232\347\272\277\347\250\213.png" "b/docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\346\267\261\345\205\245\346\265\205\345\207\272Java\345\244\232\347\272\277\347\250\213.png"
similarity index 100%
rename from "docs/java/multi-thread/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\346\267\261\345\205\245\346\265\205\345\207\272Java\345\244\232\347\272\277\347\250\213.png"
rename to "docs/java/concurrent/images/\345\244\232\347\272\277\347\250\213\345\255\246\344\271\240\346\214\207\345\215\227/\346\267\261\345\205\245\346\265\205\345\207\272Java\345\244\232\347\272\277\347\250\213.png"
diff --git "a/docs/java/multi-thread/Java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/docs/java/concurrent/java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 82%
rename from "docs/java/multi-thread/Java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index e79ab7b7713..2cf5c7cf22e 100644
--- "a/docs/java/multi-thread/Java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/java\345\271\266\345\217\221\345\237\272\347\241\200\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,33 +1,13 @@
-
-
-- [Java 并发基础常见面试题总结](#Java-并发基础常见面试题总结)
- - [1. 什么是线程和进程?](#1-什么是线程和进程)
- - [1.1. 何为进程?](#11-何为进程)
- - [1.2. 何为线程?](#12-何为线程)
- - [2. 请简要描述线程与进程的关系,区别及优缺点?](#2-请简要描述线程与进程的关系区别及优缺点)
- - [2.1. 图解进程和线程的关系](#21-图解进程和线程的关系)
- - [2.2. 程序计数器为什么是私有的?](#22-程序计数器为什么是私有的)
- - [2.3. 虚拟机栈和本地方法栈为什么是私有的?](#23-虚拟机栈和本地方法栈为什么是私有的)
- - [2.4. 一句话简单了解堆和方法区](#24-一句话简单了解堆和方法区)
- - [3. 说说并发与并行的区别?](#3-说说并发与并行的区别)
- - [4. 为什么要使用多线程呢?](#4-为什么要使用多线程呢)
- - [5. 使用多线程可能带来什么问题?](#5-使用多线程可能带来什么问题)
- - [6. 说说线程的生命周期和状态?](#6-说说线程的生命周期和状态)
- - [7. 什么是上下文切换?](#7-什么是上下文切换)
- - [8. 什么是线程死锁?如何避免死锁?](#8-什么是线程死锁如何避免死锁)
- - [8.1. 认识线程死锁](#81-认识线程死锁)
- - [8.2. 如何避免线程死锁?](#82-如何避免线程死锁)
- - [9. 说说 sleep() 方法和 wait() 方法区别和共同点?](#9-说说-sleep-方法和-wait-方法区别和共同点)
- - [10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?](#10-为什么我们调用-start-方法时会执行-run-方法为什么我们不能直接调用-run-方法)
- - [公众号](#公众号)
-
-
-
-# Java 并发基础常见面试题总结
-
-## 1. 什么是线程和进程?
-
-### 1.1. 何为进程?
+---
+title: Java 并发常见知识点&面试题总结(基础篇)
+category: Java
+tag:
+ - Java并发
+---
+
+## 什么是线程和进程?
+
+### 何为进程?
进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。
@@ -37,7 +17,7 @@

-### 1.2. 何为线程?
+### 何为线程?
线程与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享进程的**堆**和**方法区**资源,但每个线程有自己的**程序计数器**、**虚拟机栈**和**本地方法栈**,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
@@ -70,17 +50,15 @@ public class MultiThread {
从上面的输出内容可以看出:**一个 Java 程序的运行是 main 线程和多个其他线程同时运行**。
-## 2. 请简要描述线程与进程的关系,区别及优缺点?
+## 请简要描述线程与进程的关系,区别及优缺点?
**从 JVM 角度说进程和线程之间的关系**
-### 2.1. 图解进程和线程的关系
+### 图解进程和线程的关系
-下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。如果你对 Java 内存区域 (运行时数据区) 这部分知识不太了解的话可以阅读一下这篇文章:[《可能是把 Java 内存区域讲的最清楚的一篇文章》](https://github.com/Snailclimb/JavaGuide/blob/3965c02cc0f294b0bd3580df4868d5e396959e2e/Java%E7%9B%B8%E5%85%B3/%E5%8F%AF%E8%83%BD%E6%98%AF%E6%8A%8AJava%E5%86%85%E5%AD%98%E5%8C%BA%E5%9F%9F%E8%AE%B2%E7%9A%84%E6%9C%80%E6%B8%85%E6%A5%9A%E7%9A%84%E4%B8%80%E7%AF%87%E6%96%87%E7%AB%A0.md "《可能是把 Java 内存区域讲的最清楚的一篇文章》")
+下图是 Java 内存区域,通过下图我们从 JVM 的角度来说一下线程和进程之间的关系。
-
-
-
+
从上图可以看出:一个进程中可以有多个线程,多个线程共享进程的**堆**和**方法区 (JDK1.8 之后的元空间)**资源,但是每个线程有自己的**程序计数器**、**虚拟机栈** 和 **本地方法栈**。
@@ -90,7 +68,7 @@ public class MultiThread {
下面来思考这样一个问题:为什么**程序计数器**、**虚拟机栈**和**本地方法栈**是线程私有的呢?为什么堆和方法区是线程共享的呢?
-### 2.2. 程序计数器为什么是私有的?
+### 程序计数器为什么是私有的?
程序计数器主要有下面两个作用:
@@ -101,23 +79,23 @@ public class MultiThread {
所以,程序计数器私有主要是为了**线程切换后能恢复到正确的执行位置**。
-### 2.3. 虚拟机栈和本地方法栈为什么是私有的?
+### 虚拟机栈和本地方法栈为什么是私有的?
- **虚拟机栈:** 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
- **本地方法栈:** 和虚拟机栈所发挥的作用非常相似,区别是: **虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。** 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。
所以,为了**保证线程中的局部变量不被别的线程访问到**,虚拟机栈和本地方法栈是线程私有的。
-### 2.4. 一句话简单了解堆和方法区
+### 一句话简单了解堆和方法区
堆和方法区是所有线程共享的资源,其中堆是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存),方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
-## 3. 说说并发与并行的区别?
+## 说说并发与并行的区别?
- **并发:** 同一时间段,多个任务都在执行 (单位时间内不一定同时执行);
- **并行:** 单位时间内,多个任务同时执行。
-## 4. 为什么要使用多线程呢?
+## 为什么要使用多线程呢?
先从总体上来说:
@@ -129,11 +107,11 @@ public class MultiThread {
- **单核时代**: 在单核时代多线程主要是为了提高单进程利用 CPU 和 IO 系统的效率。 假设只运行了一个 Java 进程的情况,当我们请求 IO 的时候,如果 Java 进程中只有一个线程,此线程被 IO 阻塞则整个进程被阻塞。CPU 和 IO 设备只有一个在运行,那么可以简单地说系统整体效率只有 50%。当使用多线程的时候,一个线程被 IO 阻塞,其他线程还可以继续使用 CPU。从而提高了 Java 进程利用系统资源的整体效率。
- **多核时代**: 多核时代多线程主要是为了提高进程利用多核 CPU 的能力。举个例子:假如我们要计算一个复杂的任务,我们只用一个线程的话,不论系统有几个 CPU 核心,都只会有一个 CPU 核心被利用到。而创建多个线程,这些线程可以被映射到底层多个 CPU 上执行,在任务中的多个线程没有资源竞争的情况下,任务执行的效率会有显著性的提高,约等于(单核时执行时间/CPU 核心数)。
-## 5. 使用多线程可能带来什么问题?
+## 使用多线程可能带来什么问题?
并发编程的目的就是为了能提高程序的执行效率提高程序运行速度,但是并发编程并不总是能提高程序运行速度的,而且并发编程可能会遇到很多问题,比如:内存泄漏、死锁、线程不安全等等。
-## 6. 说说线程的生命周期和状态?
+## 说说线程的生命周期和状态?
Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态(图源《Java 并发编程艺术》4.1.4 节)。
@@ -157,7 +135,7 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
相关阅读:[挑错 |《Java 并发编程的艺术》中关于线程状态的三处错误](https://mp.weixin.qq.com/s/UOrXql_LhOD8dhTq_EPI0w) 。
-## 7. 什么是上下文切换?
+## 什么是上下文切换?
线程在执行过程中会有自己的运行条件和状态(也称上下文),比如上文所说到过的程序计数器,栈信息等。当出现如下情况的时候,线程会从占用 CPU 状态中退出。
- 主动让出 CPU,比如调用了 `sleep()`, `wait()` 等。
@@ -169,9 +147,9 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种
上下文切换是现代操作系统的基本功能,因其每次需要保存信息恢复信息,这将会占用 CPU,内存等系统资源进行处理,也就意味着效率会有一定损耗,如果频繁切换就会造成整体效率低下。
-## 8. 什么是线程死锁?如何避免死锁?
+## 什么是线程死锁?如何避免死锁?
-### 8.1. 认识线程死锁
+### 认识线程死锁
线程死锁描述的是这样一种情况:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
@@ -238,7 +216,7 @@ Thread[线程 2,5,main]waiting get resource1
3. 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源。
4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
-### 8.2. 如何预防和避免线程死锁?
+### 如何预防和避免线程死锁?
**如何预防死锁?** 破坏死锁的产生的必要条件即可:
@@ -288,27 +266,17 @@ Process finished with exit code 0
线程 1 首先获得到 resource1 的监视器锁,这时候线程 2 就获取不到了。然后线程 1 再去获取 resource2 的监视器锁,可以获取到。然后线程 1 释放了对 resource1、resource2 的监视器锁的占用,线程 2 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。
-## 9. 说说 sleep() 方法和 wait() 方法区别和共同点?
+## 说说 sleep() 方法和 wait() 方法区别和共同点?
- 两者最主要的区别在于:**`sleep()` 方法没有释放锁,而 `wait()` 方法释放了锁** 。
- 两者都可以暂停线程的执行。
- `wait()` 通常被用于线程间交互/通信,`sleep() `通常被用于暂停执行。
- `wait()` 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 `notify() `或者 `notifyAll()` 方法。`sleep() `方法执行完成后,线程会自动苏醒。或者可以使用 `wait(long timeout)` 超时后线程会自动苏醒。
-## 10. 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
+## 为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?
这是另一个非常经典的 Java 多线程面试问题,而且在面试中会经常被问到。很简单,但是很多人都会答不上来!
new 一个 Thread,线程进入了新建状态。调用 `start()`方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 `start()` 会执行线程的相应准备工作,然后自动执行 `run()` 方法的内容,这是真正的多线程工作。 但是,直接执行 `run()` 方法,会把 `run()` 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。
**总结: 调用 `start()` 方法方可启动线程并使线程进入就绪状态,直接执行 `run()` 方法的话不会以多线程的方式执行。**
-
-## 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V2.0 PDF 版本[公众号](#公众号 "公众号")后台回复 **"面试突击"** 即可免费领取!
-
-**Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
-
-
diff --git "a/docs/java/multi-thread/Java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md" "b/docs/java/concurrent/java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
similarity index 92%
rename from "docs/java/multi-thread/Java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
index 4a2e61b16e1..2278eaf1b08 100644
--- "a/docs/java/multi-thread/Java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/java\345\271\266\345\217\221\350\277\233\351\230\266\345\270\270\350\247\201\351\235\242\350\257\225\351\242\230\346\200\273\347\273\223.md"
@@ -1,64 +1,9 @@
-点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java 面试突击》以及 Java 工程师必备学习资源。
-
-
-
-
-
-
-- [Java 并发进阶常见面试题总结](#java-并发进阶常见面试题总结)
- - [1.synchronized 关键字](#1synchronized-关键字)
- - [1.1.说一说自己对于 synchronized 关键字的了解](#11说一说自己对于-synchronized-关键字的了解)
- - [1.2. 说说自己是怎么使用 synchronized 关键字](#12-说说自己是怎么使用-synchronized-关键字)
- - [1.3. 构造方法可以使用 synchronized 关键字修饰么?](#13-构造方法可以使用-synchronized-关键字修饰么)
- - [1.3. 讲一下 synchronized 关键字的底层原理](#13-讲一下-synchronized-关键字的底层原理)
- - [1.3.1. synchronized 同步语句块的情况](#131-synchronized-同步语句块的情况)
- - [1.3.2. synchronized 修饰方法的的情况](#132-synchronized-修饰方法的的情况)
- - [1.3.3.总结](#133总结)
- - [1.4. 说说 JDK1.6 之后的 synchronized 关键字底层做了哪些优化,可以详细介绍一下这些优化吗](#14-说说-jdk16-之后的-synchronized-关键字底层做了哪些优化可以详细介绍一下这些优化吗)
- - [1.5. 谈谈 synchronized 和 ReentrantLock 的区别](#15-谈谈-synchronized-和-reentrantlock-的区别)
- - [1.5.1. 两者都是可重入锁](#151-两者都是可重入锁)
- - [1.5.2.synchronized 依赖于 JVM 而 ReentrantLock 依赖于 API](#152synchronized-依赖于-jvm-而-reentrantlock-依赖于-api)
- - [1.5.3.ReentrantLock 比 synchronized 增加了一些高级功能](#153reentrantlock-比-synchronized-增加了一些高级功能)
- - [2. volatile 关键字](#2-volatile-关键字)
- - [2.1. CPU 缓存模型](#21-cpu-缓存模型)
- - [2.2. 讲一下 JMM(Java 内存模型)](#22-讲一下-jmmjava-内存模型)
- - [2.3. 并发编程的三个重要特性](#23-并发编程的三个重要特性)
- - [2.4. 说说 synchronized 关键字和 volatile 关键字的区别](#24-说说-synchronized-关键字和-volatile-关键字的区别)
- - [3. ThreadLocal](#3-threadlocal)
- - [3.1. ThreadLocal 简介](#31-threadlocal-简介)
- - [3.2. ThreadLocal 示例](#32-threadlocal-示例)
- - [3.3. ThreadLocal 原理](#33-threadlocal-原理)
- - [3.4. ThreadLocal 内存泄露问题](#34-threadlocal-内存泄露问题)
- - [4. 线程池](#4-线程池)
- - [4.1. 为什么要用线程池?](#41-为什么要用线程池)
- - [4.2. 实现 Runnable 接口和 Callable 接口的区别](#42-实现-runnable-接口和-callable-接口的区别)
- - [4.3. 执行 execute()方法和 submit()方法的区别是什么呢?](#43-执行-execute方法和-submit方法的区别是什么呢)
- - [4.4. 如何创建线程池](#44-如何创建线程池)
- - [4.5 ThreadPoolExecutor 类分析](#45-threadpoolexecutor-类分析)
- - [4.5.1 `ThreadPoolExecutor`构造函数重要参数分析](#451-threadpoolexecutor构造函数重要参数分析)
- - [4.5.2 `ThreadPoolExecutor` 饱和策略](#452-threadpoolexecutor-饱和策略)
- - [4.6 一个简单的线程池 Demo](#46-一个简单的线程池-demo)
- - [4.7 线程池原理分析](#47-线程池原理分析)
- - [5. Atomic 原子类](#5-atomic-原子类)
- - [5.1. 介绍一下 Atomic 原子类](#51-介绍一下-atomic-原子类)
- - [5.2. JUC 包中的原子类是哪 4 类?](#52-juc-包中的原子类是哪-4-类)
- - [5.3. 讲讲 AtomicInteger 的使用](#53-讲讲-atomicinteger-的使用)
- - [5.4. 能不能给我简单介绍一下 AtomicInteger 类的原理](#54-能不能给我简单介绍一下-atomicinteger-类的原理)
- - [6. AQS](#6-aqs)
- - [6.1. AQS 介绍](#61-aqs-介绍)
- - [6.2. AQS 原理分析](#62-aqs-原理分析)
- - [6.2.1. AQS 原理概览](#621-aqs-原理概览)
- - [6.2.2. AQS 对资源的共享方式](#622-aqs-对资源的共享方式)
- - [6.2.3. AQS 底层使用了模板方法模式](#623-aqs-底层使用了模板方法模式)
- - [6.3. AQS 组件总结](#63-aqs-组件总结)
- - [6.4. 用过 CountDownLatch 么?什么场景下用的?](#64-用过-countdownlatch-么什么场景下用的)
- - [7 Reference](#7-reference)
- - [公众号](#公众号)
-
-
-
-
-# Java 并发进阶常见面试题总结
+---
+title: Java 并发常见知识点&面试题总结(进阶篇)
+category: Java
+tag:
+ - Java并发
+---
## 1.synchronized 关键字
@@ -1105,13 +1050,3 @@ CompletableFuture allFutures = CompletableFuture.allOf(
- https://www.cnblogs.com/waterystone/p/4920797.html
- https://www.cnblogs.com/chengxiao/archive/2017/07/24/7141160.html
-
-
-## 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可免费领取!
-
-**Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
-
-
diff --git "a/docs/java/multi-thread/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md" "b/docs/java/concurrent/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md"
similarity index 99%
rename from "docs/java/multi-thread/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md"
index b861d521f31..1140df91c48 100644
--- "a/docs/java/multi-thread/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/java\347\272\277\347\250\213\346\261\240\345\255\246\344\271\240\346\200\273\347\273\223.md"
@@ -1,3 +1,12 @@
+---
+title: Java线程池学习总结
+category: Java
+tag:
+ - Java并发
+---
+
+
+
## 一 使用线程池的好处
> **池化技术想必大家已经屡见不鲜了,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。**
diff --git a/docs/java/concurrent/reentrantlock.md b/docs/java/concurrent/reentrantlock.md
new file mode 100644
index 00000000000..fad97ff4dc7
--- /dev/null
+++ b/docs/java/concurrent/reentrantlock.md
@@ -0,0 +1,994 @@
+---
+title: 从ReentrantLock的实现看AQS的原理及应用
+category: Java
+tag:
+ - Java并发
+---
+
+> 本文转载自:https://tech.meituan.com/2019/12/05/aqs-theory-and-apply.html
+>
+> 作者:美团技术团队
+
+## 前言
+
+Java中的大部分同步类(Lock、Semaphore、ReentrantLock等)都是基于AbstractQueuedSynchronizer(简称为AQS)实现的。AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。本文会从应用层逐渐深入到原理层,并通过ReentrantLock的基本特性和ReentrantLock与AQS的关联,来深入解读AQS相关独占锁的知识点,同时采取问答的模式来帮助大家理解AQS。由于篇幅原因,本篇文章主要阐述AQS中独占锁的逻辑和Sync Queue,不讲述包含共享锁和Condition Queue的部分(本篇文章核心为AQS原理剖析,只是简单介绍了ReentrantLock,感兴趣同学可以阅读一下ReentrantLock的源码)。
+
+## 1 ReentrantLock
+
+### 1.1 ReentrantLock特性概览
+
+ReentrantLock意思为可重入锁,指的是一个线程能够对一个临界资源重复加锁。为了帮助大家更好地理解ReentrantLock的特性,我们先将ReentrantLock跟常用的Synchronized进行比较,其特性如下(蓝色部分为本篇文章主要剖析的点):
+
+
+
+下面通过伪代码,进行更加直观的比较:
+
+```java
+// **************************Synchronized的使用方式**************************
+// 1.用于代码块
+synchronized (this) {}
+// 2.用于对象
+synchronized (object) {}
+// 3.用于方法
+public synchronized void test () {}
+// 4.可重入
+for (int i = 0; i < 100; i++) {
+ synchronized (this) {}
+}
+// **************************ReentrantLock的使用方式**************************
+public void test () throw Exception {
+ // 1.初始化选择公平锁、非公平锁
+ ReentrantLock lock = new ReentrantLock(true);
+ // 2.可用于代码块
+ lock.lock();
+ try {
+ try {
+ // 3.支持多种加锁方式,比较灵活; 具有可重入特性
+ if(lock.tryLock(100, TimeUnit.MILLISECONDS)){ }
+ } finally {
+ // 4.手动释放锁
+ lock.unlock()
+ }
+ } finally {
+ lock.unlock();
+ }
+}
+```
+
+### 1.2 ReentrantLock与AQS的关联
+
+通过上文我们已经了解,ReentrantLock支持公平锁和非公平锁(关于公平锁和非公平锁的原理分析,可参考《[不可不说的Java“锁”事](https://mp.weixin.qq.com/s?__biz=MjM5NjQ5MTI5OA==&mid=2651749434&idx=3&sn=5ffa63ad47fe166f2f1a9f604ed10091&chksm=bd12a5778a652c61509d9e718ab086ff27ad8768586ea9b38c3dcf9e017a8e49bcae3df9bcc8&scene=38#wechat_redirect)》),并且ReentrantLock的底层就是由AQS来实现的。那么ReentrantLock是如何通过公平锁和非公平锁与AQS关联起来呢? 我们着重从这两者的加锁过程来理解一下它们与AQS之间的关系(加锁过程中与AQS的关联比较明显,解锁流程后续会介绍)。
+
+非公平锁源码中的加锁流程如下:
+
+```java
+// java.util.concurrent.locks.ReentrantLock#NonfairSync
+
+// 非公平锁
+static final class NonfairSync extends Sync {
+ ...
+ final void lock() {
+ if (compareAndSetState(0, 1))
+ setExclusiveOwnerThread(Thread.currentThread());
+ else
+ acquire(1);
+ }
+ ...
+}
+```
+
+这块代码的含义为:
+
+- 若通过CAS设置变量State(同步状态)成功,也就是获取锁成功,则将当前线程设置为独占线程。
+- 若通过CAS设置变量State(同步状态)失败,也就是获取锁失败,则进入Acquire方法进行后续处理。
+
+第一步很好理解,但第二步获取锁失败后,后续的处理策略是怎么样的呢?这块可能会有以下思考:
+
+- 某个线程获取锁失败的后续流程是什么呢?有以下两种可能:
+
+(1) 将当前线程获锁结果设置为失败,获取锁流程结束。这种设计会极大降低系统的并发度,并不满足我们实际的需求。所以就需要下面这种流程,也就是AQS框架的处理流程。
+
+(2) 存在某种排队等候机制,线程继续等待,仍然保留获取锁的可能,获取锁流程仍在继续。
+
+- 对于问题1的第二种情况,既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?
+- 处于排队等候机制中的线程,什么时候可以有机会获取锁呢?
+- 如果处于排队等候机制中的线程一直无法获取锁,还是需要一直等待吗,还是有别的策略来解决这一问题?
+
+带着非公平锁的这些问题,再看下公平锁源码中获锁的方式:
+
+```
+// java.util.concurrent.locks.ReentrantLock#FairSync
+
+static final class FairSync extends Sync {
+ ...
+ final void lock() {
+ acquire(1);
+ }
+ ...
+}
+```
+
+看到这块代码,我们可能会存在这种疑问:Lock函数通过Acquire方法进行加锁,但是具体是如何加锁的呢?
+
+结合公平锁和非公平锁的加锁流程,虽然流程上有一定的不同,但是都调用了Acquire方法,而Acquire方法是FairSync和UnfairSync的父类AQS中的核心方法。
+
+对于上边提到的问题,其实在ReentrantLock类源码中都无法解答,而这些问题的答案,都是位于Acquire方法所在的类AbstractQueuedSynchronizer中,也就是本文的核心——AQS。下面我们会对AQS以及ReentrantLock和AQS的关联做详细介绍(相关问题答案会在2.3.5小节中解答)。
+
+## 2 AQS
+
+首先,我们通过下面的架构图来整体了解一下AQS框架:
+
+
+
+- 上图中有颜色的为Method,无颜色的为Attribution。
+- 总的来说,AQS框架共分为五层,自上而下由浅入深,从AQS对外暴露的API到底层基础数据。
+- 当有自定义同步器接入时,只需重写第一层所需要的部分方法即可,不需要关注底层具体的实现流程。当自定义同步器进行加锁或者解锁操作时,先经过第一层的API进入AQS内部方法,然后经过第二层进行锁的获取,接着对于获取锁失败的流程,进入第三层和第四层的等待队列处理,而这些处理方式均依赖于第五层的基础数据提供层。
+
+下面我们会从整体到细节,从流程到方法逐一剖析AQS框架,主要分析过程如下:
+
+
+
+### 2.1 原理概览
+
+AQS核心思想是,如果被请求的共享资源空闲,那么就将当前请求资源的线程设置为有效的工作线程,将共享资源设置为锁定状态;如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中。
+
+CLH:Craig、Landin and Hagersten队列,是单向链表,AQS中的队列是CLH变体的虚拟双向队列(FIFO),AQS是通过将每条请求共享资源的线程封装成一个节点来实现锁的分配。
+
+主要原理图如下:
+
+
+
+AQS使用一个Volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,通过CAS完成对State值的修改。
+
+#### 2.1.1 AQS数据结构
+
+先来看下AQS中最基本的数据结构——Node,Node即为上面CLH变体队列中的节点。
+
+
+
+解释一下几个方法和属性值的含义:
+
+| 方法和属性值 | 含义 |
+| :----------- | :----------------------------------------------------------- |
+| waitStatus | 当前节点在队列中的状态 |
+| thread | 表示处于该节点的线程 |
+| prev | 前驱指针 |
+| predecessor | 返回前驱节点,没有的话抛出npe |
+| nextWaiter | 指向下一个处于CONDITION状态的节点(由于本篇文章不讲述Condition Queue队列,这个指针不多介绍) |
+| next | 后继指针 |
+
+线程两种锁的模式:
+
+| 模式 | 含义 |
+| :-------- | :----------------------------- |
+| SHARED | 表示线程以共享的模式等待锁 |
+| EXCLUSIVE | 表示线程正在以独占的方式等待锁 |
+
+waitStatus有下面几个枚举值:
+
+| 枚举 | 含义 |
+| :-------- | :--------------------------------------------- |
+| 0 | 当一个Node被初始化的时候的默认值 |
+| CANCELLED | 为1,表示线程获取锁的请求已经取消了 |
+| CONDITION | 为-2,表示节点在等待队列中,节点线程等待唤醒 |
+| PROPAGATE | 为-3,当前线程处在SHARED情况下,该字段才会使用 |
+| SIGNAL | 为-1,表示线程已经准备好了,就等资源释放了 |
+
+#### 2.1.2 同步状态State
+
+在了解数据结构后,接下来了解一下AQS的同步状态——State。AQS中维护了一个名为state的字段,意为同步状态,是由Volatile修饰的,用于展示当前临界资源的获锁情况。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private volatile int state;
+```
+
+下面提供了几个访问这个字段的方法:
+
+| 方法名 | 描述 |
+| :----------------------------------------------------------- | :------------------- |
+| protected final int getState() | 获取State的值 |
+| protected final void setState(int newState) | 设置State的值 |
+| protected final boolean compareAndSetState(int expect, int update) | 使用CAS方式更新State |
+
+这几个方法都是Final修饰的,说明子类中无法重写它们。我们可以通过修改State字段表示的同步状态来实现多线程的独占模式和共享模式(加锁过程)。
+
+
+
+
+
+对于我们自定义的同步工具,需要自定义获取同步状态和释放状态的方式,也就是AQS架构图中的第一层:API层。
+
+## 2.2 AQS重要方法与ReentrantLock的关联
+
+从架构图中可以得知,AQS提供了大量用于自定义同步器实现的Protected方法。自定义同步器实现的相关方法也只是为了通过修改State字段来实现多线程的独占模式或者共享模式。自定义同步器需要实现以下方法(ReentrantLock需要实现的方法如下,并不是全部):
+
+| 方法名 | 描述 |
+| :------------------------------------------ | :----------------------------------------------------------- |
+| protected boolean isHeldExclusively() | 该线程是否正在独占资源。只有用到Condition才需要去实现它。 |
+| protected boolean tryAcquire(int arg) | 独占方式。arg为获取锁的次数,尝试获取资源,成功则返回True,失败则返回False。 |
+| protected boolean tryRelease(int arg) | 独占方式。arg为释放锁的次数,尝试释放资源,成功则返回True,失败则返回False。 |
+| protected int tryAcquireShared(int arg) | 共享方式。arg为获取锁的次数,尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。 |
+| protected boolean tryReleaseShared(int arg) | 共享方式。arg为释放锁的次数,尝试释放资源,如果释放后允许唤醒后续等待结点返回True,否则返回False。 |
+
+一般来说,自定义同步器要么是独占方式,要么是共享方式,它们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。ReentrantLock是独占锁,所以实现了tryAcquire-tryRelease。
+
+以非公平锁为例,这里主要阐述一下非公平锁与AQS之间方法的关联之处,具体每一处核心方法的作用会在文章后面详细进行阐述。
+
+
+
+为了帮助大家理解ReentrantLock和AQS之间方法的交互过程,以非公平锁为例,我们将加锁和解锁的交互流程单独拎出来强调一下,以便于对后续内容的理解。
+
+
+
+加锁:
+
+- 通过ReentrantLock的加锁方法Lock进行加锁操作。
+- 会调用到内部类Sync的Lock方法,由于Sync#lock是抽象方法,根据ReentrantLock初始化选择的公平锁和非公平锁,执行相关内部类的Lock方法,本质上都会执行AQS的Acquire方法。
+- AQS的Acquire方法会执行tryAcquire方法,但是由于tryAcquire需要自定义同步器实现,因此执行了ReentrantLock中的tryAcquire方法,由于ReentrantLock是通过公平锁和非公平锁内部类实现的tryAcquire方法,因此会根据锁类型不同,执行不同的tryAcquire。
+- tryAcquire是获取锁逻辑,获取失败后,会执行框架AQS的后续逻辑,跟ReentrantLock自定义同步器无关。
+
+解锁:
+
+- 通过ReentrantLock的解锁方法Unlock进行解锁。
+- Unlock会调用内部类Sync的Release方法,该方法继承于AQS。
+- Release中会调用tryRelease方法,tryRelease需要自定义同步器实现,tryRelease只在ReentrantLock中的Sync实现,因此可以看出,释放锁的过程,并不区分是否为公平锁。
+- 释放成功后,所有处理由AQS框架完成,与自定义同步器无关。
+
+通过上面的描述,大概可以总结出ReentrantLock加锁解锁时API层核心方法的映射关系。
+
+
+
+## 2.3 通过ReentrantLock理解AQS
+
+ReentrantLock中公平锁和非公平锁在底层是相同的,这里以非公平锁为例进行分析。
+
+在非公平锁中,有一段这样的代码:
+
+```java
+// java.util.concurrent.locks.ReentrantLock
+
+static final class NonfairSync extends Sync {
+ ...
+ final void lock() {
+ if (compareAndSetState(0, 1))
+ setExclusiveOwnerThread(Thread.currentThread());
+ else
+ acquire(1);
+ }
+ ...
+}
+```
+
+看一下这个Acquire是怎么写的:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+public final void acquire(int arg) {
+ if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+ selfInterrupt();
+}
+```
+
+再看一下tryAcquire方法:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+protected boolean tryAcquire(int arg) {
+ throw new UnsupportedOperationException();
+}
+```
+
+可以看出,这里只是AQS的简单实现,具体获取锁的实现方法是由各自的公平锁和非公平锁单独实现的(以ReentrantLock为例)。如果该方法返回了True,则说明当前线程获取锁成功,就不用往后执行了;如果获取失败,就需要加入到等待队列中。下面会详细解释线程是何时以及怎样被加入进等待队列中的。
+
+### 2.3.1 线程加入等待队列
+
+#### 2.3.1.1 加入队列的时机
+
+当执行Acquire(1)时,会通过tryAcquire获取锁。在这种情况下,如果获取锁失败,就会调用addWaiter加入到等待队列中去。
+
+#### 2.3.1.2 如何加入队列
+
+获取锁失败后,会执行addWaiter(Node.EXCLUSIVE)加入等待队列,具体实现方法如下:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private Node addWaiter(Node mode) {
+ Node node = new Node(Thread.currentThread(), mode);
+ // Try the fast path of enq; backup to full enq on failure
+ Node pred = tail;
+ if (pred != null) {
+ node.prev = pred;
+ if (compareAndSetTail(pred, node)) {
+ pred.next = node;
+ return node;
+ }
+ }
+ enq(node);
+ return node;
+}
+private final boolean compareAndSetTail(Node expect, Node update) {
+ return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
+}
+```
+
+主要的流程如下:
+
+- 通过当前的线程和锁模式新建一个节点。
+- Pred指针指向尾节点Tail。
+- 将New中Node的Prev指针指向Pred。
+- 通过compareAndSetTail方法,完成尾节点的设置。这个方法主要是对tailOffset和Expect进行比较,如果tailOffset的Node和Expect的Node地址是相同的,那么设置Tail的值为Update的值。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+static {
+ try {
+ stateOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer.class.getDeclaredField("state"));
+ headOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer.class.getDeclaredField("head"));
+ tailOffset = unsafe.objectFieldOffset(AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
+ waitStatusOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("waitStatus"));
+ nextOffset = unsafe.objectFieldOffset(Node.class.getDeclaredField("next"));
+ } catch (Exception ex) {
+ throw new Error(ex);
+ }
+}
+```
+
+从AQS的静态代码块可以看出,都是获取一个对象的属性相对于该对象在内存当中的偏移量,这样我们就可以根据这个偏移量在对象内存当中找到这个属性。tailOffset指的是tail对应的偏移量,所以这个时候会将new出来的Node置为当前队列的尾节点。同时,由于是双向链表,也需要将前一个节点指向尾节点。
+
+- 如果Pred指针是Null(说明等待队列中没有元素),或者当前Pred指针和Tail指向的位置不同(说明被别的线程已经修改),就需要看一下Enq的方法。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private Node enq(final Node node) {
+ for (;;) {
+ Node t = tail;
+ if (t == null) { // Must initialize
+ if (compareAndSetHead(new Node()))
+ tail = head;
+ } else {
+ node.prev = t;
+ if (compareAndSetTail(t, node)) {
+ t.next = node;
+ return t;
+ }
+ }
+ }
+}
+```
+
+如果没有被初始化,需要进行初始化一个头结点出来。但请注意,初始化的头结点并不是当前线程节点,而是调用了无参构造函数的节点。如果经历了初始化或者并发导致队列中有元素,则与之前的方法相同。其实,addWaiter就是一个在双端链表添加尾节点的操作,需要注意的是,双端链表的头结点是一个无参构造函数的头结点。
+
+总结一下,线程获取锁的时候,过程大体如下:
+
+1. 当没有线程获取到锁时,线程1获取锁成功。
+2. 线程2申请锁,但是锁被线程1占有。
+
+
+
+1. 如果再有线程要获取锁,依次在队列中往后排队即可。
+
+回到上边的代码,hasQueuedPredecessors是公平锁加锁时判断等待队列中是否存在有效节点的方法。如果返回False,说明当前线程可以争取共享资源;如果返回True,说明队列中存在有效节点,当前线程必须加入到等待队列中。
+
+```java
+// java.util.concurrent.locks.ReentrantLock
+
+public final boolean hasQueuedPredecessors() {
+ // The correctness of this depends on head being initialized
+ // before tail and on head.next being accurate if the current
+ // thread is first in queue.
+ Node t = tail; // Read fields in reverse initialization order
+ Node h = head;
+ Node s;
+ return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
+}
+```
+
+看到这里,我们理解一下h != t && ((s = h.next) == null || s.thread != Thread.currentThread());为什么要判断的头结点的下一个节点?第一个节点储存的数据是什么?
+
+> 双向链表中,第一个节点为虚节点,其实并不存储任何信息,只是占位。真正的第一个有数据的节点,是在第二个节点开始的。当h != t时: 如果(s = h.next) == null,等待队列正在有线程进行初始化,但只是进行到了Tail指向Head,没有将Head指向Tail,此时队列中有元素,需要返回True(这块具体见下边代码分析)。 如果(s = h.next) != null,说明此时队列中至少有一个有效节点。如果此时s.thread == Thread.currentThread(),说明等待队列的第一个有效节点中的线程与当前线程相同,那么当前线程是可以获取资源的;如果s.thread != Thread.currentThread(),说明等待队列的第一个有效节点线程与当前线程不同,当前线程必须加入进等待队列。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer#enq
+
+if (t == null) { // Must initialize
+ if (compareAndSetHead(new Node()))
+ tail = head;
+} else {
+ node.prev = t;
+ if (compareAndSetTail(t, node)) {
+ t.next = node;
+ return t;
+ }
+}
+```
+
+节点入队不是原子操作,所以会出现短暂的head != tail,此时Tail指向最后一个节点,而且Tail指向Head。如果Head没有指向Tail(可见5、6、7行),这种情况下也需要将相关线程加入队列中。所以这块代码是为了解决极端情况下的并发问题。
+
+#### 2.3.1.3 等待队列中线程出队列时机
+
+回到最初的源码:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+public final void acquire(int arg) {
+ if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
+ selfInterrupt();
+}
+```
+
+上文解释了addWaiter方法,这个方法其实就是把对应的线程以Node的数据结构形式加入到双端队列里,返回的是一个包含该线程的Node。而这个Node会作为参数,进入到acquireQueued方法中。acquireQueued方法可以对排队中的线程进行“获锁”操作。
+
+总的来说,一个线程获取锁失败了,被放入等待队列,acquireQueued会把放入队列中的线程不断去获取锁,直到获取成功或者不再需要获取(中断)。
+
+下面我们从“何时出队列?”和“如何出队列?”两个方向来分析一下acquireQueued源码:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+final boolean acquireQueued(final Node node, int arg) {
+ // 标记是否成功拿到资源
+ boolean failed = true;
+ try {
+ // 标记等待过程中是否中断过
+ boolean interrupted = false;
+ // 开始自旋,要么获取锁,要么中断
+ for (;;) {
+ // 获取当前节点的前驱节点
+ final Node p = node.predecessor();
+ // 如果p是头结点,说明当前节点在真实数据队列的首部,就尝试获取锁(别忘了头结点是虚节点)
+ if (p == head && tryAcquire(arg)) {
+ // 获取锁成功,头指针移动到当前node
+ setHead(node);
+ p.next = null; // help GC
+ failed = false;
+ return interrupted;
+ }
+ // 说明p为头节点且当前没有获取到锁(可能是非公平锁被抢占了)或者是p不为头结点,这个时候就要判断当前node是否要被阻塞(被阻塞条件:前驱节点的waitStatus为-1),防止无限循环浪费资源。具体两个方法下面细细分析
+ if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
+ interrupted = true;
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+}
+```
+
+注:setHead方法是把当前节点置为虚节点,但并没有修改waitStatus,因为它是一直需要用的数据。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private void setHead(Node node) {
+ head = node;
+ node.thread = null;
+ node.prev = null;
+}
+
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+// 靠前驱节点判断当前线程是否应该被阻塞
+private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
+ // 获取头结点的节点状态
+ int ws = pred.waitStatus;
+ // 说明头结点处于唤醒状态
+ if (ws == Node.SIGNAL)
+ return true;
+ // 通过枚举值我们知道waitStatus>0是取消状态
+ if (ws > 0) {
+ do {
+ // 循环向前查找取消节点,把取消节点从队列中剔除
+ node.prev = pred = pred.prev;
+ } while (pred.waitStatus > 0);
+ pred.next = node;
+ } else {
+ // 设置前任节点等待状态为SIGNAL
+ compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
+ }
+ return false;
+}
+```
+
+parkAndCheckInterrupt主要用于挂起当前线程,阻塞调用栈,返回当前线程的中断状态。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private final boolean parkAndCheckInterrupt() {
+ LockSupport.park(this);
+ return Thread.interrupted();
+}
+```
+
+上述方法的流程图如下:
+
+
+
+从上图可以看出,跳出当前循环的条件是当“前置节点是头结点,且当前线程获取锁成功”。为了防止因死循环导致CPU资源被浪费,我们会判断前置节点的状态来决定是否要将当前线程挂起,具体挂起流程用流程图表示如下(shouldParkAfterFailedAcquire流程):
+
+
+
+从队列中释放节点的疑虑打消了,那么又有新问题了:
+
+- shouldParkAfterFailedAcquire中取消节点是怎么生成的呢?什么时候会把一个节点的waitStatus设置为-1?
+- 是在什么时间释放节点通知到被挂起的线程呢?
+
+### 2.3.2 CANCELLED状态节点生成
+
+acquireQueued方法中的Finally代码:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+final boolean acquireQueued(final Node node, int arg) {
+ boolean failed = true;
+ try {
+ ...
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head && tryAcquire(arg)) {
+ ...
+ failed = false;
+ ...
+ }
+ ...
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+}
+```
+
+通过cancelAcquire方法,将Node的状态标记为CANCELLED。接下来,我们逐行来分析这个方法的原理:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private void cancelAcquire(Node node) {
+ // 将无效节点过滤
+ if (node == null)
+ return;
+ // 设置该节点不关联任何线程,也就是虚节点
+ node.thread = null;
+ Node pred = node.prev;
+ // 通过前驱节点,跳过取消状态的node
+ while (pred.waitStatus > 0)
+ node.prev = pred = pred.prev;
+ // 获取过滤后的前驱节点的后继节点
+ Node predNext = pred.next;
+ // 把当前node的状态设置为CANCELLED
+ node.waitStatus = Node.CANCELLED;
+ // 如果当前节点是尾节点,将从后往前的第一个非取消状态的节点设置为尾节点
+ // 更新失败的话,则进入else,如果更新成功,将tail的后继节点设置为null
+ if (node == tail && compareAndSetTail(node, pred)) {
+ compareAndSetNext(pred, predNext, null);
+ } else {
+ int ws;
+ // 如果当前节点不是head的后继节点,1:判断当前节点前驱节点的是否为SIGNAL,2:如果不是,则把前驱节点设置为SINGAL看是否成功
+ // 如果1和2中有一个为true,再判断当前节点的线程是否为null
+ // 如果上述条件都满足,把当前节点的前驱节点的后继指针指向当前节点的后继节点
+ if (pred != head && ((ws = pred.waitStatus) == Node.SIGNAL || (ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) && pred.thread != null) {
+ Node next = node.next;
+ if (next != null && next.waitStatus <= 0)
+ compareAndSetNext(pred, predNext, next);
+ } else {
+ // 如果当前节点是head的后继节点,或者上述条件不满足,那就唤醒当前节点的后继节点
+ unparkSuccessor(node);
+ }
+ node.next = node; // help GC
+ }
+}
+```
+
+当前的流程:
+
+- 获取当前节点的前驱节点,如果前驱节点的状态是CANCELLED,那就一直往前遍历,找到第一个waitStatus <= 0的节点,将找到的Pred节点和当前Node关联,将当前Node设置为CANCELLED。
+- 根据当前节点的位置,考虑以下三种情况:
+
+(1) 当前节点是尾节点。
+
+(2) 当前节点是Head的后继节点。
+
+(3) 当前节点不是Head的后继节点,也不是尾节点。
+
+根据上述第二条,我们来分析每一种情况的流程。
+
+当前节点是尾节点。
+
+
+
+当前节点是Head的后继节点。
+
+
+
+当前节点不是Head的后继节点,也不是尾节点。
+
+
+
+通过上面的流程,我们对于CANCELLED节点状态的产生和变化已经有了大致的了解,但是为什么所有的变化都是对Next指针进行了操作,而没有对Prev指针进行操作呢?什么情况下会对Prev指针进行操作?
+
+> 执行cancelAcquire的时候,当前节点的前置节点可能已经从队列中出去了(已经执行过Try代码块中的shouldParkAfterFailedAcquire方法了),如果此时修改Prev指针,有可能会导致Prev指向另一个已经移除队列的Node,因此这块变化Prev指针不安全。 shouldParkAfterFailedAcquire方法中,会执行下面的代码,其实就是在处理Prev指针。shouldParkAfterFailedAcquire是获取锁失败的情况下才会执行,进入该方法后,说明共享资源已被获取,当前节点之前的节点都不会出现变化,因此这个时候变更Prev指针比较安全。
+>
+> ```java
+> do {
+> node.prev = pred = pred.prev;
+> } while (pred.waitStatus > 0);
+> ```
+
+### 2.3.3 如何解锁
+
+我们已经剖析了加锁过程中的基本流程,接下来再对解锁的基本流程进行分析。由于ReentrantLock在解锁的时候,并不区分公平锁和非公平锁,所以我们直接看解锁的源码:
+
+```java
+// java.util.concurrent.locks.ReentrantLock
+
+public void unlock() {
+ sync.release(1);
+}
+```
+
+可以看到,本质释放锁的地方,是通过框架来完成的。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+public final boolean release(int arg) {
+ if (tryRelease(arg)) {
+ Node h = head;
+ if (h != null && h.waitStatus != 0)
+ unparkSuccessor(h);
+ return true;
+ }
+ return false;
+}
+```
+
+在ReentrantLock里面的公平锁和非公平锁的父类Sync定义了可重入锁的释放锁机制。
+
+```java
+// java.util.concurrent.locks.ReentrantLock.Sync
+
+// 方法返回当前锁是不是没有被线程持有
+protected final boolean tryRelease(int releases) {
+ // 减少可重入次数
+ int c = getState() - releases;
+ // 当前线程不是持有锁的线程,抛出异常
+ if (Thread.currentThread() != getExclusiveOwnerThread())
+ throw new IllegalMonitorStateException();
+ boolean free = false;
+ // 如果持有线程全部释放,将当前独占锁所有线程设置为null,并更新state
+ if (c == 0) {
+ free = true;
+ setExclusiveOwnerThread(null);
+ }
+ setState(c);
+ return free;
+}
+```
+
+我们来解释下述源码:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+public final boolean release(int arg) {
+ // 上边自定义的tryRelease如果返回true,说明该锁没有被任何线程持有
+ if (tryRelease(arg)) {
+ // 获取头结点
+ Node h = head;
+ // 头结点不为空并且头结点的waitStatus不是初始化节点情况,解除线程挂起状态
+ if (h != null && h.waitStatus != 0)
+ unparkSuccessor(h);
+ return true;
+ }
+ return false;
+}
+```
+
+这里的判断条件为什么是h != null && h.waitStatus != 0?
+
+> h == null Head还没初始化。初始情况下,head == null,第一个节点入队,Head会被初始化一个虚拟节点。所以说,这里如果还没来得及入队,就会出现head == null 的情况。
+>
+> h != null && waitStatus == 0 表明后继节点对应的线程仍在运行中,不需要唤醒。
+>
+> h != null && waitStatus < 0 表明后继节点可能被阻塞了,需要唤醒。
+
+再看一下unparkSuccessor方法:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private void unparkSuccessor(Node node) {
+ // 获取头结点waitStatus
+ int ws = node.waitStatus;
+ if (ws < 0)
+ compareAndSetWaitStatus(node, ws, 0);
+ // 获取当前节点的下一个节点
+ Node s = node.next;
+ // 如果下个节点是null或者下个节点被cancelled,就找到队列最开始的非cancelled的节点
+ if (s == null || s.waitStatus > 0) {
+ s = null;
+ // 就从尾部节点开始找,到队首,找到队列第一个waitStatus<0的节点。
+ for (Node t = tail; t != null && t != node; t = t.prev)
+ if (t.waitStatus <= 0)
+ s = t;
+ }
+ // 如果当前节点的下个节点不为空,而且状态<=0,就把当前节点unpark
+ if (s != null)
+ LockSupport.unpark(s.thread);
+}
+```
+
+为什么要从后往前找第一个非Cancelled的节点呢?原因如下。
+
+之前的addWaiter方法:
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private Node addWaiter(Node mode) {
+ Node node = new Node(Thread.currentThread(), mode);
+ // Try the fast path of enq; backup to full enq on failure
+ Node pred = tail;
+ if (pred != null) {
+ node.prev = pred;
+ if (compareAndSetTail(pred, node)) {
+ pred.next = node;
+ return node;
+ }
+ }
+ enq(node);
+ return node;
+}
+```
+
+我们从这里可以看到,节点入队并不是原子操作,也就是说,node.prev = pred; compareAndSetTail(pred, node) 这两个地方可以看作Tail入队的原子操作,但是此时pred.next = node;还没执行,如果这个时候执行了unparkSuccessor方法,就没办法从前往后找了,所以需要从后往前找。还有一点原因,在产生CANCELLED状态节点的时候,先断开的是Next指针,Prev指针并未断开,因此也是必须要从后往前遍历才能够遍历完全部的Node。
+
+综上所述,如果是从前往后找,由于极端情况下入队的非原子操作和CANCELLED节点产生过程中断开Next指针的操作,可能会导致无法遍历所有的节点。所以,唤醒对应的线程后,对应的线程就会继续往下执行。继续执行acquireQueued方法以后,中断如何处理?
+
+### 2.3.4 中断恢复后的执行流程
+
+唤醒后,会执行return Thread.interrupted();,这个函数返回的是当前执行线程的中断状态,并清除。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private final boolean parkAndCheckInterrupt() {
+ LockSupport.park(this);
+ return Thread.interrupted();
+}
+```
+
+再回到acquireQueued代码,当parkAndCheckInterrupt返回True或者False的时候,interrupted的值不同,但都会执行下次循环。如果这个时候获取锁成功,就会把当前interrupted返回。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+final boolean acquireQueued(final Node node, int arg) {
+ boolean failed = true;
+ try {
+ boolean interrupted = false;
+ for (;;) {
+ final Node p = node.predecessor();
+ if (p == head && tryAcquire(arg)) {
+ setHead(node);
+ p.next = null; // help GC
+ failed = false;
+ return interrupted;
+ }
+ if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
+ interrupted = true;
+ }
+ } finally {
+ if (failed)
+ cancelAcquire(node);
+ }
+}
+```
+
+如果acquireQueued为True,就会执行selfInterrupt方法。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+static void selfInterrupt() {
+ Thread.currentThread().interrupt();
+}
+```
+
+该方法其实是为了中断线程。但为什么获取了锁以后还要中断线程呢?这部分属于Java提供的协作式中断知识内容,感兴趣同学可以查阅一下。这里简单介绍一下:
+
+1. 当中断线程被唤醒时,并不知道被唤醒的原因,可能是当前线程在等待中被中断,也可能是释放了锁以后被唤醒。因此我们通过Thread.interrupted()方法检查中断标记(该方法返回了当前线程的中断状态,并将当前线程的中断标识设置为False),并记录下来,如果发现该线程被中断过,就再中断一次。
+2. 线程在等待资源的过程中被唤醒,唤醒后还是会不断地去尝试获取锁,直到抢到锁为止。也就是说,在整个流程中,并不响应中断,只是记录中断记录。最后抢到锁返回了,那么如果被中断过的话,就需要补充一次中断。
+
+这里的处理方式主要是运用线程池中基本运作单元Worder中的runWorker,通过Thread.interrupted()进行额外的判断处理,感兴趣的同学可以看下ThreadPoolExecutor源码。
+
+### 2.3.5 小结
+
+我们在1.3小节中提出了一些问题,现在来回答一下。
+
+> Q:某个线程获取锁失败的后续流程是什么呢?
+>
+> A:存在某种排队等候机制,线程继续等待,仍然保留获取锁的可能,获取锁流程仍在继续。
+>
+> Q:既然说到了排队等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?
+>
+> A:是CLH变体的FIFO双端队列。
+>
+> Q:处于排队等候机制中的线程,什么时候可以有机会获取锁呢?
+>
+> A:可以详细看下2.3.1.3小节。
+>
+> Q:如果处于排队等候机制中的线程一直无法获取锁,需要一直等待么?还是有别的策略来解决这一问题?
+>
+> A:线程所在节点的状态会变成取消状态,取消状态的节点会从队列中释放,具体可见2.3.2小节。
+>
+> Q:Lock函数通过Acquire方法进行加锁,但是具体是如何加锁的呢?
+>
+> A:AQS的Acquire会调用tryAcquire方法,tryAcquire由各个自定义同步器实现,通过tryAcquire完成加锁过程。
+
+## 3 AQS应用
+
+### 3.1 ReentrantLock的可重入应用
+
+ReentrantLock的可重入性是AQS很好的应用之一,在了解完上述知识点以后,我们很容易得知ReentrantLock实现可重入的方法。在ReentrantLock里面,不管是公平锁还是非公平锁,都有一段逻辑。
+
+公平锁:
+
+```java
+// java.util.concurrent.locks.ReentrantLock.FairSync#tryAcquire
+
+if (c == 0) {
+ if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
+ setExclusiveOwnerThread(current);
+ return true;
+ }
+}
+else if (current == getExclusiveOwnerThread()) {
+ int nextc = c + acquires;
+ if (nextc < 0)
+ throw new Error("Maximum lock count exceeded");
+ setState(nextc);
+ return true;
+}
+```
+
+非公平锁:
+
+```java
+// java.util.concurrent.locks.ReentrantLock.Sync#nonfairTryAcquire
+
+if (c == 0) {
+ if (compareAndSetState(0, acquires)){
+ setExclusiveOwnerThread(current);
+ return true;
+ }
+}
+else if (current == getExclusiveOwnerThread()) {
+ int nextc = c + acquires;
+ if (nextc < 0) // overflow
+ throw new Error("Maximum lock count exceeded");
+ setState(nextc);
+ return true;
+}
+```
+
+从上面这两段都可以看到,有一个同步状态State来控制整体可重入的情况。State是Volatile修饰的,用于保证一定的可见性和有序性。
+
+```java
+// java.util.concurrent.locks.AbstractQueuedSynchronizer
+
+private volatile int state;
+```
+
+接下来看State这个字段主要的过程:
+
+1. State初始化的时候为0,表示没有任何线程持有锁。
+2. 当有线程持有该锁时,值就会在原来的基础上+1,同一个线程多次获得锁是,就会多次+1,这里就是可重入的概念。
+3. 解锁也是对这个字段-1,一直到0,此线程对锁释放。
+
+### 3.2 JUC中的应用场景
+
+除了上边ReentrantLock的可重入性的应用,AQS作为并发编程的框架,为很多其他同步工具提供了良好的解决方案。下面列出了JUC中的几种同步工具,大体介绍一下AQS的应用场景:
+
+| 同步工具 | 同步工具与AQS的关联 |
+| :--------------------- | :----------------------------------------------------------- |
+| ReentrantLock | 使用AQS保存锁重复持有的次数。当一个线程获取锁时,ReentrantLock记录当前获得锁的线程标识,用于检测是否重复获取,以及错误线程试图解锁操作时异常情况的处理。 |
+| Semaphore | 使用AQS同步状态来保存信号量的当前计数。tryRelease会增加计数,acquireShared会减少计数。 |
+| CountDownLatch | 使用AQS同步状态来表示计数。计数为0时,所有的Acquire操作(CountDownLatch的await方法)才可以通过。 |
+| ReentrantReadWriteLock | 使用AQS同步状态中的16位保存写锁持有的次数,剩下的16位用于保存读锁的持有次数。 |
+| ThreadPoolExecutor | Worker利用AQS同步状态实现对独占线程变量的设置(tryAcquire和tryRelease)。 |
+
+### 3.3 自定义同步工具
+
+了解AQS基本原理以后,按照上面所说的AQS知识点,自己实现一个同步工具。
+
+```java
+public class LeeLock {
+
+ private static class Sync extends AbstractQueuedSynchronizer {
+ @Override
+ protected boolean tryAcquire (int arg) {
+ return compareAndSetState(0, 1);
+ }
+
+ @Override
+ protected boolean tryRelease (int arg) {
+ setState(0);
+ return true;
+ }
+
+ @Override
+ protected boolean isHeldExclusively () {
+ return getState() == 1;
+ }
+ }
+
+ private Sync sync = new Sync();
+
+ public void lock () {
+ sync.acquire(1);
+ }
+
+ public void unlock () {
+ sync.release(1);
+ }
+}
+```
+
+通过我们自己定义的Lock完成一定的同步功能。
+
+```java
+public class LeeMain {
+
+ static int count = 0;
+ static LeeLock leeLock = new LeeLock();
+
+ public static void main (String[] args) throws InterruptedException {
+
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run () {
+ try {
+ leeLock.lock();
+ for (int i = 0; i < 10000; i++) {
+ count++;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ leeLock.unlock();
+ }
+
+ }
+ };
+ Thread thread1 = new Thread(runnable);
+ Thread thread2 = new Thread(runnable);
+ thread1.start();
+ thread2.start();
+ thread1.join();
+ thread2.join();
+ System.out.println(count);
+ }
+}
+```
+
+上述代码每次运行结果都会是20000。通过简单的几行代码就能实现同步功能,这就是AQS的强大之处。
+
+## 总结
+
+我们日常开发中使用并发的场景太多,但是对并发内部的基本框架原理了解的人却不多。由于篇幅原因,本文仅介绍了可重入锁ReentrantLock的原理和AQS原理,希望能够成为大家了解AQS和ReentrantLock等同步器的“敲门砖”。
+
+## 参考资料
+
+- Lea D. The java. util. concurrent synchronizer framework[J]. Science of Computer Programming, 2005, 58(3): 293-309.
+- 《Java并发编程实战》
+- [不可不说的Java“锁”事](https://tech.meituan.com/2018/11/15/java-lock.html)
\ No newline at end of file
diff --git "a/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md" b/docs/java/concurrent/threadlocal.md
similarity index 99%
rename from "docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md"
rename to docs/java/concurrent/threadlocal.md
index 4238d03382d..a4aff50f23a 100644
--- "a/docs/java/multi-thread/\344\270\207\345\255\227\350\257\246\350\247\243ThreadLocal\345\205\263\351\224\256\345\255\227.md"
+++ b/docs/java/concurrent/threadlocal.md
@@ -1,3 +1,12 @@
+---
+title: 万字解析 ThreadLocal 关键字
+category: Java
+tag:
+ - Java并发
+---
+
+
+
> 本文来自一枝花算不算浪漫投稿, 原文地址:[https://juejin.im/post/5eacc1c75188256d976df748](https://juejin.im/post/5eacc1c75188256d976df748)。
### 前言
diff --git "a/docs/java/multi-thread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md" "b/docs/java/concurrent/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
similarity index 99%
rename from "docs/java/multi-thread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
rename to "docs/java/concurrent/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
index e4042ebe76b..d6f3691bfad 100644
--- "a/docs/java/multi-thread/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
+++ "b/docs/java/concurrent/\345\271\266\345\217\221\345\256\271\345\231\250\346\200\273\347\273\223.md"
@@ -1,4 +1,9 @@
-## JDK 提供的并发容器总结
+---
+title: JDK 提供的并发容器总结
+category: Java
+tag:
+ - Java并发
+---
JDK 提供的这些容器大部分在 `java.util.concurrent` 包中。
diff --git "a/docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md" "b/docs/java/concurrent/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204java\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"
similarity index 99%
rename from "docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"
rename to "docs/java/concurrent/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204java\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"
index e7f3c30ed15..45034bf3392 100644
--- "a/docs/java/multi-thread/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"
+++ "b/docs/java/concurrent/\346\213\277\346\235\245\345\215\263\347\224\250\347\232\204java\347\272\277\347\250\213\346\261\240\346\234\200\344\275\263\345\256\236\350\267\265.md"
@@ -1,4 +1,9 @@
-# 线程池最佳实践
+---
+title: 拿来即用的Java线程池最佳实践
+category: Java
+tag:
+ - Java并发
+---
这篇文章篇幅虽短,但是绝对是干货。标题稍微有点夸张,嘿嘿,实际都是自己使用线程池的时候总结的一些个人感觉比较重要的点。
diff --git a/docs/java/images/image-20200405151029416.png b/docs/java/images/image-20200405151029416.png
deleted file mode 100644
index 26ea14ca479..00000000000
Binary files a/docs/java/images/image-20200405151029416.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance1.png b/docs/java/images/performance-tuning/java-performance1.png
deleted file mode 100644
index 0975d26519e..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance1.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance2.png b/docs/java/images/performance-tuning/java-performance2.png
deleted file mode 100644
index 76bbc0a82f1..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance2.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance3.png b/docs/java/images/performance-tuning/java-performance3.png
deleted file mode 100644
index 150e5ce5d5a..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance3.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance4.png b/docs/java/images/performance-tuning/java-performance4.png
deleted file mode 100644
index e3bf7450592..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance4.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance5.png b/docs/java/images/performance-tuning/java-performance5.png
deleted file mode 100644
index c6b44840ff4..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance5.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance6.png b/docs/java/images/performance-tuning/java-performance6.png
deleted file mode 100644
index b1e182ed89c..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance6.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance7.png b/docs/java/images/performance-tuning/java-performance7.png
deleted file mode 100644
index 0796e30d239..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance7.png and /dev/null differ
diff --git a/docs/java/images/performance-tuning/java-performance8.png b/docs/java/images/performance-tuning/java-performance8.png
deleted file mode 100644
index 75172dfad5f..00000000000
Binary files a/docs/java/images/performance-tuning/java-performance8.png and /dev/null differ
diff --git "a/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md" b/docs/java/jvm/class-file-structure.md
similarity index 92%
rename from "docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md"
rename to docs/java/jvm/class-file-structure.md
index 380e11fb15d..b5a2611397e 100644
--- "a/docs/java/jvm/\347\261\273\346\226\207\344\273\266\347\273\223\346\236\204.md"
+++ b/docs/java/jvm/class-file-structure.md
@@ -1,25 +1,10 @@
+---
+category: Java
+tag:
+ - JVM
+---
-
-
-
-
-- [类文件结构](#类文件结构)
- - [一 概述](#一-概述)
- - [二 Class 文件结构总结](#二-class-文件结构总结)
- - [2.1 魔数(Magic Number)](#21-魔数magic-number)
- - [2.2 Class 文件版本号(Minor&Major Version)](#22-class-文件版本号minormajor-version)
- - [2.3 常量池(Constant Pool)](#23-常量池constant-pool)
- - [2.4 访问标志(Access Flags)](#24-访问标志access-flags)
- - [2.5 当前类(This Class)、父类(Super Class)、接口(Interfaces)索引集合](#25-当前类this-class-父类super-class-接口interfaces索引集合)
- - [2.6 字段表集合(Fields)](#26-字段表集合fields)
- - [2.7 方法表集合(Methods)](#27-方法表集合methods)
- - [2.8 属性表集合(Attributes)](#28-属性表集合attributes)
- - [参考](#参考)
-
-
-
-
-# 类文件结构
+# 类文件结构详解
## 一 概述
diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md" b/docs/java/jvm/class-loading-process.md
similarity index 90%
rename from "docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md"
rename to docs/java/jvm/class-loading-process.md
index bf2811eb441..fbe1b161d68 100644
--- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\350\277\207\347\250\213.md"
+++ b/docs/java/jvm/class-loading-process.md
@@ -1,18 +1,13 @@
-
+---
+category: Java
+tag:
+ - JVM
+---
-- [类的生命周期](#类的生命周期)
- - [类加载过程](#类加载过程)
- - [加载](#加载)
- - [验证](#验证)
- - [准备](#准备)
- - [解析](#解析)
- - [初始化](#初始化)
- - [卸载](#卸载)
- - [公众号](#公众号)
-
+# 类加载过程详解
-# 类的生命周期
+## 类的生命周期
一个类的完整生命周期如下:
@@ -115,13 +110,3 @@ Class 文件需要加载到虚拟机中之后才能运行和使用,那么虚
- 《深入理解 Java 虚拟机》
- 《实战 Java 虚拟机》
-
-
-## 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java 面试突击"** 即可免费领取!
-
-**Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
-
-
diff --git "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md" b/docs/java/jvm/classloader.md
similarity index 99%
rename from "docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md"
rename to docs/java/jvm/classloader.md
index 013397017ee..93cd907e45a 100644
--- "a/docs/java/jvm/\347\261\273\345\212\240\350\275\275\345\231\250.md"
+++ b/docs/java/jvm/classloader.md
@@ -1,3 +1,11 @@
+---
+category: Java
+tag:
+ - JVM
+---
+
+# 类加载器详解
+
## 回顾一下类加载过程
类加载过程:**加载->连接->初始化**。连接过程又可分为三步:**验证->准备->解析**。
diff --git "a/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md" b/docs/java/jvm/jdk-monitoring-and-troubleshooting-tools.md
similarity index 92%
rename from "docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md"
rename to docs/java/jvm/jdk-monitoring-and-troubleshooting-tools.md
index 779ab01f1ed..37e2c0d320e 100644
--- "a/docs/java/jvm/JDK\347\233\221\346\216\247\345\222\214\346\225\205\351\232\234\345\244\204\347\220\206\345\267\245\345\205\267\346\200\273\347\273\223.md"
+++ b/docs/java/jvm/jdk-monitoring-and-troubleshooting-tools.md
@@ -1,22 +1,8 @@
-
-
-- [JDK 监控和故障处理工具总结](#jdk-监控和故障处理工具总结)
- - [JDK 命令行工具](#jdk-命令行工具)
- - [`jps`:查看所有 Java 进程](#jps查看所有-java-进程)
- - [`jstat`: 监视虚拟机各种运行状态信息](#jstat-监视虚拟机各种运行状态信息)
- - [` jinfo`: 实时地查看和调整虚拟机各项参数](#-jinfo-实时地查看和调整虚拟机各项参数)
- - [`jmap`:生成堆转储快照](#jmap生成堆转储快照)
- - [**`jhat`**: 分析 heapdump 文件](#jhat-分析-heapdump-文件)
- - [**`jstack`** :生成虚拟机当前时刻的线程快照](#jstack-生成虚拟机当前时刻的线程快照)
- - [JDK 可视化分析工具](#jdk-可视化分析工具)
- - [JConsole:Java 监视与管理控制台](#jconsolejava-监视与管理控制台)
- - [连接 Jconsole](#连接-jconsole)
- - [查看 Java 程序概况](#查看-java-程序概况)
- - [内存监控](#内存监控)
- - [线程监控](#线程监控)
- - [Visual VM:多合一故障处理工具](#visual-vm多合一故障处理工具)
-
-
+---
+category: Java
+tag:
+ - JVM
+---
# JDK 监控和故障处理工具总结
diff --git "a/docs/java/jvm/jvm \347\237\245\350\257\206\347\202\271\346\261\207\346\200\273.md" "b/docs/java/jvm/jvm \347\237\245\350\257\206\347\202\271\346\261\207\346\200\273.md"
deleted file mode 100644
index 7a835ecc8fe..00000000000
--- "a/docs/java/jvm/jvm \347\237\245\350\257\206\347\202\271\346\261\207\346\200\273.md"
+++ /dev/null
@@ -1,12 +0,0 @@
-无论什么级别的Java从业者,JVM都是进阶时必须迈过的坎。不管是工作还是面试中,JVM都是必考题。如果不懂JVM的话,薪酬会非常吃亏(近70%的面试者挂在JVM上了)。
-
-
-掌握了JVM机制,就等于学会了深层次解决问题的方法。对于Java开发者而言,只有熟悉底层虚拟机的运行机制,才能通过JVM日志深入到字节码的层次去分析排查问题,发现隐性的系统缺陷,进而提升系统性能。
-
-
-一些技术人员开发工具用得很熟练,触及JVM问题时却是模棱两可,甚至连内存模型和内存区域,HotSpot和JVM规范,都混淆不清。工作很长时间,在生产时还在用缺省参数来直接启动,以致系统运行时出现性能、稳定性等问题时束手无措,不知该如何追踪排查。久而久之,这对自己的职业成长是极为不利的。
-
-
-掌握JVM,是深入Java技术栈的必经之路。
-
-
\ No newline at end of file
diff --git "a/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md" b/docs/java/jvm/jvm-garbage-collection.md
similarity index 94%
rename from "docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md"
rename to docs/java/jvm/jvm-garbage-collection.md
index 7d22468e5b7..058b2794f2c 100644
--- "a/docs/java/jvm/JVM\345\236\203\345\234\276\345\233\236\346\224\266.md"
+++ b/docs/java/jvm/jvm-garbage-collection.md
@@ -1,44 +1,10 @@
-
-
-
-
-- [JVM 垃圾回收](#jvm-垃圾回收)
- - [写在前面](#写在前面)
- - [本节常见面试题](#本节常见面试题)
- - [本文导火索](#本文导火索)
- - [1 揭开 JVM 内存分配与回收的神秘面纱](#1-揭开-jvm-内存分配与回收的神秘面纱)
- - [1.1 对象优先在 eden 区分配](#11-对象优先在-eden-区分配)
- - [1.2 大对象直接进入老年代](#12-大对象直接进入老年代)
- - [1.3 长期存活的对象将进入老年代](#13-长期存活的对象将进入老年代)
- - [1.4 动态对象年龄判定](#14-动态对象年龄判定)
- - [1.5 主要进行 gc 的区域](#15-主要进行-gc-的区域)
- - [2 对象已经死亡?](#2-对象已经死亡)
- - [2.1 引用计数法](#21-引用计数法)
- - [2.2 可达性分析算法](#22-可达性分析算法)
- - [2.3 再谈引用](#23-再谈引用)
- - [2.4 不可达的对象并非“非死不可”](#24-不可达的对象并非非死不可)
- - [2.5 如何判断一个常量是废弃常量?](#25-如何判断一个常量是废弃常量)
- - [2.6 如何判断一个类是无用的类](#26-如何判断一个类是无用的类)
- - [3 垃圾收集算法](#3-垃圾收集算法)
- - [3.1 标记-清除算法](#31-标记-清除算法)
- - [3.2 标记-复制算法](#32-标记-复制算法)
- - [3.3 标记-整理算法](#33-标记-整理算法)
- - [3.4 分代收集算法](#34-分代收集算法)
- - [4 垃圾收集器](#4-垃圾收集器)
- - [4.1 Serial 收集器](#41-serial-收集器)
- - [4.2 ParNew 收集器](#42-parnew-收集器)
- - [4.3 Parallel Scavenge 收集器](#43-parallel-scavenge-收集器)
- - [4.4.Serial Old 收集器](#44serial-old-收集器)
- - [4.5 Parallel Old 收集器](#45-parallel-old-收集器)
- - [4.6 CMS 收集器](#46-cms-收集器)
- - [4.7 G1 收集器](#47-g1-收集器)
- - [4.8 ZGC 收集器](#48-zgc-收集器)
- - [参考](#参考)
-
-
-
-
-# JVM 垃圾回收
+---
+category: Java
+tag:
+ - JVM
+---
+
+# JVM 垃圾回收详解
## 写在前面
diff --git "a/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md" b/docs/java/jvm/jvm-intro.md
similarity index 99%
rename from "docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md"
rename to docs/java/jvm/jvm-intro.md
index f1e16f87e9f..87cd046a0f8 100644
--- "a/docs/java/jvm/[\345\212\240\351\244\220]\345\244\247\347\231\275\350\257\235\345\270\246\344\275\240\350\256\244\350\257\206JVM.md"
+++ b/docs/java/jvm/jvm-intro.md
@@ -1,3 +1,11 @@
+---
+category: Java
+tag:
+ - JVM
+---
+
+# 大白话带你认识JVM
+
> 来自掘金用户:[说出你的愿望吧丷](https://juejin.im/user/5c2400afe51d45451758aa96)投稿,原文地址:https://juejin.im/post/5e1505d0f265da5d5d744050#heading-28
## 前言
diff --git "a/docs/java/jvm/\346\234\200\351\207\215\350\246\201\347\232\204JVM\345\217\202\346\225\260\346\214\207\345\215\227.md" b/docs/java/jvm/jvm-parameters-intro.md
similarity index 94%
rename from "docs/java/jvm/\346\234\200\351\207\215\350\246\201\347\232\204JVM\345\217\202\346\225\260\346\214\207\345\215\227.md"
rename to docs/java/jvm/jvm-parameters-intro.md
index a8514e149fe..4b9bf19670d 100644
--- "a/docs/java/jvm/\346\234\200\351\207\215\350\246\201\347\232\204JVM\345\217\202\346\225\260\346\214\207\345\215\227.md"
+++ b/docs/java/jvm/jvm-parameters-intro.md
@@ -1,4 +1,13 @@
-> 本文由 JavaGuide 翻译自 [https://www.baeldung.com/jvm-parameters](https://www.baeldung.com/jvm-parameters),并对文章进行了大量的完善补充。翻译不易,如需转载请注明出处,作者:[baeldung](https://www.baeldung.com/author/baeldung/) 。
+---
+category: Java
+tag:
+ - JVM
+---
+
+
+# 最重要的 JVM 参数总结
+
+本文由 JavaGuide 翻译自 [https://www.baeldung.com/jvm-parameters](https://www.baeldung.com/jvm-parameters),并对文章进行了大量的完善补充。翻译不易,如需转载请注明出处,作者:[baeldung](https://www.baeldung.com/author/baeldung/) 。
## 1.概述
diff --git "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md" b/docs/java/jvm/memory-area.md
similarity index 94%
rename from "docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md"
rename to docs/java/jvm/memory-area.md
index fbcc80c9422..68d98002c47 100644
--- "a/docs/java/jvm/Java\345\206\205\345\255\230\345\214\272\345\237\237.md"
+++ b/docs/java/jvm/memory-area.md
@@ -1,38 +1,8 @@
-
-
-- [Java 内存区域详解](#java-内存区域详解)
- - [写在前面 (常见面试题)](#写在前面-常见面试题)
- - [基本问题](#基本问题)
- - [拓展问题](#拓展问题)
- - [一 概述](#一-概述)
- - [二 运行时数据区域](#二-运行时数据区域)
- - [2.1 程序计数器](#21-程序计数器)
- - [2.2 Java 虚拟机栈](#22-java-虚拟机栈)
- - [2.3 本地方法栈](#23-本地方法栈)
- - [2.4 堆](#24-堆)
- - [2.5 方法区](#25-方法区)
- - [2.5.1 方法区和永久代的关系](#251-方法区和永久代的关系)
- - [2.5.2 常用参数](#252-常用参数)
- - [2.5.3 为什么要将永久代 (PermGen) 替换为元空间 (MetaSpace) 呢?](#253-为什么要将永久代-permgen-替换为元空间-metaspace-呢)
- - [2.6 运行时常量池](#26-运行时常量池)
- - [2.7 直接内存](#27-直接内存)
- - [三 HotSpot 虚拟机对象探秘](#三-hotspot-虚拟机对象探秘)
- - [3.1 对象的创建](#31-对象的创建)
- - [Step1:类加载检查](#step1类加载检查)
- - [Step2:分配内存](#step2分配内存)
- - [Step3:初始化零值](#step3初始化零值)
- - [Step4:设置对象头](#step4设置对象头)
- - [Step5:执行 init 方法](#step5执行-init-方法)
- - [3.2 对象的内存布局](#32-对象的内存布局)
- - [3.3 对象的访问定位](#33-对象的访问定位)
- - [四 重点补充内容](#四--重点补充内容)
- - [4.1 String 类和常量池](#41-string-类和常量池)
- - [4.2 String s1 = new String("abc");这句话创建了几个字符串对象?](#42-string-s1--new-stringabc这句话创建了几个字符串对象)
- - [4.3 8 种基本类型的包装类和常量池](#43-8-种基本类型的包装类和常量池)
- - [参考](#参考)
- - [公众号](#公众号)
-
-
+---
+category: Java
+tag:
+ - JVM
+---
# Java 内存区域详解
@@ -592,7 +562,7 @@ Integer i2 = new Integer(40);
System.out.println(i1==i2);
```
-`Integer i1=40` 这一行代码会发生拆箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。
+`Integer i1=40` 这一行代码会发生装箱,也就是说这行代码等价于 `Integer i1=Integer.valueOf(40)` 。因此,`i1` 直接使用的是常量池中的对象。而`Integer i1 = new Integer(40)` 会直接创建新的对象。
因此,答案是 `false` 。你答对了吗?
diff --git "a/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md" "b/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md"
deleted file mode 100644
index c3776c2da21..00000000000
--- "a/docs/java/multi-thread/synchronized\345\234\250JDK1.6\344\271\213\345\220\216\347\232\204\345\272\225\345\261\202\344\274\230\345\214\226.md"
+++ /dev/null
@@ -1,62 +0,0 @@
-JDK1.6 对锁的实现引入了大量的优化来减少锁操作的开销,如: **偏向锁**、**轻量级锁**、**自旋锁**、**适应性自旋锁**、**锁消除**、**锁粗化** 等等技术。
-
-锁主要存在四中状态,依次是:
-
-1. 无锁状态
-2. 偏向锁状态
-3. 轻量级锁状态
-4. 重量级锁状态
-
-锁🔐会随着竞争的激烈而逐渐升级。
-
-另外,需要注意:**锁可以升级不可降级,即 无锁 -> 偏向锁 -> 轻量级锁 -> 重量级锁是单向的。** 这种策略是为了提高获得锁和释放锁的效率。
-
-### 偏向锁
-
-**引入偏向锁的目的和引入轻量级锁的目的很像,他们都是为了没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗。但是不同是:轻量级锁在无竞争的情况下使用 CAS 操作去代替使用互斥量。而偏向锁在无竞争的情况下会把整个同步都消除掉**。
-
-偏向锁的“偏”就是偏心的偏,它的意思是会偏向于第一个获得它的线程,如果在接下来的执行中,该锁没有被其他线程获取,那么持有偏向锁的线程就不需要进行同步!(关于偏向锁的原理可以查看《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。)
-
-#### 偏向锁的加锁
-
-当一个线程访问同步块并获取锁时, 会在锁对象的对象头和栈帧中的锁记录里存储锁偏向的线程ID, 以后该线程进入和退出同步块时不需要进行CAS操作来加锁和解锁, 只需要简单的测试一下锁对象的对象头的MarkWord里是否存储着指向当前线程的偏向锁(线程ID是当前线程), 如果测试成功, 表示线程已经获得了锁; 如果测试失败, 则需要再测试一下MarkWord中偏向锁的标识是否设置成1(表示当前是偏向锁), 如果没有设置, 则使用CAS竞争锁, 如果设置了, 则尝试使用CAS将锁对象的对象头的偏向锁指向当前线程.
-
-#### 偏向锁的撤销
-
-偏向锁使用了一种等到竞争出现才释放锁的机制, 所以当其他线程尝试竞争偏向锁时, 持有偏向锁的线程才会释放锁. 偏向锁的撤销需要等到全局安全点(在这个时间点上没有正在执行的字节码). 首先会暂停持有偏向锁的线程, 然后检查持有偏向锁的线程是否存活, 如果线程不处于活动状态, 则将锁对象的对象头设置为无锁状态; 如果线程仍然活着, 则锁对象的对象头中的MarkWord和栈中的锁记录要么重新偏向于其它线程要么恢复到无锁状态, 最后唤醒暂停的线程(释放偏向锁的线程).
-
-但是对于锁竞争比较激烈的场合,偏向锁就失效了,因为这样场合极有可能每次申请锁的线程都是不相同的,因此这种场合下不应该使用偏向锁,否则会得不偿失,需要注意的是,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁。
-
-### 轻量级锁
-
-倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的)。**轻量级锁不是为了代替重量级锁,它的本意是在没有多线程竞争的前提下,减少传统的重量级锁使用操作系统互斥量产生的性能消耗,因为使用轻量级锁时,不需要申请互斥量。另外,轻量级锁的加锁和解锁都用到了CAS操作。** 关于轻量级锁的加锁和解锁的原理可以查看《深入理解Java虚拟机:JVM高级特性与最佳实践》第二版的13章第三节锁优化。
-
-**轻量级锁能够提升程序同步性能的依据是“对于绝大部分锁,在整个同步周期内都是不存在竞争的”,这是一个经验数据。如果没有竞争,轻量级锁使用 CAS 操作避免了使用互斥操作的开销。但如果存在锁竞争,除了互斥量开销外,还会额外发生CAS操作,因此在有锁竞争的情况下,轻量级锁比传统的重量级锁更慢!如果锁竞争激烈,那么轻量级将很快膨胀为重量级锁!**
-
-### 自旋锁和自适应自旋
-
-轻量级锁失败后,虚拟机为了避免线程真实地在操作系统层面挂起,还会进行一项称为自旋锁的优化手段。
-
-互斥同步对性能最大的影响就是阻塞的实现,因为挂起线程/恢复线程的操作都需要转入内核态中完成(用户态转换到内核态会耗费时间)。
-
-**一般线程持有锁的时间都不是太长,所以仅仅为了这一点时间去挂起线程/恢复线程是得不偿失的。** 所以,虚拟机的开发团队就这样去考虑:“我们能不能让后面来的请求获取锁的线程等待一会而不被挂起呢?看看持有锁的线程是否很快就会释放锁”。**为了让一个线程等待,我们只需要让线程执行一个忙循环(自旋),这项技术就叫做自旋**。
-
-百度百科对自旋锁的解释:
-
-> 何谓自旋锁?它是为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。但是两者在调度机制上略有不同。对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。
-
-自旋锁在 JDK1.6 之前其实就已经引入了,不过是默认关闭的,需要通过`--XX:+UseSpinning`参数来开启。JDK1.6及1.6之后,就改为默认开启的了。需要注意的是:自旋等待不能完全替代阻塞,因为它还是要占用处理器时间。如果锁被占用的时间短,那么效果当然就很好了!反之,相反!自旋等待的时间必须要有限度。如果自旋超过了限定次数任然没有获得锁,就应该挂起线程。**自旋次数的默认值是10次,用户可以修改`--XX:PreBlockSpin`来更改**。
-
-另外,**在 JDK1.6 中引入了自适应的自旋锁。自适应的自旋锁带来的改进就是:自旋的时间不在固定了,而是和前一次同一个锁上的自旋时间以及锁的拥有者的状态来决定,虚拟机变得越来越“聪明”了**。
-
-### 锁消除
-
-锁消除理解起来很简单,它指的就是虚拟机即使编译器在运行时,如果检测到那些共享数据不可能存在竞争,那么就执行锁消除。锁消除可以节省毫无意义的请求锁的时间。
-
-### 锁粗化
-
-原则上,我们在编写代码的时候,总是推荐将同步块的作用范围限制得尽量小,——只在共享数据的实际作用域才进行同步,这样是为了使得需要同步的操作数量尽可能变小,如果存在锁竞争,那等待线程也能尽快拿到锁。
-
-大部分情况下,上面的原则都是没有问题的,但是如果一系列的连续操作都对同一个对象反复加锁和解锁,那么会带来很多不必要的性能消耗。
-
-
diff --git "a/docs/java/multi-thread/\345\210\233\345\273\272\347\272\277\347\250\213\347\232\204\345\207\240\347\247\215\346\226\271\345\274\217\346\200\273\347\273\223.md" "b/docs/java/multi-thread/\345\210\233\345\273\272\347\272\277\347\250\213\347\232\204\345\207\240\347\247\215\346\226\271\345\274\217\346\200\273\347\273\223.md"
deleted file mode 100644
index 764a63a492a..00000000000
--- "a/docs/java/multi-thread/\345\210\233\345\273\272\347\272\277\347\250\213\347\232\204\345\207\240\347\247\215\346\226\271\345\274\217\346\200\273\347\273\223.md"
+++ /dev/null
@@ -1,40 +0,0 @@
-## 面试官:“创建线程有哪几种常见的方式?”
-
-1. 继承 Thread 类
-2. 实现 Runnable 接口
-3. 使用 Executor 框架
-4. 使用 FutureTask
-
-## 最简单的两种方式
-
-### 1.继承 Thread 类
-
-
-
-
-
-### 2.实现 Runnable 接口
-
-## 比较实用的两种方式
-
-### 3.使用 Executor 框架
-
-Executor 框架是 Java5 之后引进的,在 Java 5 之后,通过 Executor 来启动线程比使用 Thread 的 start 方法更好,除了更易管理,效率更好(用线程池实现,节约开销)外,还有关键的一点:有助于避免 this 逃逸问题。
-
-> 补充:this 逃逸是指在构造函数返回之前其他线程就持有该对象的引用. 调用尚未构造完全的对象的方法可能引发令人疑惑的错误。
-
-Executor 框架不仅包括了线程池的管理,还提供了线程工厂、队列以及拒绝策略等,Executor 框架让并发编程变得更加简单。
-
-为了能搞懂如何使用 Executor 框架创建
-
-### Executor 框架结构(主要由三大部分组成)
-
-#### 1) 任务(`Runnable` /`Callable`)
-
-执行任务需要实现的 **`Runnable` 接口** 或 **`Callable`接口**。**`Runnable` 接口**或 **`Callable` 接口** 实现类都可以被 **`ThreadPoolExecutor`** 或 **`ScheduledThreadPoolExecutor`** 执行。
-
-#### 2) 任务的执行(`Executor`)
-
-如下图所示,包括任务执行机制的核心接口 **`Executor`** ,以及继承自 `Executor` 接口的 **`ExecutorService` 接口。`ThreadPoolExecutor`** 和 **`ScheduledThreadPoolExecutor`** 这两个关键类实现了 **ExecutorService 接口**。
-
-### 4.使用 FutureTask
\ No newline at end of file
diff --git "a/docs/java/new-features/Java8foreach\346\214\207\345\215\227.md" "b/docs/java/new-features/Java8foreach\346\214\207\345\215\227.md"
deleted file mode 100644
index 48cda3abfd9..00000000000
--- "a/docs/java/new-features/Java8foreach\346\214\207\345\215\227.md"
+++ /dev/null
@@ -1,139 +0,0 @@
-> 本文由 JavaGuide 翻译,原文地址:https://www.baeldung.com/foreach-java
-
-## 1 概述
-
-在Java 8中引入的*forEach*循环为程序员提供了一种新的,简洁而有趣的迭代集合的方式。
-
-在本文中,我们将看到如何将*forEach*与集合*一起*使用,它采用何种参数以及此循环与增强的*for*循环的不同之处。
-
-## 2 基础知识
-
-```Java
-public interface Collection extends Iterable
-```
-
-Collection 接口实现了 Iterable 接口,而 Iterable 接口在 Java 8开始具有一个新的 API:
-
-```java
-void forEach(Consumer super T> action)//对 Iterable的每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。
-```
-
-使用*forEach*,我们可以迭代一个集合并对每个元素执行给定的操作,就像任何其他*迭代器一样。*
-
-例如,迭代和打印字符串集合*的*for循环版本:
-
-```java
-for (String name : names) {
- System.out.println(name);
-}
-```
-
-我们可以使用*forEach*写这个 :
-
-```java
-names.forEach(name -> {
- System.out.println(name);
-});
-```
-
-## 3.使用forEach方法
-
-### 3.1 匿名类
-
-我们使用 *forEach*迭代集合并对每个元素执行特定操作。**要执行的操作包含在实现Consumer接口的类中,并作为参数传递给forEach 。**
-
-所述*消费者*接口是一个功能接口(具有单个抽象方法的接口)。它接受输入并且不返回任何结果。
-
-Consumer 接口定义如下:
-
-```java
-@FunctionalInterface
-public interface Consumer {
- void accept(T t);
-}
-```
-任何实现,例如,只是打印字符串的消费者:
-
-```java
-Consumer printConsumer = new Consumer() {
- public void accept(String name) {
- System.out.println(name);
- };
-};
-```
-
-可以作为参数传递给*forEach*:
-
-```java
-names.forEach(printConsumer);
-```
-
-但这不是通过消费者和使用*forEach* API 创建操作的唯一方法。让我们看看我们将使用*forEach*方法的另外2种最流行的方式:
-
-### 3.2 Lambda表达式
-
-Java 8功能接口的主要优点是我们可以使用Lambda表达式来实例化它们,并避免使用庞大的匿名类实现。
-
-由于 Consumer 接口属于函数式接口,我们可以通过以下形式在Lambda中表达它:
-
-```java
-(argument) -> { body }
-name -> System.out.println(name)
-names.forEach(name -> System.out.println(name));
-```
-
-### 3.3 方法参考
-
-我们可以使用方法引用语法而不是普通的Lambda语法,其中已存在一个方法来对类执行操作:
-
-```java
-names.forEach(System.out::println);
-```
-
-## 4.forEach在集合中的使用
-
-### 4.1.迭代集合
-
-**任何类型Collection的可迭代 - 列表,集合,队列 等都具有使用forEach的相同语法。**
-
-因此,正如我们已经看到的,迭代列表的元素:
-
-```java
-List names = Arrays.asList("Larry", "Steve", "James");
-
-names.forEach(System.out::println);
-```
-
-同样对于一组:
-
-```java
-Set uniqueNames = new HashSet<>(Arrays.asList("Larry", "Steve", "James"));
-
-uniqueNames.forEach(System.out::println);
-```
-
-或者让我们说一个*队列*也是一个*集合*:
-
-```java
-Queue namesQueue = new ArrayDeque<>(Arrays.asList("Larry", "Steve", "James"));
-
-namesQueue.forEach(System.out::println);
-```
-
-### 4.2.迭代Map - 使用Map的forEach
-
-Map没有实现Iterable接口,但它**提供了自己的forEach 变体,它接受BiConsumer**。*
-
-```java
-Map namesMap = new HashMap<>();
-namesMap.put(1, "Larry");
-namesMap.put(2, "Steve");
-namesMap.put(3, "James");
-namesMap.forEach((key, value) -> System.out.println(key + " " + value));
-```
-
-### 4.3.迭代一个Map - 通过迭代entrySet
-
-```java
-namesMap.entrySet().forEach(entry -> System.out.println(entry.getKey() + " " + entry.getValue()));
-```
\ No newline at end of file
diff --git "a/docs/java/new-features/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md" "b/docs/java/new-features/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md"
deleted file mode 100644
index 7de58352a5f..00000000000
--- "a/docs/java/new-features/Java8\346\225\231\347\250\213\346\216\250\350\215\220.md"
+++ /dev/null
@@ -1,18 +0,0 @@
-### 书籍
-
-- **《Java8 In Action》**
-- **《写给大忙人看的Java SE 8》**
-
-上述书籍的PDF版本见 https://shimo.im/docs/CPB0PK05rP4CFmI2/ 中的 “Java 书籍推荐”。
-
-### 开源文档
-
-- **【译】Java 8 简明教程**:
-- **30 seconds of java8:**
-
-### 视频
-
-- **尚硅谷 Java 8 新特性**
-
-视频资源见: https://shimo.im/docs/CPB0PK05rP4CFmI2/ 。
-
diff --git a/docs/java/new-features/java8-common-new-features.md b/docs/java/new-features/java8-common-new-features.md
index c518a149683..1e9d8cd974a 100644
--- a/docs/java/new-features/java8-common-new-features.md
+++ b/docs/java/new-features/java8-common-new-features.md
@@ -1,4 +1,4 @@
-# 我,一个10年老程序员,最近才开始用 Java 8 新特性
+# Java8新特性实战
> 本文来自[cowbi](https://github.com/cowbi)的投稿~
diff --git "a/docs/java/new-features/Java8\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" b/docs/java/new-features/java8-tutorial-translate.md
similarity index 92%
rename from "docs/java/new-features/Java8\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md"
rename to docs/java/new-features/java8-tutorial-translate.md
index 5016d4aaf58..97bb45cf94e 100644
--- "a/docs/java/new-features/Java8\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md"
+++ b/docs/java/new-features/java8-tutorial-translate.md
@@ -1,50 +1,9 @@
-点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
+# 《Java8指南》中文翻译
随着 Java 8 的普及度越来越高,很多人都提到面试中关于Java 8 也是非常常问的知识点。应各位要求和需要,我打算对这部分知识做一个总结。本来准备自己总结的,后面看到Github 上有一个相关的仓库,地址:
-[https://github.com/winterbe/java8-tutorial](https://github.com/winterbe/java8-tutorial)。这个仓库是英文的,我对其进行了翻译并添加和修改了部分内容,下面是正文了。
-
-
-
-- [Java 8 Tutorial](#java-8-tutorial)
- - [接口的默认方法\(Default Methods for Interfaces\)](#接口的默认方法default-methods-for-interfaces)
- - [Lambda表达式\(Lambda expressions\)](#lambda表达式lambda-expressions)
- - [函数式接口\(Functional Interfaces\)](#函数式接口functional-interfaces)
- - [方法和构造函数引用\(Method and Constructor References\)](#方法和构造函数引用method-and-constructor-references)
- - [Lamda 表达式作用域\(Lambda Scopes\)](#lamda-表达式作用域lambda-scopes)
- - [访问局部变量](#访问局部变量)
- - [访问字段和静态变量](#访问字段和静态变量)
- - [访问默认接口方法](#访问默认接口方法)
- - [内置函数式接口\(Built-in Functional Interfaces\)](#内置函数式接口built-in-functional-interfaces)
- - [Predicate](#predicate)
- - [Function](#function)
- - [Supplier](#supplier)
- - [Consumer](#consumer)
- - [Comparator](#comparator)
- - [Optional](#optional)
- - [Streams\(流\)](#streams流)
- - [Filter\(过滤\)](#filter过滤)
- - [Sorted\(排序\)](#sorted排序)
- - [Map\(映射\)](#map映射)
- - [Match\(匹配\)](#match匹配)
- - [Count\(计数\)](#count计数)
- - [Reduce\(规约\)](#reduce规约)
- - [Parallel Streams\(并行流\)](#parallel-streams并行流)
- - [Sequential Sort\(串行排序\)](#sequential-sort串行排序)
- - [Parallel Sort\(并行排序\)](#parallel-sort并行排序)
- - [Maps](#maps)
- - [Date API\(日期相关API\)](#date-api日期相关api)
- - [Clock](#clock)
- - [Timezones\(时区\)](#timezones时区)
- - [LocalTime\(本地时间\)](#localtime本地时间)
- - [LocalDate\(本地日期\)](#localdate本地日期)
- - [LocalDateTime\(本地日期时间\)](#localdatetime本地日期时间)
- - [Annotations\(注解\)](#annotations注解)
- - [Where to go from here?](#where-to-go-from-here)
-
-
-
-
-# Java 8 Tutorial
+[https://github.com/winterbe/java8-tutorial](https://github.com/winterbe/java8-tutorial)。这个仓库是英文的,我对其进行了翻译并添加和修改了部分内容,下面是正文。
+
+------
欢迎阅读我对Java 8的介绍。本教程将逐步指导您完成所有新语言功能。 在简短的代码示例的基础上,您将学习如何使用默认接口方法,lambda表达式,方法引用和可重复注释。 在本文的最后,您将熟悉最新的 API 更改,如流,函数式接口(Functional Interfaces),Map 类的扩展和新的 Date API。 没有大段枯燥的文字,只有一堆注释的代码片段。
@@ -944,13 +903,3 @@ System.out.println(hints2.length); // 2
## Where to go from here?
关于Java 8的新特性就写到这了,肯定还有更多的特性等待发掘。JDK 1.8里还有很多很有用的东西,比如`Arrays.parallelSort`, `StampedLock`和`CompletableFuture`等等。
-
-## 公众号
-
-如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号。
-
-**《Java面试突击》:** 由本文档衍生的专为面试而生的《Java面试突击》V2.0 PDF 版本[公众号](#公众号)后台回复 **"Java面试突击"** 即可免费领取!
-
-**Java工程师必备学习资源:** 一些Java工程师常用学习资源[公众号](#公众号)后台回复关键字 **“1”** 即可免费无套路获取。
-
-
diff --git "a/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md" "b/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md"
index d27c7489745..a2714b49d51 100644
--- "a/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md"
+++ "b/docs/java/new-features/java\346\226\260\347\211\271\346\200\247\346\200\273\347\273\223.md"
@@ -1,4 +1,4 @@
-# 再见Java8!Java11新特性真香
+# 一文带你看遍 JDK9~15 的重要新特性!
Java 8 新特性见这里:[Java8 新特性最佳指南](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484744&idx=1&sn=9db31dca13d327678845054af75efb74&chksm=cea24a83f9d5c3956f4feb9956b068624ab2fdd6c4a75fe52d5df5dca356a016577301399548&token=1082669959&lang=zh_CN&scene=21#wechat_redirect) 。
diff --git "a/docs/java/tips/JAD\345\217\215\347\274\226\350\257\221tricks.md" b/docs/java/tips/jad.md
similarity index 99%
rename from "docs/java/tips/JAD\345\217\215\347\274\226\350\257\221tricks.md"
rename to docs/java/tips/jad.md
index 8c387754969..47d25a4ed53 100644
--- "a/docs/java/tips/JAD\345\217\215\347\274\226\350\257\221tricks.md"
+++ b/docs/java/tips/jad.md
@@ -1,3 +1,5 @@
+# JAD 反编译
+
[jad](https://varaneckas.com/jad/)反编译工具,已经不再更新,且只支持 JDK1.4,但并不影响其强大的功能。
基本用法:`jad xxx.class`,会生成直接可读的 `xxx.jad` 文件。
diff --git "a/docs/java/tips/locate-performance-problems/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\232\344\275\215\345\270\270\350\247\201Java\346\200\247\350\203\275\351\227\256\351\242\230.md" "b/docs/java/tips/locate-performance-problems/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\232\344\275\215\345\270\270\350\247\201Java\346\200\247\350\203\275\351\227\256\351\242\230.md"
index ab60c9a8bd4..7856d542333 100644
--- "a/docs/java/tips/locate-performance-problems/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\232\344\275\215\345\270\270\350\247\201Java\346\200\247\350\203\275\351\227\256\351\242\230.md"
+++ "b/docs/java/tips/locate-performance-problems/\346\211\213\346\212\212\346\211\213\346\225\231\344\275\240\345\256\232\344\275\215\345\270\270\350\247\201Java\346\200\247\350\203\275\351\227\256\351\242\230.md"
@@ -1,6 +1,6 @@
-> 本文来自木木匠投稿。
+# 手把手教你定位常见 Java 性能问题
-## 手把手教你定位常见 Java 性能问题
+> 本文来自木木匠投稿。
## 概述
@@ -326,7 +326,7 @@ procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
**sy=86**,说明内核态占用了 86%的 CPU,这里明显就是做上下文切换工作了。
-我们通过`top`命令以及`top -Hp pid`查看进程和线程 CPU 情况,发现 Java 线程 CPU 占满了,但是线程 CPU 使用情况很平均,没有某一个线程把 CPU 吃满的情况。
+我们通过`top`命令以及`top -Hp pid`查看进程和线程 CPU 情况,发现 Java 进程 CPU 占满了,但是线程 CPU 使用情况很平均,没有某一个线程把 CPU 吃满的情况。
```
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
diff --git a/docs/questions/java-big-data.md b/docs/questions/java-big-data.md
deleted file mode 100644
index 6bea7d6f163..00000000000
--- a/docs/questions/java-big-data.md
+++ /dev/null
@@ -1,65 +0,0 @@
-先说一下自己的经历,大学的时候我从大二开始学习 Java ,然后学了大半年多的安卓。之后就开始学习 Java 后台,学习完 Java 后台一些常用的知识比如 Java基础、Spring、MyBatis等等之后。因为感觉大数据领域发展也挺不错的,所以就接触了一些大数据方面的知识比如当时大数据领域的霸主 Hadoop 。
-
-> 我当时学习了很多比较古老的技术比如现在基本不会用的 JSP、Struts2等等。另外,我
-
-所以,我当时在找工作之间也纠结过自己到底是投大数据岗位还是Java后台开发岗位。
-
-主要纠结点如下:
-
-1. **薪资:** 大数据当时的薪资水平高于 Java 后台开发很多;
-2. **前景:** 我个人感觉大数据岗位的发展前景很好;
-3. **个人偏见:** 感觉大数据开发比 Java后台开发听着高大上点(哈哈,当时的我就是这么真实);
-
-不过在我分析了大部分公司的大数据岗位的要求以及自身的优势(Java后台开发的实际经验)之后还是义无反顾的只投递 Java 后台开发岗位。
-
-先来看一下几家典型的互联网公司对大数据工程师的要求(我找的都是允许应届毕业生投递的岗位):
-
-**SHEIN**
-
-> 很多人可以不了解这家低调的公司,主要原因是因为 SHEIN目前的主要业务是出口跨境电商,用户基本集中在海外。SHEIN 这些年的发展非常不错,总的来说是一家值得去的公司。
-
-
-
-SHEIN 的大数据岗位的要求写的还是比较有代代表性的!但是我觉得加上:**有扎实的Java基础、熟悉多线程与JVM相关原理** 这一条可能会更好!
-
-一家公司可能并不具有代表性,我们再来找一家公司的大数据岗位看看。
-
-**Alibaba**
-
-
-
-说明一下,阿里巴巴大的大数据开发岗位的描述其实挺友好的比如这样描述:
-
-> “如果你有参与过数据处理、分析、挖掘等相关项目更好”、“如果你对Hadoop、Hive、Hbase等分布式平台有一定的理解更好”。
-
-实际是这样吗?nonono!我信你个鬼,你个糟老头子坏的很!毕竟这么多人竞争这一个岗位,不会像描述的这么简单。
-
-如果你对 HDFS、HBase、Hadoop 甚至是 Elasticsearch这些不了解的话,还是会很难入场。
-
-**总结一下(偏大厂)大数据岗位的对于应届生的基本要求(社招的其实也差不多,对于经验要求会更高):**
-
-1. **算法和数据结构是最基本的(比如手写快排、手撕红黑树)。**
-2. **有扎实的Java基础、熟悉多线程与JVM相关原理。**
-3. **熟练使用 Linux ,熟悉一门脚本语言 shell 或者 Python**
-4. 熟悉Hadoop架构和工作原理、MapReduce编程、HDFS;熟悉Hive,最好有HQL优化经验;
-5. **熟练掌握 Spark 及 Spark Streaming开发,有实际项目研发经验更佳;**
-6. 熟悉 Elasticsearch、Kafka等技术会是加分项;
-7. ......
-
-所以,总的来说不论是对于 **Java 后台开发还是大数据开发都会要求你的数据结构和算法 Java 基础、多线程、jvm 底层这些掌握的要很好。** 很多人 Java 后台的人转大数据开发很快的原因也是在这里。
-
-正常一点的大数据面试还是比较有难度的,比如如果你写了你会 Spark 的话,他就会问题你:
-
-1. 什么场景下用的Spark ?解决了什么问题?
-2. Spark 执行机制了解吗?
-3. Spark 内存模型了解吗?
-4. ......
-
-另外,如果你的简历上写了你会 Spring 这些东西的话,面试官应该也会一并提问。可以看出现在的大数据岗位没有强制性要求你有 web 开发经验,在我那一年的时候,大部分大数据开发岗位都要求你还要有 web 开发经验。
-
-
-
-
-
-
-
diff --git a/docs/questions/java-learning-website-blog.md b/docs/questions/java-learning-website-blog.md
deleted file mode 100644
index d9ba95fae99..00000000000
--- a/docs/questions/java-learning-website-blog.md
+++ /dev/null
@@ -1,80 +0,0 @@
-## 推荐两个视频学习网站
-
-### 慕课网
-
-第一个推荐的学习网站应该是慕课网(慕课网私聊我打钱哈!),在我初学的时候,这个网站对我的帮助挺大的,里面有很多免费的课程,也有很多付费的课程。如果你没有特殊的需求,一般免费课程就够自己学的了。
-
-
-
-### 哔哩哔哩
-
-想不到弹幕追番/原创视频小站也被推荐了吧!不得不说哔哩哔哩上面的学习资源还是很多的,现在有很多年轻人都在上面学习呢!哈哈哈 大部分年轻人最爱的小破站可是受到过央视表扬的。被誉为年轻人学习的首要阵地,哔哩哔哩干杯!
-
-不过在哔哩哔哩上面越靠前的视频就是最好的视频或者说最适合你的视频,也是要筛选一下的。
-
-
-
-### 极客时间
-
-主打付费学习的一个付费学习社区(极客时间私聊我打钱哈!)。不过课程的质量大部分都挺高的,我自己也看了里面很多的课程,并且很多课程都是 Java 领域大佬级别的人物将的。
-
-
-
-## 推荐一些文字类型学习网站/博客
-
-### Github
-
-最牛逼的程序员交流网站!!!没有之一。一定要多逛逛!上面有很多好东西,比如我搜索 Java(它竟然给我返回贼多 javascript 的项目,啥意思???)
-
-
-
-比如我搜索女装,emm....然后就出来了这些东西,捂住眼睛,不敢看!
-
-
-
-### 菜鸟教程
-
-对于新手入门来说很不错的网站,大部分教程都是针对的入门级别。优点是网站教程内容比较完善并且内容质量也是有保障的。
-
-
-
-### w3cschool
-
-和菜鸟教程类似的一个网站,里面的教程也很齐全。
-
-
-
-### Stackoverflow
-
-**Stack Overflow**是一个程序设计领域的问答网站,网站允许注册用户提出或回答问题。和知乎很像,重大的一点不同是 Stack Overflow 可以对问题进行打分。
-
-
-
-### leetcode
-
-网站地址:https://leetcode-cn.com/
-
-工作之余没事去刷个算法题,岂不是美滋滋。
-
-
-
-### 一些不错的技术交流社区推荐
-
-1. **掘金**:[https://juejin.im/](https://juejin.im/ "https://juejin.im/") 。
-2. **segmentfault** : [https://segmentfault.com/](https://segmentfault.com/ "https://segmentfault.com/")
-3. **博客园** : [https://www.cnblogs.com/](https://www.cnblogs.com/ "https://www.cnblogs.com/")
-4. **慕课网手记** :[https://www.imooc.com/article](https://www.imooc.com/article "https://www.imooc.com/article")
-5. **知乎** :[https://www.zhihu.com/](https://www.zhihu.com/ "https://www.zhihu.com/")
-
-### 一些不错的博客/Github 推荐
-
-- SnailClimb 的 Github :[https://github.com/Snailclimb](https://github.com/Snailclimb "https://github.com/Snailclimb") 。(自荐一波哈!主要专注在 Java 基础和进阶、Spring、Spring Boot、Java 面试这方面。)
-- 徐靖峰个人博客 :[https://www.cnkirito.moe/](https://www.cnkirito.moe/ "https://www.cnkirito.moe/")(探讨 Java 生态的知识点,内容覆盖分布式服务治理、微服务、性能调优、各类源码分析)
-- 田小波:[http://www.tianxiaobo.com/](http://www.tianxiaobo.com/ "http://www.tianxiaobo.com/") (Java 、Spring 、MyBatis 、Dubbo)
-- 周立的博客: [http://www.itmuch.com/](http://www.itmuch.com/ "http://www.itmuch.com/")(Spring Cloud、Docker、Kubernetes,及其相关生态的技术)
-- Hollis: [https://www.hollischuang.com/](https://www.hollischuang.com/ "https://www.hollischuang.com/") (Java 后端)
-- 方志朋的专栏 : [https://www.fangzhipeng.com/](https://www.fangzhipeng.com/ "https://www.fangzhipeng.com/") (Java 面试 Java 并发 openresty kubernetes Docker 故事 )
-- 纯洁的微笑 : [http://www.ityouknow.com/](http://www.ityouknow.com/ "http://www.ityouknow.com/") (Java、SpringBoot、Spring Cloud)
-- 芋道源码: [http://www.iocoder.cn/](http://www.iocoder.cn/ "http://www.iocoder.cn/") (专注源码)。
-- 欢迎自荐
-- ......
diff --git a/docs/questions/java-training-4-month.md b/docs/questions/java-training-4-month.md
deleted file mode 100644
index 82c7690a366..00000000000
--- a/docs/questions/java-training-4-month.md
+++ /dev/null
@@ -1,104 +0,0 @@
-问题描述:
-
-> 最近在北京华软科技公司看到一个招聘,去咨询了人事部,他说培训四个月就能上岗,并且不要学费,上岗后再每还1000元,还一年,这个可靠吗?本人高中毕业,四个月能学会吗?谢谢了!!!
-
-下面是正文:
-
-一般说不要学费,上岗后每月再还1000元这种十有八九都不靠谱,就算你把合同看的再仔细,别人也总有各种办法去刁难你。
-
-另外,目前的互联网行业已经完全不是它刚开始盛行的样子了。在互联网爆火🔥的初期,你可能会简单用一下语言就能找到一个不错的工作。那时候,即使是没有学历支撑直接从培训班出来的基本也都找到了还算是不错的工作。但是,现在已经完全不一样了。我觉得主要可以从以下几个方面讲:
-
-1. **没有学历支撑,直接从培训班出来的找工作会很难,甚至找不到**;
-2. **面试的难度可以说一年比一年难,学的人越来越多,和你竞争的也越来越多,特别是像面试阿里、腾讯、字节跳动这样的大厂,你可能要和更多人去竞争。“面试造火箭,入职拎螺丝”想想也是正常,毕竟这么多人去竞争那少数的 offer,如果不难点的话,区分度就没那么明显了**;
-3. 学习计算机专业的越来越多,和你竞争的也越来越多,需求就那么一些,人多了之后,平均工资水平以后应该不会和其他行业差别这么大。但是,我个人感觉技术厉害的还是会很吃香。只是,普通的程序员的工资可能比不上前几年了。
-
-**养成一个学习习惯和编程习惯真的太重要了,一个好习惯的养成真的对后面的学习有很大帮助。** 说实话我自己当初在这方面吃了不少亏,很多比较好的习惯我也是后面自己才慢慢发现,所以这里想着重给大家说一下有哪些好的学习和编程习惯。另外,**不要在意自己会多少框架,真的没有一点用!**
-
-下面是一些我觉得还不错的编程好习惯,希望对大家有帮助。
-
-## 编程好习惯推荐
-
-> **下面这些我都总结在了 Github 上,更多内容可以通过这个链接查看:** https://github.com/Snailclimb/programmer-advancement 。
-
-### 正确提问
-
-我们平时任何时候都离不开提问特别是初学的时候,但是真正知道如何正确的提问的人很少。问别人问题前不要来一句“在吗”,你说你问了在吗我是回复好还是不回复好呢 ?不要让别人给你发 32 位的JDK,除非你是喜欢那个人。
-
-更多关于如何提问的内容,详见 github 上开源版『提问的智慧』 ,抽时间看一下,我想看完之后应该会有很多收获。
-
-更多内容可以查看我的这篇原创文章:[如何提问](docs/how-to-ask.md)
-
-### 健康生活
-
-我一直觉得这一方面是最重要的,我想很多人和我一样会无意识间忽略它,等到真的身体不舒服了,你才开始意识到健康生活的重要性。
-
-1. 除非万不得已,不要熬夜了。熬夜的危害就不用多说了,秃头加内分泌失调,你懂得!
-2. 看电脑45分钟之后,起来走5分钟,看看远方放松一下。不要觉得这5分钟浪费时间,相反,这5分钟可能为你带来更大的效率提升。
-3. 可以考虑买一个电脑架子,保护好自己脊椎的同时,办公体验也会提升很多。
-4. 可以下载一个护眼宝,感觉可以护眼模式挺棒的,非常适合我们这种需要经常盯着电脑的人使用,强烈安利。
-
-### 高效搜索
-
-尽量用 google 查找技术资料以及自己在学习中遇到的一些问题。
-
-### 解决 bug
-
-程序遇到问题先在 stackoverflow 找找,大部分别人已经遇到过了。如果上面没有的话,再考虑其他解决办法。实在解决不了的话,再去问你觉得有能力帮你解决的人(注意描述好自己的问题,不要随便截一个Bug 图)。
-
-### 善于总结
-
-学习完任何一门知识后,你可能当时看视频感觉老师讲的挺容易懂的。但是,过几天后你发现你忘的一干二净,别人问你一个类似的问题,你一点思路都没有。所以,我推荐你学完一门知识后不光要及时复习,还要做好总结,让知识形成一个体系。另外,你可以假想自己要给别人讲这个知识点,你能不能把这个知识点讲清楚呢?如果不能,说明你对这个知识点还没有彻底了解。这也就是人们经常说的费曼学习技巧。
-
-总结的方式:
-
-1. 有道云笔记、OneNote......这类专门用来记录笔记的软件上;
-2. 思维导图;
-3. 通过写博客输出。可以考虑自己搭建一个博客(hexo+GithubPages非常简单),你也可以在简书、掘金......等等技术交流社区写博客。Markdown 格式参考: 中文文案排版指北:
-
-### 写博客
-
-写博客有哪些好处:
-
-1. 对知识有更加深的认识,让自己的知识体系更加完整;
-2. 督促自己学习;
-3. 可能会带来不错的经济收入;
-4. 提升个人影响力;
-5. 拥有更多机会;
-6. ......
-
-**总的来说,写博客是一件利己利彼的事情。你可能会从中收获到很多东西,你写的东西也可能对别人也有很大的帮助。但是,写博客还是比较耗费自己时间的,你需要和工作做好权衡。**
-
-**分享是一种美德,任何行业都不是靠单打独斗的,写博客、写好博客是一个程序员很好的习惯。我为人人,人人为我!**
-
-更多内容可以查看我的这篇原创文章:[我为什么推荐你写博客?](./docs/我为什么推荐你写博客.md)
-
-### 多用 Github
-
-没事多去Github转转,如果有能力可以参与到一些开源项目中。多看看别人开源的优秀项目,看看别人的代码和设计思路,看的多了,你的编程思想也会慢慢得到提升。除了这些优秀的开源项目之外,Github上面还有很多不错的开源文档、开源资料什么的,我觉得对我们平时学习都挺有帮助。Github用得好还能装一下,毕竟人家还是一个全英文网站,咳咳咳。
-
-### 实践
-
-多去实践,将学到的东西运用到实际项目中去。很多人都找我抱怨过没有实际项目让自己去做,怎么能有项目经验呢?如果实在没有实际项目让你去做,我觉得你可以通过下面几种方式:
-
-1. 在网上找一个符合自己能力与找工作需求的实战项目视频或者博客跟着老师一起做。做的过程中,你要有自己的思考,不要浅尝辄止,对于很多知识点,别人的讲解可能只是满足项目就够了,你自己想多点知识的话,对于重要的知识点就要自己学会去往深出学。
-2. Github或者码云上面有很多实战类别项目,你可以选择一个来研究,为了让自己对这个项目更加理解,在理解原有代码的基础上,你可以对原有项目进行改进或者增加功能。
-3. 自己动手去做一个自己想完成的东西,遇到不会的东西就临时去学,现学现卖。
-
-### 注意代码规范
-
-从学习编程的第一天起就要养成不错的编码习惯,包、类、方法的命名这些是最基本的。
-
-推荐阅读:
-
-- 阿里巴巴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编程风格指南:
-- Effective Java第三版中文版:
-
-### 沟通能力
-
-程序员也离不开沟通。你可能需要与客户交流需求,还要和同事交流项目问题,还有可能定期需要向领导汇报项目进展情况。所以,我觉得不错的沟通能力也是一个优秀的程序员应该有的基本素质。
-
-## 学习方法和学习路线推荐
-
-推荐查看我的这篇文章[《可能是最适合你的Java学习方法和路线推荐》](https://github.com/Snailclimb/JavaGuide/blob/master/docs/questions/java-learning-path-and-methods.md),文中提到的学习路线以及方法是笔主根据个人学习经历总结改进后得出,我相信照着这条学习路线来你的学习效率会非常高。
-
diff --git a/docs/readme.md b/docs/readme.md
new file mode 100644
index 00000000000..814f5e936a5
--- /dev/null
+++ b/docs/readme.md
@@ -0,0 +1,70 @@
+---
+icon: creative
+title: JavaGuide(Java学习&&面试指南)
+---
+
+> 1. **贡献指南** :欢迎参与 [JavaGuide 的维护工作](https://github.com/Snailclimb/JavaGuide/issues/1235),这是一件非常有意义的事情。
+> 2. **知识星球** : 简历指导/Java 学习/面试指导/面试小册。欢迎加入[我的知识星球](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) 。
+> 3. **面试专版** :准备面试的小伙伴可以考虑面试专版:[《Java 面试进阶指北 》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7) (质量很高,专为面试打造)
+> 4. **转载须知** :以下所有文章如非文首说明为转载皆为我(Guide 哥)的原创,转载在文首注明出处,如发现恶意抄袭/搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!⛽️
+
+在大三准备面试的时候,我开源了 JavaGuide 。我把自己准备面试过程中的一些总结都毫不保留地通过 JavaGuide 分享了出来。
+
+开源 JavaGuide 初始想法源于自己的个人那一段比较迷茫的学习经历。主要目的是为了通过这个开源平台来帮助一些在学习 Java 或者面试过程中遇到问题的小伙伴。
+
+- **对于 Java 初学者来说:** 本文档倾向于给你提供一个比较详细的学习路径,让你对于 Java 整体的知识体系有一个初步认识。另外,本文的一些文章也是你学习和复习 Java 知识不错的实践;
+- **对于非 Java 初学者来说:** 本文档更适合回顾知识,准备面试,搞清面试应该把重心放在那些问题上。要搞清楚这个道理:提前知道那些面试常见,不是为了背下来应付面试,而是为了让你可以更有针对的学习重点。
+
+相比于其他通过 JavaGuide 学到东西或者说助力获得 offer 的朋友来说 , JavaGuide 对我的意义更加重大。不夸张的说,有时候真的感觉像是自己的孩子一点一点长大一样,我一直用心呵护着它。
+
+虽然,我花了很长时间来维护它,但是,我觉得非常值得!非常有有益!
+
+另外,[JavaGuide](https://github.com/Snailclimb/JavaGuide) 的 Star 数量虽然比较多,但是它的价值和含金量一定是不能和 Dubbo、Nacos 、SkyWalking 这些优秀的国产开源项目比的。希望国内可以出更多优秀的开源项目!
+
+希望大家对面试不要抱有侥幸的心理,打铁还需自身硬! 我希望这个文档是为你学习 Java 指明方向,而不是用来应付面试用的。加油!奥利给!
+
+## 项目说明
+
+1. 项目的 Markdown 格式参考:[Github Markdown 格式](https://guides.github.com/features/mastering-markdown/),表情素材来自:[EMOJI CHEAT SHEET](https://www.webpagefx.com/tools/emoji-cheat-sheet/)。
+2. Logo 下的小图标是使用[Shields.IO](https://shields.io/) 生成的。
+
+## 如何对该开源文档进行贡献
+
+- 笔记内容大多是手敲,所以难免会有笔误,你可以帮我找错别字。
+- 很多知识点我可能没有涉及到,所以你可以对其他知识点进行补充。
+- 现有的知识点难免存在不完善或者错误,所以你可以对已有知识点进行修改/补充。
+
+如果要提 issue/question 的话,强烈推荐阅读 [《提问的智慧》](https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way)、[《如何向开源社区提问题》](https://github.com/seajs/seajs/issues/545) 和 [《如何有效地报告 Bug》](http://www.chiark.greenend.org.uk/~sgtatham/bugs-cn.html)、[《如何向开源项目提交无法解答的问题》](https://zhuanlan.zhihu.com/p/25795393)。
+
+## 贡献者
+
+[你可以点此链接查看 JavaGuide 的所有贡献者。](https://github.com/Snailclimb/JavaGuide/graphs/contributors) 感谢你们让 JavaGuide 变得更好!如果你们来到武汉一定要找我,我请你们吃饭玩耍。
+
+_悄悄话:JavaGuide 会不定时为贡献者们送福利。_
+
+## 待办
+
+- [ ] 计算机网络知识点完善
+- [ ] 分布式常见理论和算法总结完善
+
+## 捐赠支持
+
+项目的发展离不开你的支持,如果 JavaGuide 帮助到了你找到自己满意的 offer,请作者喝杯咖啡吧 ☕ 后续会继续完善更新!加油!
+
+[点击捐赠支持作者](https://www.yuque.com/snailclimb/dr6cvl/mr44yt#vu3ok)
+
+## 联系我
+
+
+
+整理了一份各个技术的学习路线,需要的小伙伴加我微信:“**JavaGuide1996**”备注“**Github-学习路线**”即可!
+
+
+
+## 公众号
+
+如果大家想要实时关注我更新的文章以及分享的干货的话,可以关注我的公众号“**JavaGuide**”。
+
+**《Java 面试突击》:** 由本文档衍生的专为面试而生的《Java 面试突击》V4.0 PDF 版本[公众号](#公众号)后台回复 **"面试突击"** 即可领取!
+
+
diff --git "a/docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md" "b/docs/system-design/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
similarity index 100%
rename from "docs/java/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
rename to "docs/system-design/J2EE\345\237\272\347\241\200\347\237\245\350\257\206.md"
diff --git "a/docs/system-design/coding-way/RESTfulAPI\347\256\200\346\230\216\346\225\231\347\250\213.md" b/docs/system-design/basis/RESTfulAPI.md
similarity index 99%
rename from "docs/system-design/coding-way/RESTfulAPI\347\256\200\346\230\216\346\225\231\347\250\213.md"
rename to docs/system-design/basis/RESTfulAPI.md
index ee4296ed781..142c0f735f7 100644
--- "a/docs/system-design/coding-way/RESTfulAPI\347\256\200\346\230\216\346\225\231\347\250\213.md"
+++ b/docs/system-design/basis/RESTfulAPI.md
@@ -1,3 +1,7 @@
+
+# RestFul API 简明教程
+
+

大家好,我是 Guide哥!
diff --git a/docs/system-design/naming.md b/docs/system-design/basis/naming.md
similarity index 98%
rename from docs/system-design/naming.md
rename to docs/system-design/basis/naming.md
index 5075c057b37..66f333458a3 100644
--- a/docs/system-design/naming.md
+++ b/docs/system-design/basis/naming.md
@@ -1,8 +1,6 @@
-> 可选标题:工作半年,变量命名不规范,被diss了!
->
-> 项目组新来的实习生因为变量命名被 “diss” 了!
-大家好,这里是热爱分享的 Guide !
+
+# Java 命名之道
我还记得我刚工作那一段时间, 项目 Code Review 的时候,我经常因为变量命名不规范而被 “diss”!
diff --git a/docs/system-design/pictures/Codelf.png b/docs/system-design/basis/pictures/Codelf.png
similarity index 100%
rename from docs/system-design/pictures/Codelf.png
rename to docs/system-design/basis/pictures/Codelf.png
diff --git a/docs/system-design/pictures/dubbo-naming.png b/docs/system-design/basis/pictures/dubbo-naming.png
similarity index 100%
rename from docs/system-design/pictures/dubbo-naming.png
rename to docs/system-design/basis/pictures/dubbo-naming.png
diff --git a/docs/system-design/pictures/marting-naming.png b/docs/system-design/basis/pictures/marting-naming.png
similarity index 100%
rename from docs/system-design/pictures/marting-naming.png
rename to docs/system-design/basis/pictures/marting-naming.png
diff --git a/docs/system-design/pictures/naming-mindmap.png b/docs/system-design/basis/pictures/naming-mindmap.png
similarity index 100%
rename from docs/system-design/pictures/naming-mindmap.png
rename to docs/system-design/basis/pictures/naming-mindmap.png
diff --git a/docs/system-design/pictures/vscode-codelf.png b/docs/system-design/basis/pictures/vscode-codelf.png
similarity index 100%
rename from docs/system-design/pictures/vscode-codelf.png
rename to docs/system-design/basis/pictures/vscode-codelf.png
diff --git "a/docs/system-design/distributed-system/BASE\347\220\206\350\256\272.md" "b/docs/system-design/distributed-system/BASE\347\220\206\350\256\272.md"
deleted file mode 100644
index 17c5789ce28..00000000000
--- "a/docs/system-design/distributed-system/BASE\347\220\206\350\256\272.md"
+++ /dev/null
@@ -1,66 +0,0 @@
-## BASE 理论
-
-[BASE 理论](https://dl.acm.org/doi/10.1145/1394127.1394128)起源于 2008 年, 由eBay的架构师Dan Pritchett在ACM上发表。
-
-### 简介
-
-**BASE** 是 **Basically Available(基本可用)** 、**Soft-state(软状态)** 和 **Eventually Consistent(最终一致性)** 三个短语的缩写。BASE 理论是对 CAP 中一致性 C 和可用性 A 权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于 CAP 定理逐步演化而来的,它大大降低了我们对系统的要求。
-
-### BASE 理论的核心思想
-
-即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。
-
-> 也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。
-
-**BASE 理论本质上是对 CAP 的延伸和补充,更具体地说,是对 CAP 中 AP 方案的一个补充。**
-
-**为什么这样说呢?**
-
-CAP 理论这节我们也说过了:
-
-> 如果系统没有发生“分区”的话,节点间的网络连接通信正常的话,也就不存在 P 了。这个时候,我们就可以同时保证 C 和 A 了。因此,**如果系统发生“分区”,我们要考虑选择 CP 还是 AP。如果系统没有发生“分区”的话,我们要思考如何保证 CA 。**
-
-因此,AP 方案只是在系统发生分区的时候放弃一致性,而不是永远放弃一致性。在分区故障恢复后,系统应该达到最终一致性。这一点其实就是 BASE 理论延伸的地方。
-
-### BASE 理论三要素
-
-
-
-#### 1. 基本可用
-
-基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。
-
-**什么叫允许损失部分可用性呢?**
-
-- **响应时间上的损失**: 正常情况下,处理用户请求需要 0.5s 返回结果,但是由于系统出现故障,处理用户请求的时间变为 3 s。
-- **系统功能上的损失**:正常情况下,用户可以使用系统的全部功能,但是由于系统访问量突然剧增,系统的部分非核心功能无法使用。
-
-#### 2. 软状态
-
-软状态指允许系统中的数据存在中间状态(**CAP 理论中的数据不一致**),并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时。
-
-#### 3. 最终一致性
-
-最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
-
-> 分布式一致性的 3 种级别:
->
-> 1. **强一致性** :系统写入了什么,读出来的就是什么。
->
-> 2. **弱一致性** :不一定可以读取到最新写入的值,也不保证多少时间之后读取到的数据是最新的,只是会尽量保证某个时刻达到数据一致的状态。
->
-> 3. **最终一致性** :弱一致性的升级版,系统会保证在一定时间内达到数据一致的状态。
->
-> **业界比较推崇是最终一致性级别,但是某些对数据一致要求十分严格的场景比如银行转账还是要保证强一致性。**
-
-那实现最终一致性的具体方式是什么呢? [《分布式协议与算法实战》](http://gk.link/a/10rZM) 中是这样介绍:
-
-> - **读时修复** : 在读取数据时,检测数据的不一致,进行修复。比如 Cassandra 的 Read Repair 实现,具体来说,在向 Cassandra 系统查询数据的时候,如果检测到不同节点 的副本数据不一致,系统就自动修复数据。
-> - **写时修复** : 在写入数据,检测数据的不一致时,进行修复。比如 Cassandra 的 Hinted Handoff 实现。具体来说,Cassandra 集群的节点之间远程写数据的时候,如果写失败 就将数据缓存下来,然后定时重传,修复数据的不一致性。
-> - **异步修复** : 这个是最常用的方式,通过定时对账检测副本数据的一致性,并修复。
-
-比较推荐 **写时修复**,这种方式对性能消耗比较低。
-
-### 总结
-
-**ACID 是数据库事务完整性的理论,CAP 是分布式系统设计理论,BASE 是 CAP 理论中 AP 方案的延伸。**
diff --git a/docs/system-design/framework/mybatis/mybatis-interview.md b/docs/system-design/framework/mybatis/mybatis-interview.md
index db84dee3b5c..8f982e328cf 100644
--- a/docs/system-design/framework/mybatis/mybatis-interview.md
+++ b/docs/system-design/framework/mybatis/mybatis-interview.md
@@ -1,4 +1,6 @@
-> 本篇文章是JavaGuide收集自网络,原出处不明。
+# MyBatis 常见面试总结
+
+> 本篇文章是 JavaGuide 收集自网络,原出处不明。
MyBatis 技术内幕系列博客,从原理和源码角度,介绍了其内部实现细节,无论是写的好与不好,我确实是用心写了,由于并不是介绍如何使用 MyBatis 的文章,所以,一些参数使用细节略掉了,我们的目标是介绍 MyBatis 的技术架构和重要组成部分,以及基本运行原理。
@@ -14,26 +16,26 @@ MyBatis 技术内幕系列博客,从原理和源码角度,介绍了其内部
答:
-- `${}`是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如\${driver}会被静态替换为`com.mysql.jdbc.Driver`。
-- `#{}`是 sql 的参数占位符,MyBatis 会将 sql 中的`#{}`替换为?号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的?号占位符设置参数值,比如 ps.setInt(0, parameterValue),`#{item.name}` 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 `param.getItem().getName()`。
+- `${}`是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换,比如\${driver}会被静态替换为`com.mysql.jdbc. Driver`。
+- `#{}`是 sql 的参数占位符,MyBatis 会将 sql 中的`#{}`替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值,比如 ps.setInt(0, parameterValue),`#{item.name}` 的取值方式为使用反射从参数对象中获取 item 对象的 name 属性值,相当于 `param.getItem().getName()`。
#### 2、Xml 映射文件中,除了常见的 select|insert|update|delete 标签之外,还有哪些标签?
注:这道题是京东面试官面试我时问的。
-答:还有很多其他的标签,``、``、``、``、``,加上动态 sql 的 9 个标签,`trim|where|set|foreach|if|choose|when|otherwise|bind`等,其中为 sql 片段标签,通过``标签引入 sql 片段,``为不支持自增的主键生成策略标签。
+答:还有很多其他的标签, `` 、 `` 、 `` 、 `` 、 `` ,加上动态 sql 的 9 个标签, `trim|where|set|foreach|if|choose|when|otherwise|bind` 等,其中 `` 为 sql 片段标签,通过 `` 标签引入 sql 片段, `` 为不支持自增的主键生成策略标签。
#### 3、最佳实践中,通常一个 Xml 映射文件,都会写一个 Dao 接口与之对应,请问,这个 Dao 接口的工作原理是什么?Dao 接口里的方法,参数不同时,方法能重载吗?
注:这道题也是京东面试官面试我被问的。
-答:Dao 接口,就是人们常说的 `Mapper`接口,接口的全限名,就是映射文件中的 namespace 的值,接口的方法名,就是映射文件中`MappedStatement`的 id 值,接口方法内的参数,就是传递给 sql 的参数。`Mapper`接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个`MappedStatement`,举例:`com.mybatis3.mappers.StudentDao.findStudentById`,可以唯一找到 namespace 为`com.mybatis3.mappers.StudentDao`下面`id = findStudentById`的`MappedStatement`。在 MyBatis 中,每一个``、``、``、``标签,都会被解析为一个`MappedStatement`对象。
+答:Dao 接口,就是人们常说的 `Mapper` 接口,接口的全限名,就是映射文件中的 namespace 的值,接口的方法名,就是映射文件中 `MappedStatement` 的 id 值,接口方法内的参数,就是传递给 sql 的参数。 `Mapper` 接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为 key 值,可唯一定位一个 `MappedStatement` ,举例: `com.mybatis3.mappers. StudentDao.findStudentById` ,可以唯一找到 namespace 为 `com.mybatis3.mappers. StudentDao` 下面 `id = findStudentById` 的 `MappedStatement` 。在 MyBatis 中,每一个 `` 、 `` 、 `` 、 `` 标签,都会被解析为一个 `MappedStatement` 对象。
~~Dao 接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。~~
-Dao 接口里的方法可以重载,但是Mybatis的XML里面的ID不允许重复。
+Dao 接口里的方法可以重载,但是 Mybatis 的 XML 里面的 ID 不允许重复。
-Mybatis版本3.3.0,亲测如下:
+Mybatis 版本 3.3.0,亲测如下:
```java
/**
@@ -42,12 +44,12 @@ Mybatis版本3.3.0,亲测如下:
public interface StuMapper {
List getAllStu();
-
+
List getAllStu(@Param("id") Integer id);
}
```
-然后在 `StuMapper.xml` 中利用Mybatis的动态sql就可以实现。
+然后在 `StuMapper.xml` 中利用 Mybatis 的动态 sql 就可以实现。
```java
@@ -60,17 +62,17 @@ public interface StuMapper {
```
-能正常运行,并能得到相应的结果,这样就实现了在Dao接口中写重载方法。
+能正常运行,并能得到相应的结果,这样就实现了在 Dao 接口中写重载方法。
**Mybatis 的 Dao 接口可以有多个重载方法,但是多个接口对应的映射必须只有一个,否则启动会报错。**
-相关 issue :[更正:Dao 接口里的方法可以重载,但是Mybatis的XML里面的ID不允许重复!](https://github.com/Snailclimb/JavaGuide/issues/1122)。
+相关 issue :[更正:Dao 接口里的方法可以重载,但是 Mybatis 的 XML 里面的 ID 不允许重复!](https://github.com/Snailclimb/JavaGuide/issues/1122)。
-Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行`MappedStatement`所代表的 sql,然后将 sql 执行结果返回。
+Dao 接口的工作原理是 JDK 动态代理,MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象,代理对象 proxy 会拦截接口方法,转而执行 `MappedStatement` 所代表的 sql,然后将 sql 执行结果返回。
##### ==补充:==
-Dao接口方法可以重载,但是需要满足以下条件:
+Dao 接口方法可以重载,但是需要满足以下条件:
1. 仅有一个无参方法和一个有参方法
2. 多个有参方法时,参数数量必须一致。且使用相同的 `@Param` ,或者使用 `param1` 这种
@@ -106,7 +108,7 @@ Person queryById(@Param("id") Long id, @Param("name") String name);
```
-`org.apache.ibatis.scripting.xmltags.DynamicContext.ContextAccessor#getProperty`方法用于获取``标签中的条件值
+`org.apache.ibatis.scripting.xmltags. DynamicContext. ContextAccessor#getProperty` 方法用于获取 `` 标签中的条件值
```java
public Object getProperty(Map context, Object target, Object name) {
@@ -126,9 +128,9 @@ public Object getProperty(Map context, Object target, Object name) {
}
```
-`parameterObject`为map,存放的是Dao接口中参数相关信息。
+`parameterObject` 为 map,存放的是 Dao 接口中参数相关信息。
-`((Map)parameterObject).get(name)`方法如下
+`((Map)parameterObject).get(name)` 方法如下
```java
public V get(Object key) {
@@ -139,9 +141,9 @@ public V get(Object key) {
}
```
-1. `queryById()`方法执行时,`parameterObject`为null,`getProperty`方法返回null值,``标签获取的所有条件值都为null,所有条件不成立,动态sql可以正常执行。
-2. `queryById(1L)`方法执行时,`parameterObject`为map,包含了`id`和`param1`两个key值。当获取``标签中`name`的属性值时,进入`((Map)parameterObject).get(name)`方法中,map中key不包含`name`,所以抛出异常。
-3. `queryById(1L,"1")`方法执行时,`parameterObject`中包含`id`,`param1`,`name`,`param2`四个key值,`id`和`name`属性都可以获取到,动态sql正常执行。
+1. `queryById()`方法执行时,`parameterObject`为 null,`getProperty`方法返回 null 值,``标签获取的所有条件值都为 null,所有条件不成立,动态 sql 可以正常执行。
+2. `queryById(1L)`方法执行时,`parameterObject`为 map,包含了`id`和`param1`两个 key 值。当获取``标签中`name`的属性值时,进入`((Map)parameterObject).get(name)`方法中,map 中 key 不包含`name`,所以抛出异常。
+3. `queryById(1L,"1")`方法执行时,`parameterObject`中包含`id`,`param1`,`name`,`param2`四个 key 值,`id`和`name`属性都可以获取到,动态 sql 正常执行。
#### 4、MyBatis 是如何进行分页的?分页插件的原理是什么?
@@ -151,15 +153,15 @@ public V get(Object key) {
分页插件的基本原理是使用 MyBatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。
-举例:`select _ from student`,拦截 sql 后重写为:`select t._ from (select \* from student)t limit 0,10`
+举例: `select _ from student` ,拦截 sql 后重写为: `select t._ from (select \* from student)t limit 0,10`
#### 5、简述 MyBatis 的插件运行原理,以及如何编写一个插件。
注:我出的。
-答:MyBatis 仅可以编写针对 `ParameterHandler`、`ResultSetHandler`、`StatementHandler`、`Executor` 这 4 种接口的插件,MyBatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 `InvocationHandler` 的 `invoke()`方法,当然,只会拦截那些你指定需要拦截的方法。
+答:MyBatis 仅可以编写针对 `ParameterHandler` 、 `ResultSetHandler` 、 `StatementHandler` 、 `Executor` 这 4 种接口的插件,MyBatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 `InvocationHandler` 的 `invoke()` 方法,当然,只会拦截那些你指定需要拦截的方法。
-实现 MyBatis 的 Interceptor 接口并复写` intercept()`方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
+实现 MyBatis 的 Interceptor 接口并复写 `intercept()` 方法,然后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了在配置文件中配置你编写的插件。
#### 6、MyBatis 执行批量插入,能返回数据库主键列表吗?
@@ -171,7 +173,7 @@ public V get(Object key) {
注:我出的。
-答:MyBatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,MyBatis 提供了 9 种动态 sql 标签 `trim|where|set|foreach|if|choose|when|otherwise|bind`。
+答:MyBatis 动态 sql 可以让我们在 Xml 映射文件内,以标签的形式编写动态 sql,完成逻辑判断和动态拼接 sql 的功能,MyBatis 提供了 9 种动态 sql 标签 `trim|where|set|foreach|if|choose|when|otherwise|bind` 。
其执行原理为,使用 OGNL 从 sql 参数对象中计算表达式的值,根据表达式的值动态拼接 sql,以此来完成动态 sql 的功能。
@@ -179,7 +181,7 @@ public V get(Object key) {
注:我出的。
-答:第一种是使用``标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是 name,小写,但是列名不区分大小写,MyBatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMe,MyBatis 一样可以正常工作。
+答:第一种是使用 `` 标签,逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能,将列别名书写为对象属性名,比如 T_NAME AS NAME,对象属性名一般是 name,小写,但是列名不区分大小写,MyBatis 会忽略列名大小写,智能找到与之对应对象属性名,你甚至可以写成 T_NAME AS NaMe,MyBatis 一样可以正常工作。
有了列名与属性名的映射关系后,MyBatis 通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。
@@ -187,11 +189,11 @@ public V get(Object key) {
注:我出的。
-答:能,MyBatis 不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把 `selectOne()`修改为 `selectList()`即可;多对多查询,其实就是一对多查询,只需要把 `selectOne()`修改为 `selectList()`即可。
+
关联对象查询,有两种实现方式,一种是单独发送一个 sql 去查询关联对象,赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用 join 查询,一部分列是 A 对象的属性值,另外一部分列是关联对象 B 的属性值,好处是只发一个 sql 查询,就可以把主对象和其关联对象查出来。
-那么问题来了,join 查询出来 100 条记录,如何确定主对象是 5 个,而不是 100 个?其去重复的原理是``标签内的``子标签,指定了唯一确定一条记录的 id 列,MyBatis 根据列值来完成 100 条记录的去重复功能,``可以有多个,代表了联合主键的语意。
+那么问题来了,join 查询出来 100 条记录,如何确定主对象是 5 个,而不是 100 个?其去重复的原理是 `` 标签内的 `` 子标签,指定了唯一确定一条记录的 id 列,MyBatis 根据 `` 列值来完成 100 条记录的去重复功能, `` 可以有多个,代表了联合主键的语意。
同样主对象的关联对象,也是根据这个原理去重复的,尽管一般情况下,只有主对象会有重复记录,关联对象一般不会重复。
@@ -212,7 +214,7 @@ public V get(Object key) {
答:MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载,association 指的就是一对一,collection 指的就是一对多查询。在 MyBatis 配置文件中,可以配置是否启用延迟加载 `lazyLoadingEnabled=true|false。`
-它的原理是,使用` CGLIB` 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 `a.getB().getName()`,拦截器 `invoke()`方法发现 `a.getB()`是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 `a.getB().getName()`方法的调用。这就是延迟加载的基本原理。
+它的原理是,使用 `CGLIB` 创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用 `a.getB().getName()` ,拦截器 `invoke()` 方法发现 `a.getB()` 是 null 值,那么就会单独发送事先保存好的查询关联 B 对象的 sql,把 B 查询上来,然后调用 a.setB(b),于是 a 的对象 b 属性就有值了,接着完成 `a.getB().getName()` 方法的调用。这就是延迟加载的基本原理。
当然了,不光是 MyBatis,几乎所有的包括 Hibernate,支持延迟加载的原理都是一样的。
@@ -222,7 +224,7 @@ public V get(Object key) {
答:不同的 Xml 映射文件,如果配置了 namespace,那么 id 可以重复;如果没有配置 namespace,那么 id 不能重复;毕竟 namespace 不是必须的,只是最佳实践而已。
-原因就是 namespace+id 是作为 `Map`的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。
+原因就是 namespace+id 是作为 `Map` 的 key 使用的,如果没有 namespace,就剩下 id,那么,id 重复会导致数据互相覆盖。有了 namespace,自然 id 就可以重复,namespace 不同,namespace+id 自然也就不同。
#### 12、MyBatis 中如何执行批处理?
@@ -234,13 +236,13 @@ public V get(Object key) {
注:我出的
-答:MyBatis 有三种基本的 Executor 执行器,**`SimpleExecutor`、`ReuseExecutor`、`BatchExecutor`。**
+答:MyBatis 有三种基本的 Executor 执行器,** `SimpleExecutor` 、 `ReuseExecutor` 、 `BatchExecutor` 。**
-**`SimpleExecutor`:**每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
+** `SimpleExecutor` :**每执行一次 update 或 select,就开启一个 Statement 对象,用完立刻关闭 Statement 对象。
-**`ReuseExecutor`:**执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map内,供下一次使用。简言之,就是重复使用 Statement 对象。
+** `ReuseExecutor` :**执行 update 或 select,以 sql 作为 key 查找 Statement 对象,存在就使用,不存在就创建,用完后,不关闭 Statement 对象,而是放置于 Map内,供下一次使用。简言之,就是重复使用 Statement 对象。
-**`BatchExecutor`:**执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
+** `BatchExecutor` :**执行 update(没有 select,JDBC 批处理不支持 select),将所有 sql 都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
作用范围:Executor 的这些特点,都严格限制在 SqlSession 生命周期范围内。
@@ -254,7 +256,7 @@ public V get(Object key) {
注:我出的
-答:MyBatis 可以映射枚举类,不单可以映射枚举类,MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 `TypeHandler`,实现 `TypeHandler` 的 `setParameter()`和 `getResult()`接口方法。`TypeHandler` 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 `setParameter()`和 `getResult()`两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。
+答:MyBatis 可以映射枚举类,不单可以映射枚举类,MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 `TypeHandler` ,实现 `TypeHandler` 的 `setParameter()` 和 `getResult()` 接口方法。 `TypeHandler` 有两个作用,一是完成从 javaType 至 jdbcType 的转换,二是完成 jdbcType 至 javaType 的转换,体现为 `setParameter()` 和 `getResult()` 两个方法,分别代表设置 sql 问号占位符参数和获取列查询结果。
#### 16、MyBatis 映射文件中,如果 A 标签通过 include 引用了 B 标签的内容,请问,B 标签能否定义在 A 标签的后面,还是说必须定义在 A 标签的前面?
@@ -268,7 +270,7 @@ public V get(Object key) {
注:我出的
-答:MyBatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中,``标签会被解析为 `ParameterMap` 对象,其每个子元素会被解析为 ParameterMapping 对象。``标签会被解析为 `ResultMap` 对象,其每个子元素会被解析为 `ResultMapping` 对象。每一个`、、、`标签均会被解析为 `MappedStatement` 对象,标签内的 sql 会被解析为 BoundSql 对象。
+答:MyBatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中, `` 标签会被解析为 `ParameterMap` 对象,其每个子元素会被解析为 ParameterMapping 对象。 `` 标签会被解析为 `ResultMap` 对象,其每个子元素会被解析为 `ResultMapping` 对象。每一个 `、、、` 标签均会被解析为 `MappedStatement` 对象,标签内的 sql 会被解析为 BoundSql 对象。
#### 18、为什么说 MyBatis 是半自动 ORM 映射工具?它与全自动的区别在哪里?
diff --git a/docs/system-design/framework/netty.md b/docs/system-design/framework/netty.md
new file mode 100644
index 00000000000..75f3efc3afb
--- /dev/null
+++ b/docs/system-design/framework/netty.md
@@ -0,0 +1,7 @@
+# Netty 知识点&面试题总结
+
+这部分内容为我的星球专属,已经整理到了[《Java面试进阶指北 打造个人的技术竞争力》](https://www.yuque.com/docs/share/f37fc804-bfe6-4b0d-b373-9c462188fec7?# )中。
+
+欢迎加入我的星球,[一个纯 Java 面试交流圈子 !Ready!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=100015911&idx=1&sn=2e8a0f5acb749ecbcbb417aa8a4e18cc&chksm=4ea1b0ec79d639fae37df1b86f196e8ce397accfd1dd2004bcadb66b4df5f582d90ae0d62448#rd) (点击链接了解星球详细信息,还有专属优惠款可以领取)。
+
+
\ No newline at end of file
diff --git "a/docs/system-design/framework/spring/SpringBoot+Spring\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md" "b/docs/system-design/framework/spring/Spring&SpringBoot\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md"
similarity index 90%
rename from "docs/system-design/framework/spring/SpringBoot+Spring\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md"
rename to "docs/system-design/framework/spring/Spring&SpringBoot\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md"
index 2c7e09c7de5..ad5f0e8ed7b 100644
--- "a/docs/system-design/framework/spring/SpringBoot+Spring\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md"
+++ "b/docs/system-design/framework/spring/Spring&SpringBoot\345\270\270\347\224\250\346\263\250\350\247\243\346\200\273\347\273\223.md"
@@ -1,52 +1,6 @@
-### 文章目录
-
-
-- [文章目录](#%e6%96%87%e7%ab%a0%e7%9b%ae%e5%bd%95)
-- [0.前言](#0%e5%89%8d%e8%a8%80)
-- [1. `@SpringBootApplication`](#1-springbootapplication)
-- [2. Spring Bean 相关](#2-spring-bean-%e7%9b%b8%e5%85%b3)
- - [2.1. `@Autowired`](#21-autowired)
- - [2.2. `@Component`,`@Repository`,`@Service`, `@Controller`](#22-componentrepositoryservice-controller)
- - [2.3. `@RestController`](#23-restcontroller)
- - [2.4. `@Scope`](#24-scope)
- - [2.5. `@Configuration`](#25-configuration)
-- [3. 处理常见的 HTTP 请求类型](#3-%e5%a4%84%e7%90%86%e5%b8%b8%e8%a7%81%e7%9a%84-http-%e8%af%b7%e6%b1%82%e7%b1%bb%e5%9e%8b)
- - [3.1. GET 请求](#31-get-%e8%af%b7%e6%b1%82)
- - [3.2. POST 请求](#32-post-%e8%af%b7%e6%b1%82)
- - [3.3. PUT 请求](#33-put-%e8%af%b7%e6%b1%82)
- - [3.4. **DELETE 请求**](#34-delete-%e8%af%b7%e6%b1%82)
- - [3.5. **PATCH 请求**](#35-patch-%e8%af%b7%e6%b1%82)
-- [4. 前后端传值](#4-%e5%89%8d%e5%90%8e%e7%ab%af%e4%bc%a0%e5%80%bc)
- - [4.1. `@PathVariable` 和 `@RequestParam`](#41-pathvariable-%e5%92%8c-requestparam)
- - [4.2. `@RequestBody`](#42-requestbody)
-- [5. 读取配置信息](#5-%e8%af%bb%e5%8f%96%e9%85%8d%e7%bd%ae%e4%bf%a1%e6%81%af)
- - [5.1. `@value`(常用)](#51-value%e5%b8%b8%e7%94%a8)
- - [5.2. `@ConfigurationProperties`(常用)](#52-configurationproperties%e5%b8%b8%e7%94%a8)
- - [5.3. `PropertySource`(不常用)](#53-propertysource%e4%b8%8d%e5%b8%b8%e7%94%a8)
-- [6. 参数校验](#6-%e5%8f%82%e6%95%b0%e6%a0%a1%e9%aa%8c)
- - [6.1. 一些常用的字段验证的注解](#61-%e4%b8%80%e4%ba%9b%e5%b8%b8%e7%94%a8%e7%9a%84%e5%ad%97%e6%ae%b5%e9%aa%8c%e8%af%81%e7%9a%84%e6%b3%a8%e8%a7%a3)
- - [6.2. 验证请求体(RequestBody)](#62-%e9%aa%8c%e8%af%81%e8%af%b7%e6%b1%82%e4%bd%93requestbody)
- - [6.3. 验证请求参数(Path Variables 和 Request Parameters)](#63-%e9%aa%8c%e8%af%81%e8%af%b7%e6%b1%82%e5%8f%82%e6%95%b0path-variables-%e5%92%8c-request-parameters)
-- [7. 全局处理 Controller 层异常](#7-%e5%85%a8%e5%b1%80%e5%a4%84%e7%90%86-controller-%e5%b1%82%e5%bc%82%e5%b8%b8)
-- [8. JPA 相关](#8-jpa-%e7%9b%b8%e5%85%b3)
- - [8.1. 创建表](#81-%e5%88%9b%e5%bb%ba%e8%a1%a8)
- - [8.2. 创建主键](#82-%e5%88%9b%e5%bb%ba%e4%b8%bb%e9%94%ae)
- - [8.3. 设置字段类型](#83-%e8%ae%be%e7%bd%ae%e5%ad%97%e6%ae%b5%e7%b1%bb%e5%9e%8b)
- - [8.4. 指定不持久化特定字段](#84-%e6%8c%87%e5%ae%9a%e4%b8%8d%e6%8c%81%e4%b9%85%e5%8c%96%e7%89%b9%e5%ae%9a%e5%ad%97%e6%ae%b5)
- - [8.5. 声明大字段](#85-%e5%a3%b0%e6%98%8e%e5%a4%a7%e5%ad%97%e6%ae%b5)
- - [8.6. 创建枚举类型的字段](#86-%e5%88%9b%e5%bb%ba%e6%9e%9a%e4%b8%be%e7%b1%bb%e5%9e%8b%e7%9a%84%e5%ad%97%e6%ae%b5)
- - [8.7. 增加审计功能](#87-%e5%a2%9e%e5%8a%a0%e5%ae%a1%e8%ae%a1%e5%8a%9f%e8%83%bd)
- - [8.8. 删除/修改数据](#88-%e5%88%a0%e9%99%a4%e4%bf%ae%e6%94%b9%e6%95%b0%e6%8d%ae)
- - [8.9. 关联关系](#89-%e5%85%b3%e8%81%94%e5%85%b3%e7%b3%bb)
-- [9. 事务 `@Transactional`](#9-%e4%ba%8b%e5%8a%a1-transactional)
-- [10. json 数据处理](#10-json-%e6%95%b0%e6%8d%ae%e5%a4%84%e7%90%86)
- - [10.1. 过滤 json 数据](#101-%e8%bf%87%e6%bb%a4-json-%e6%95%b0%e6%8d%ae)
- - [10.2. 格式化 json 数据](#102-%e6%a0%bc%e5%bc%8f%e5%8c%96-json-%e6%95%b0%e6%8d%ae)
- - [10.3. 扁平化对象](#103-%e6%89%81%e5%b9%b3%e5%8c%96%e5%af%b9%e8%b1%a1)
-- [11. 测试相关](#11-%e6%b5%8b%e8%af%95%e7%9b%b8%e5%85%b3)
-
-
+# Spring/Spring Boot 常用注解总结!安排!
+
### 0.前言
_大家好,我是 Guide 哥!这是我的 221 篇优质原创文章。如需转载,请在文首注明地址,蟹蟹!_
diff --git a/docs/system-design/framework/spring/Spring.md b/docs/system-design/framework/spring/Spring.md
deleted file mode 100644
index 82fe4ef759c..00000000000
--- a/docs/system-design/framework/spring/Spring.md
+++ /dev/null
@@ -1,80 +0,0 @@
-
-
-## Spring相关教程/资料
-
-### 官网相关
-
-- [Spring官网](https://spring.io/)、[Spring系列主要项目](https://spring.io/projects)、[Spring官网指南](https://spring.io/guides)、[官方文档](https://spring.io/docs/reference)
-- [spring-framework-reference](https://docs.spring.io/spring/docs/5.0.14.RELEASE/spring-framework-reference/index.html)
-- [Spring Framework 4.3.17.RELEASE API](https://docs.spring.io/spring/docs/4.3.17.RELEASE/javadoc-api/)
-
-## 系统学习教程
-
-### 文档
-
-- [极客学院Spring Wiki](http://wiki.jikexueyuan.com/project/spring/transaction-management.html)
-- [Spring W3Cschool教程 ](https://www.w3cschool.cn/wkspring/f6pk1ic8.html)
-
-### 视频
-
-- [网易云课堂——58集精通java教程Spring框架开发](https://study.163.com/course/courseMain.htm?courseId=1004475015#/courseDetail?tab=1&35)
-- [慕课网相关视频](https://www.imooc.com/)
-
-- **黑马视频和尚硅谷视频(非常推荐):** 微信公众号:“**JavaGuide**”后台回复关键字 “**1**” 免费领取。
-
-
-## 面试必备知识点
-
-### SpringAOP,IOC实现原理
-
-AOP实现原理、动态代理和静态代理、Spring IOC的初始化过程、IOC原理、自己实现怎么实现一个IOC容器?这些东西都是经常会被问到的。
-
-推荐阅读:
-
-- [自己动手实现的 Spring IOC 和 AOP - 上篇](http://www.coolblog.xyz/2018/01/18/自己动手实现的-Spring-IOC-和-AOP-上篇/)
-
-- [自己动手实现的 Spring IOC 和 AOP - 下篇](http://www.coolblog.xyz/2018/01/18/自己动手实现的-Spring-IOC-和-AOP-下篇/)
-
-### AOP
-
-AOP思想的实现一般都是基于 **代理模式** ,在JAVA中一般采用JDK动态代理模式,但是我们都知道,**JDK动态代理模式只能代理接口而不能代理类**。因此,Spring AOP 会这样子来进行切换,因为Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理。
-
-- 如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
-- 如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类——不过这个选择过程对开发者完全透明、开发者也无需关心。
-
-推荐阅读:
-
-- [静态代理、JDK动态代理、CGLIB动态代理讲解](https://www.cnblogs.com/puyangsky/p/6218925.html) :我们知道AOP思想的实现一般都是基于 **代理模式** ,所以在看下面的文章之前建议先了解一下静态代理以及JDK动态代理、CGLIB动态代理的实现方式。
-- [Spring AOP 入门](https://juejin.im/post/5aa7818af265da23844040c6) :带你入门的一篇文章。这篇文章主要介绍了AOP中的基本概念:5种类型的通知(Before,After,After-returning,After-throwing,Around);Spring中对AOP的支持:AOP思想的实现一般都是基于代理模式,在Java中一般采用JDK动态代理模式,Spring AOP 同时支持 CGLIB、ASPECTJ、JDK动态代理,
-- [Spring AOP 基于AspectJ注解如何实现AOP](https://juejin.im/post/5a55af9e518825734d14813f) : **AspectJ是一个AOP框架,它能够对java代码进行AOP编译(一般在编译期进行),让java代码具有AspectJ的AOP功能(当然需要特殊的编译器)**,可以这样说AspectJ是目前实现AOP框架中最成熟,功能最丰富的语言,更幸运的是,AspectJ与java程序完全兼容,几乎是无缝关联,因此对于有java编程基础的工程师,上手和使用都非常容易。Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ(静态织入)最根本的区别。**Spring 只是使用了与 AspectJ 5 一样的注解,但仍然没有使用 AspectJ 的编译器,底层依是动态代理技术的实现,因此并不依赖于 AspectJ 的编译器**。 Spring AOP虽然是使用了那一套注解,其实实现AOP的底层是使用了动态代理(JDK或者CGLib)来动态植入。至于AspectJ的静态植入,不是本文重点,所以只提一提。
-- [探秘Spring AOP(慕课网视频,很不错)](https://www.imooc.com/learn/869):慕课网视频,讲解的很不错,详细且深入
-- [spring源码剖析(六)AOP实现原理剖析](https://blog.csdn.net/fighterandknight/article/details/51209822) :通过源码分析Spring AOP的原理
-
-### IOC
-
-- [[Spring框架]Spring IOC的原理及详解。](https://www.cnblogs.com/wang-meng/p/5597490.html)
-- [Spring IOC核心源码学习](https://yikun.github.io/2015/05/29/Spring-IOC核心源码学习/) :比较简短,推荐阅读。
-- [Spring IOC 容器源码分析](https://javadoop.com/post/spring-ioc) :强烈推荐,内容详尽,而且便于阅读。
-- [Bean初始化过程](https://www.qzztf.com/2019/08/21/Bean%E5%88%9D%E5%A7%8B%E5%8C%96/#Bean-%E5%AE%9E%E4%BE%8B%E5%8C%96)
-
-
-## Spring事务管理
-
-- [可能是最漂亮的Spring事务管理详解](https://juejin.im/post/5b00c52ef265da0b95276091)
-- [Spring编程式和声明式事务实例讲解](https://juejin.im/post/5b010f27518825426539ba38)
-
-### Spring单例与线程安全
-
-- [Spring框架中的单例模式(源码解读)](https://www.cnblogs.com/chengxuyuanzhilu/p/6404991.html):单例模式是一种常用的软件设计模式。通过单例模式可以保证系统中一个类只有一个实例。spring依赖注入时,使用了 多重判断加锁 的单例模式。
-
-### Spring源码阅读
-
-阅读源码不仅可以加深我们对Spring设计思想的理解,提高自己的编码水平,还可以让自己在面试中如鱼得水。下面的是Github上的一个开源的Spring源码阅读,大家有时间可以看一下,当然你如果有时间也可以自己慢慢研究源码。
-
- - [spring-core](https://github.com/seaswalker/Spring/blob/master/note/Spring.md)
-- [spring-aop](https://github.com/seaswalker/Spring/blob/master/note/spring-aop.md)
-- [spring-context](https://github.com/seaswalker/Spring/blob/master/note/spring-context.md)
-- [spring-task](https://github.com/seaswalker/Spring/blob/master/note/spring-task.md)
-- [spring-transaction](https://github.com/seaswalker/Spring/blob/master/note/spring-transaction.md)
-- [spring-mvc](https://github.com/seaswalker/Spring/blob/master/note/spring-mvc.md)
-- [guava-cache](https://github.com/seaswalker/Spring/blob/master/note/guava-cache.md)
diff --git "a/docs/system-design/framework/spring/SpringBoot\350\207\252\345\212\250\350\243\205\351\205\215\345\216\237\347\220\206.md" "b/docs/system-design/framework/spring/SpringBoot\350\207\252\345\212\250\350\243\205\351\205\215\345\216\237\347\220\206.md"
new file mode 100644
index 00000000000..e8a8e58c53c
--- /dev/null
+++ "b/docs/system-design/framework/spring/SpringBoot\350\207\252\345\212\250\350\243\205\351\205\215\345\216\237\347\220\206.md"
@@ -0,0 +1,320 @@
+
+# Spring Boot 自动装配原理
+
+> 本文已经收录进 Github 95k+ Star 的Java项目JavaGuide 。JavaGuide项目地址 : https://github.com/Snailclimb/JavaGuide 。
+>
+> 作者:[Miki-byte-1024](https://github.com/Miki-byte-1024) & [Snailclimb](https://github.com/Snailclimb)
+
+每次问到 Spring Boot, 面试官非常喜欢问这个问题:“讲述一下 SpringBoot 自动装配原理?”。
+
+我觉得我们可以从以下几个方面回答:
+
+1. 什么是 SpringBoot 自动装配?
+2. SpringBoot 是如何实现自动装配的?如何实现按需加载?
+3. 如何实现一个 Starter?
+
+篇幅问题,这篇文章并没有深入,小伙伴们也可以直接使用 debug 的方式去看看 SpringBoot 自动装配部分的源代码。
+
+## 前言
+
+使用过 Spring 的小伙伴,一定有被 XML 配置统治的恐惧。即使 Spring 后面引入了基于注解的配置,我们在开启某些 Spring 特性或者引入第三方依赖的时候,还是需要用 XML 或 Java 进行显式配置。
+
+举个例子。没有 Spring Boot 的时候,我们写一个 RestFul Web 服务,还首先需要进行如下配置。
+
+```java
+@Configuration
+public class RESTConfiguration
+{
+ @Bean
+ public View jsonTemplate() {
+ MappingJackson2JsonView view = new MappingJackson2JsonView();
+ view.setPrettyPrint(true);
+ return view;
+ }
+
+ @Bean
+ public ViewResolver viewResolver() {
+ return new BeanNameViewResolver();
+ }
+}
+```
+
+`spring-servlet.xml`
+
+```xml
+
+
+
+
+
+
+
+
+
+
+```
+
+但是,Spring Boot 项目,我们只需要添加相关依赖,无需配置,通过启动下面的 `main` 方法即可。
+
+```java
+@SpringBootApplication
+public class DemoApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(DemoApplication.class, args);
+ }
+}
+```
+
+并且,我们通过 Spring Boot 的全局配置文件 `application.properties`或`application.yml`即可对项目进行设置比如更换端口号,配置 JPA 属性等等。
+
+**为什么 Spring Boot 使用起来这么酸爽呢?** 这得益于其自动装配。**自动装配可以说是 Spring Boot 的核心,那究竟什么是自动装配呢?**
+
+## 什么是 SpringBoot 自动装配?
+
+我们现在提到自动装配的时候,一般会和 Spring Boot 联系在一起。但是,实际上 Spring Framework 早就实现了这个功能。Spring Boot 只是在其基础上,通过 SPI 的方式,做了进一步优化。
+
+> SpringBoot 定义了一套接口规范,这套规范规定:SpringBoot 在启动时会扫描外部引用 jar 包中的`META-INF/spring.factories`文件,将文件中配置的类型信息加载到 Spring 容器(此处涉及到 JVM 类加载机制与 Spring 的容器知识),并执行类中定义的各种操作。对于外部 jar 来说,只需要按照 SpringBoot 定义的标准,就能将自己的功能装置进 SpringBoot。
+
+没有 Spring Boot 的情况下,如果我们需要引入第三方依赖,需要手动配置,非常麻烦。但是,Spring Boot 中,我们直接引入一个 starter 即可。比如你想要在项目中使用 redis 的话,直接在项目中引入对应的 starter 即可。
+
+```xml
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+```
+
+引入 starter 之后,我们通过少量注解和一些简单的配置就能使用第三方组件提供的功能了。
+
+在我看来,自动装配可以简单理解为:**通过注解或者一些简单的配置就能在 Spring Boot 的帮助下实现某块功能。**
+
+## SpringBoot 是如何实现自动装配的?
+
+我们先看一下 SpringBoot 的核心注解 `SpringBootApplication` 。
+
+```java
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+<1.>@SpringBootConfiguration
+<2.>@ComponentScan
+<3.>@EnableAutoConfiguration
+public @interface SpringBootApplication {
+
+}
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Configuration //实际上它也是一个配置类
+public @interface SpringBootConfiguration {
+}
+```
+
+大概可以把 `@SpringBootApplication`看作是 `@Configuration`、`@EnableAutoConfiguration`、`@ComponentScan` 注解的集合。根据 SpringBoot 官网,这三个注解的作用分别是:
+
+- `@EnableAutoConfiguration`:启用 SpringBoot 的自动配置机制
+- `@Configuration`:允许在上下文中注册额外的 bean 或导入其他配置类
+- `@ComponentScan`: 扫描被`@Component` (`@Service`,`@Controller`)注解的 bean,注解默认会扫描启动类所在的包下所有的类 ,可以自定义不扫描某些 bean。如下图所示,容器中将排除`TypeExcludeFilter`和`AutoConfigurationExcludeFilter`。
+
+ 
+
+`@EnableAutoConfiguration` 是实现自动装配的重要注解,我们以这个注解入手。
+
+### @EnableAutoConfiguration:实现自动装配的核心注解
+
+`EnableAutoConfiguration` 只是一个简单地注解,自动装配核心功能的实现实际是通过 `AutoConfigurationImportSelector`类。
+
+```java
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@AutoConfigurationPackage //作用:将main包下的所有组件注册到容器中
+@Import({AutoConfigurationImportSelector.class}) //加载自动装配类 xxxAutoconfiguration
+public @interface EnableAutoConfiguration {
+ String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
+
+ Class>[] exclude() default {};
+
+ String[] excludeName() default {};
+}
+```
+
+我们现在重点分析下`AutoConfigurationImportSelector` 类到底做了什么?
+
+### AutoConfigurationImportSelector:加载自动装配类
+
+`AutoConfigurationImportSelector`类的继承体系如下:
+
+```java
+public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
+
+}
+
+public interface DeferredImportSelector extends ImportSelector {
+
+}
+
+public interface ImportSelector {
+ String[] selectImports(AnnotationMetadata var1);
+}
+```
+
+可以看出,`AutoConfigurationImportSelector` 类实现了 `ImportSelector`接口,也就实现了这个接口中的 `selectImports`方法,该方法主要用于**获取所有符合条件的类的全限定类名,这些类需要被加载到 IoC 容器中**。
+
+```java
+private static final String[] NO_IMPORTS = new String[0];
+
+public String[] selectImports(AnnotationMetadata annotationMetadata) {
+ // <1>.判断自动装配开关是否打开
+ if (!this.isEnabled(annotationMetadata)) {
+ return NO_IMPORTS;
+ } else {
+ //<2>.获取所有需要装配的bean
+ AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
+ AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
+ return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
+ }
+ }
+```
+
+这里我们需要重点关注一下`getAutoConfigurationEntry()`方法,这个方法主要负责加载自动配置类的。
+
+该方法调用链如下:
+
+
+
+现在我们结合`getAutoConfigurationEntry()`的源码来详细分析一下:
+
+```java
+private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
+
+AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
+ //<1>.
+ if (!this.isEnabled(annotationMetadata)) {
+ return EMPTY_ENTRY;
+ } else {
+ //<2>.
+ AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
+ //<3>.
+ List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
+ //<4>.
+ configurations = this.removeDuplicates(configurations);
+ Set exclusions = this.getExclusions(annotationMetadata, attributes);
+ this.checkExcludedClasses(configurations, exclusions);
+ configurations.removeAll(exclusions);
+ configurations = this.filter(configurations, autoConfigurationMetadata);
+ this.fireAutoConfigurationImportEvents(configurations, exclusions);
+ return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
+ }
+ }
+```
+
+**第 1 步**:
+
+判断自动装配开关是否打开。默认`spring.boot.enableautoconfiguration=true`,可在 `application.properties` 或 `application.yml` 中设置
+
+
+
+**第 2 步** :
+
+用于获取`EnableAutoConfiguration`注解中的 `exclude` 和 `excludeName`。
+
+
+
+**第 3 步**
+
+获取需要自动装配的所有配置类,读取`META-INF/spring.factories`
+
+```
+spring-boot/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+```
+
+
+
+从下图可以看到这个文件的配置内容都被我们读取到了。`XXXAutoConfiguration`的作用就是按需加载组件。
+
+
+
+不光是这个依赖下的`META-INF/spring.factories`被读取到,所有 Spring Boot Starter 下的`META-INF/spring.factories`都会被读取到。
+
+所以,你可以清楚滴看到, druid 数据库连接池的 Spring Boot Starter 就创建了`META-INF/spring.factories`文件。
+
+如果,我们自己要创建一个 Spring Boot Starter,这一步是必不可少的。
+
+
+
+**第 4 步** :
+
+到这里可能面试官会问你:“`spring.factories`中这么多配置,每次启动都要全部加载么?”。
+
+很明显,这是不现实的。我们 debug 到后面你会发现,`configurations` 的值变小了。
+
+
+
+因为,这一步有经历了一遍筛选,`@ConditionalOnXXX` 中的所有条件都满足,该类才会生效。
+
+```java
+@Configuration
+// 检查相关的类:RabbitTemplate 和 Channel是否存在
+// 存在才会加载
+@ConditionalOnClass({ RabbitTemplate.class, Channel.class })
+@EnableConfigurationProperties(RabbitProperties.class)
+@Import(RabbitAnnotationDrivenConfiguration.class)
+public class RabbitAutoConfiguration {
+}
+```
+
+有兴趣的童鞋可以详细了解下 Spring Boot 提供的条件注解
+
+- `@ConditionalOnBean`:当容器里有指定 Bean 的条件下
+- `@ConditionalOnMissingBean`:当容器里没有指定 Bean 的情况下
+- `@ConditionalOnSingleCandidate`:当指定 Bean 在容器中只有一个,或者虽然有多个但是指定首选 Bean
+- `@ConditionalOnClass`:当类路径下有指定类的条件下
+- `@ConditionalOnMissingClass`:当类路径下没有指定类的条件下
+- `@ConditionalOnProperty`:指定的属性是否有指定的值
+- `@ConditionalOnResource`:类路径是否有指定的值
+- `@ConditionalOnExpression`:基于 SpEL 表达式作为判断条件
+- `@ConditionalOnJava`:基于 Java 版本作为判断条件
+- `@ConditionalOnJndi`:在 JNDI 存在的条件下差在指定的位置
+- `@ConditionalOnNotWebApplication`:当前项目不是 Web 项目的条件下
+- `@ConditionalOnWebApplication`:当前项目是 Web 项 目的条件下
+
+## 如何实现一个 Starter
+
+光说不练假把式,现在就来撸一个 starter,实现自定义线程池
+
+第一步,创建`threadpool-spring-boot-starter`工程
+
+
+
+第二步,引入 Spring Boot 相关依赖
+
+
+
+第三步,创建`ThreadPoolAutoConfiguration`
+
+
+
+第四步,在`threadpool-spring-boot-starter`工程的 resources 包下创建`META-INF/spring.factories`文件
+
+
+
+最后新建工程引入`threadpool-spring-boot-starter`
+
+
+
+测试通过!!!
+
+
+
+## 总结
+
+Spring Boot 通过`@EnableAutoConfiguration`开启自动装配,通过 SpringFactoriesLoader 最终加载`META-INF/spring.factories`中的自动配置类实现自动装配,自动配置类其实就是通过`@Conditional`按需加载的配置类,想要其生效必须引入`spring-boot-starter-xxx`包实现起步依赖
diff --git "a/docs/system-design/framework/spring/Spring\344\272\213\345\212\241\346\200\273\347\273\223.md" "b/docs/system-design/framework/spring/Spring\344\272\213\345\212\241\346\200\273\347\273\223.md"
index ef812265888..dfe98c1eeca 100644
--- "a/docs/system-design/framework/spring/Spring\344\272\213\345\212\241\346\200\273\347\273\223.md"
+++ "b/docs/system-design/framework/spring/Spring\344\272\213\345\212\241\346\200\273\347\273\223.md"
@@ -1,3 +1,6 @@
+
+# Spring 事务总结
+
大家好,我是 Guide 哥,前段时间答应读者的 **Spring 事务**分析总结终于来了。这部分内容比较重要,不论是对于工作还是面试,但是网上比较好的参考资料比较少。
如果本文有任何不对或者需要完善的地方,请帮忙指出!Guide 哥感激不尽!
diff --git "a/docs/system-design/framework/spring/Spring\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md" "b/docs/system-design/framework/spring/Spring\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md"
index 986364fd7d7..56ceeb19fd9 100644
--- "a/docs/system-design/framework/spring/Spring\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md"
+++ "b/docs/system-design/framework/spring/Spring\345\270\270\350\247\201\351\227\256\351\242\230\346\200\273\347\273\223.md"
@@ -1,3 +1,5 @@
+# Spring常见问题总结
+
这篇文章主要是想通过一些问题,加深大家对于 Spring 的理解,所以不会涉及太多的代码!
下面的很多问题我自己在使用 Spring 的过程中也并没有注意,自己也是临时查阅了很多资料和书籍补上的。网上也有一些很多关于 Spring 常见问题/面试题整理的文章,我感觉大部分都是互相 copy,而且很多问题也不是很好,有些回答也存在问题。所以,自己花了一周的业余时间整理了一下,希望对大家有帮助。
diff --git a/docs/system-design/framework/spring/Spring-Design-Patterns.md "b/docs/system-design/framework/spring/Spring\350\256\276\350\256\241\346\250\241\345\274\217\346\200\273\347\273\223.md"
similarity index 94%
rename from docs/system-design/framework/spring/Spring-Design-Patterns.md
rename to "docs/system-design/framework/spring/Spring\350\256\276\350\256\241\346\250\241\345\274\217\346\200\273\347\273\223.md"
index c5d56ff6d37..d883c194ce9 100644
--- a/docs/system-design/framework/spring/Spring-Design-Patterns.md
+++ "b/docs/system-design/framework/spring/Spring\350\256\276\350\256\241\346\250\241\345\274\217\346\200\273\347\273\223.md"
@@ -1,28 +1,4 @@
-点击关注[公众号](#公众号)及时获取笔主最新更新文章,并可免费领取本文档配套的《Java面试突击》以及Java工程师必备学习资源。
-
-
-
-- [控制反转(IoC)和依赖注入(DI)](#控制反转ioc和依赖注入di)
-- [工厂设计模式](#工厂设计模式)
-- [单例设计模式](#单例设计模式)
-- [代理设计模式](#代理设计模式)
- - [代理模式在 AOP 中的应用](#代理模式在-aop-中的应用)
- - [Spring AOP 和 AspectJ AOP 有什么区别?](#spring-aop-和-aspectj-aop-有什么区别)
-- [模板方法](#模板方法)
-- [观察者模式](#观察者模式)
- - [Spring 事件驱动模型中的三种角色](#spring-事件驱动模型中的三种角色)
- - [事件角色](#事件角色)
- - [事件监听者角色](#事件监听者角色)
- - [事件发布者角色](#事件发布者角色)
- - [Spring 的事件流程总结](#spring-的事件流程总结)
-- [适配器模式](#适配器模式)
- - [spring AOP中的适配器模式](#spring-aop中的适配器模式)
- - [spring MVC中的适配器模式](#spring-mvc中的适配器模式)
-- [装饰者模式](#装饰者模式)
-- [总结](#总结)
-- [参考](#参考)
-
-
+# Spring设计模式总结
JDK 中用到了那些设计模式?Spring 中用到了那些设计模式?这两个问题,在面试中比较常见。我在网上搜索了一下关于 Spring 中设计模式的讲解几乎都是千篇一律,而且大部分都年代久远。所以,花了几天时间自己总结了一下,由于我的个人能力有限,文中如有任何错误各位都可以指出。另外,文章篇幅有限,对于设计模式以及一些源码的解读我只是一笔带过,这篇文章的主要目的是回顾一下 Spring 中的设计模式。
diff --git a/docs/system-design/micro-service/spring-cloud.md b/docs/system-design/framework/springcloud/springcloud-intro.md
similarity index 99%
rename from docs/system-design/micro-service/spring-cloud.md
rename to docs/system-design/framework/springcloud/springcloud-intro.md
index 34c3680fcf3..37a10dad8c1 100644
--- a/docs/system-design/micro-service/spring-cloud.md
+++ b/docs/system-design/framework/springcloud/springcloud-intro.md
@@ -1,3 +1,5 @@
+# Spring Cloud 入门
+
> 本文基于 Spring Cloud Netflix 。Spring Cloud Alibaba 也是非常不错的选择哦!
>
> 授权转载自:https://juejin.im/post/5de2553e5188256e885f4fa3
@@ -8,7 +10,7 @@

-## 什么是Spring cloud
+## 什么是Spring Cloud
> 构建分布式系统不需要复杂和容易出错。Spring Cloud 为最常见的分布式系统模式提供了一种简单且易于接受的编程模型,帮助开发人员构建有弹性的、可靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上,使得开发者很容易入手并快速应用于生产中。
diff --git a/docs/system-design/high-availability/images/cap-base/partition-tolerance.drawio b/docs/system-design/high-availability/images/cap-base/partition-tolerance.drawio
deleted file mode 100644
index 34112251a8d..00000000000
--- a/docs/system-design/high-availability/images/cap-base/partition-tolerance.drawio
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/system-design/high-availability/images/cap-base/partition-tolerance.png b/docs/system-design/high-availability/images/cap-base/partition-tolerance.png
deleted file mode 100644
index d523025fdc6..00000000000
Binary files a/docs/system-design/high-availability/images/cap-base/partition-tolerance.png and /dev/null differ
diff --git a/docs/system-design/high-availability/limit-request.md b/docs/system-design/high-availability/limit-request.md
deleted file mode 100644
index 81a687dbd86..00000000000
--- a/docs/system-design/high-availability/limit-request.md
+++ /dev/null
@@ -1,41 +0,0 @@
-### 限流的算法有哪些?
-
-简单介绍 4 种非常好理解并且容易实现的限流算法!
-
-下图的图片不是 Guide 哥自己画的哦!图片来源于 InfoQ 的一篇文章[《分布式服务限流实战,已经为你排好坑了》](https://www.infoq.cn/article/Qg2tX8fyw5Vt-f3HH673)。
-
-#### 固定窗口计数器算法
-
-该算法规定我们单位时间处理的请求数量。比如我们规定我们的一个接口一分钟只能访问10次的话。使用固定窗口计数器算法的话可以这样实现:给定一个变量counter来记录处理的请求数量,当1分钟之内处理一个请求之后counter+1,1分钟之内的如果counter=10的话,后续的请求就会被全部拒绝。等到 1分钟结束后,将counter回归成0,重新开始计数(ps:只要过了一个周期就将counter回归成0)。
-
-这种限流算法无法保证限流速率,因而无法保证突然激增的流量。比如我们限制一个接口一分钟只能访问10次的话,前半分钟一个请求没有接收,后半分钟接收了10个请求。
-
-
-
-#### 滑动窗口计数器算法
-
-该算法算的上是固定窗口计数器算法的升级版。滑动窗口计数器算法相比于固定窗口计数器算法的优化在于:它把时间以一定比例分片。例如我们的接口限流每分钟处理60个请求,我们可以把 1 分钟分为60个窗口。每隔1秒移动一次,每个窗口一秒只能处理 不大于 60(请求数)/60(窗口数) 的请求, 如果当前窗口的请求计数总和超过了限制的数量的话就不再处理其他请求。
-
-很显然:当滑动窗口的格子划分的越多,滑动窗口的滚动就越平滑,限流的统计就会越精确。
-
-
-
-#### 漏桶算法
-
-我们可以把发请求的动作比作成注水到桶中,我们处理请求的过程可以比喻为 **漏桶漏水** 。我们往桶中以任意速率流入水,以一定速率流出水。当水超过桶容量则丢弃,因为桶容量是不变的,保证了整体的速率。
-
-如果想要实现这个算法的话也很简单,准备一个队列用来保存请求,然后我们定期从队列中拿请求来执行就好了。
-
-
-
-#### 令牌桶算法
-
-令牌桶算法也比较简单。和漏桶算法一样,我们的主角还是桶(这限流算法和桶过不去啊)。不过现在桶里装的是令牌了,请求在被处理之前需要拿到一个令牌,请求处理完毕之后将这个令牌丢弃(删除)。
-
-我们根据限流大小,按照一定的速率往桶里添加令牌即可!
-
-
-
-**漏桶算法 vs 令牌桶算法** :
-
-
diff --git a/docs/system-design/authority-certification/basis-of-authority-certification.md b/docs/system-design/security/basis-of-authority-certification.md
similarity index 99%
rename from docs/system-design/authority-certification/basis-of-authority-certification.md
rename to docs/system-design/security/basis-of-authority-certification.md
index 27e59e999b3..ce624842036 100644
--- a/docs/system-design/authority-certification/basis-of-authority-certification.md
+++ b/docs/system-design/security/basis-of-authority-certification.md
@@ -1,3 +1,5 @@
+# 认证授权基础
+
## 认证 (Authentication) 和授权 (Authorization)的区别是什么?
这是一个绝大多数人都会混淆的问题。首先先从读音上来认识这两个名词,很多人都会把它俩的读音搞混,所以我建议你先先去查一查这两个单词到底该怎么读,他们的具体含义是什么。
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/Session-Based-Authentication-flow.png b/docs/system-design/security/images/basis-of-authority-certification/Session-Based-Authentication-flow.png
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/Session-Based-Authentication-flow.png
rename to docs/system-design/security/images/basis-of-authority-certification/Session-Based-Authentication-flow.png
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/cookie-sessionId.png b/docs/system-design/security/images/basis-of-authority-certification/cookie-sessionId.png
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/cookie-sessionId.png
rename to docs/system-design/security/images/basis-of-authority-certification/cookie-sessionId.png
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/jwt.drawio b/docs/system-design/security/images/basis-of-authority-certification/jwt.drawio
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/jwt.drawio
rename to docs/system-design/security/images/basis-of-authority-certification/jwt.drawio
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/jwt.png b/docs/system-design/security/images/basis-of-authority-certification/jwt.png
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/jwt.png
rename to docs/system-design/security/images/basis-of-authority-certification/jwt.png
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/session-cookie.drawio b/docs/system-design/security/images/basis-of-authority-certification/session-cookie.drawio
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/session-cookie.drawio
rename to docs/system-design/security/images/basis-of-authority-certification/session-cookie.drawio
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/session-cookie.png b/docs/system-design/security/images/basis-of-authority-certification/session-cookie.png
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/session-cookie.png
rename to docs/system-design/security/images/basis-of-authority-certification/session-cookie.png
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/sso.drawio b/docs/system-design/security/images/basis-of-authority-certification/sso.drawio
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/sso.drawio
rename to docs/system-design/security/images/basis-of-authority-certification/sso.drawio
diff --git a/docs/system-design/authority-certification/images/basis-of-authority-certification/sso.png b/docs/system-design/security/images/basis-of-authority-certification/sso.png
similarity index 100%
rename from docs/system-design/authority-certification/images/basis-of-authority-certification/sso.png
rename to docs/system-design/security/images/basis-of-authority-certification/sso.png
diff --git "a/docs/system-design/authority-certification/images/basis-of-authority-certification/\345\276\256\344\277\241\346\224\257\344\273\230-fnglfdlgdfj.png" "b/docs/system-design/security/images/basis-of-authority-certification/\345\276\256\344\277\241\346\224\257\344\273\230-fnglfdlgdfj.png"
similarity index 100%
rename from "docs/system-design/authority-certification/images/basis-of-authority-certification/\345\276\256\344\277\241\346\224\257\344\273\230-fnglfdlgdfj.png"
rename to "docs/system-design/security/images/basis-of-authority-certification/\345\276\256\344\277\241\346\224\257\344\273\230-fnglfdlgdfj.png"
diff --git "a/docs/system-design/authority-certification/JWT\344\274\230\347\274\272\347\202\271\345\210\206\346\236\220\344\273\245\345\217\212\345\270\270\350\247\201\351\227\256\351\242\230\350\247\243\345\206\263\346\226\271\346\241\210.md" "b/docs/system-design/security/jwt\344\274\230\347\274\272\347\202\271\345\210\206\346\236\220\344\273\245\345\217\212\345\270\270\350\247\201\351\227\256\351\242\230\350\247\243\345\206\263\346\226\271\346\241\210.md"
similarity index 100%
rename from "docs/system-design/authority-certification/JWT\344\274\230\347\274\272\347\202\271\345\210\206\346\236\220\344\273\245\345\217\212\345\270\270\350\247\201\351\227\256\351\242\230\350\247\243\345\206\263\346\226\271\346\241\210.md"
rename to "docs/system-design/security/jwt\344\274\230\347\274\272\347\202\271\345\210\206\346\236\220\344\273\245\345\217\212\345\270\270\350\247\201\351\227\256\351\242\230\350\247\243\345\206\263\346\226\271\346\241\210.md"
diff --git a/docs/system-design/security/readme.md b/docs/system-design/security/readme.md
new file mode 100644
index 00000000000..7fb81f18cb7
--- /dev/null
+++ b/docs/system-design/security/readme.md
@@ -0,0 +1,7 @@
+**[《认证授权基础》](https://snailclimb.gitee.io/javaguide/#/docs/system-design/authority-certification/basis-of-authority-certification)** 这篇文章中我会介绍认证授权常见概念: **Authentication**,**Authorization** 以及 **Cookie**、**Session**、Token、**OAuth 2**、**SSO** 。如果你不清楚这些概念的话,建议好好阅读一下这篇文章。
+
+- **JWT** :JWT(JSON Web Token)是一种身份认证的方式,JWT 本质上就一段签名的 JSON 格式的数据。由于它是带有签名的,因此接收者便可以验证它的真实性。相关阅读:
+
+
+
+- **SSO(单点登录)** :**SSO(Single Sign On)** 即单点登录说的是用户登陆多个子系统的其中一个就有权访问与其相关的其他系统。举个例子我们在登陆了京东金融之后,我们同时也成功登陆京东的京东超市、京东家电等子系统。相关阅读:[**SSO 单点登录看这篇就够了!**](https://snailclimb.gitee.io/javaguide/#/docs/system-design/authority-certification/SSO单点登录看这一篇就够了)
\ No newline at end of file
diff --git "a/docs/system-design/authority-certification/SSO\345\215\225\347\202\271\347\231\273\345\275\225\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md" b/docs/system-design/security/sso-intro.md
similarity index 99%
rename from "docs/system-design/authority-certification/SSO\345\215\225\347\202\271\347\231\273\345\275\225\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md"
rename to docs/system-design/security/sso-intro.md
index 62d420d8119..65fea52e1fc 100644
--- "a/docs/system-design/authority-certification/SSO\345\215\225\347\202\271\347\231\273\345\275\225\347\234\213\350\277\231\344\270\200\347\257\207\345\260\261\345\244\237\344\272\206.md"
+++ b/docs/system-design/security/sso-intro.md
@@ -1,4 +1,4 @@
-
+# SSO 单点登录
> 本文授权转载自 : https://ken.io/note/sso-design-implement 作者:ken.io
>
diff --git "a/docs/system-design/security/\346\225\260\346\215\256\350\204\261\346\225\217.md" "b/docs/system-design/security/\346\225\260\346\215\256\350\204\261\346\225\217.md"
new file mode 100644
index 00000000000..58da1b305a3
--- /dev/null
+++ "b/docs/system-design/security/\346\225\260\346\215\256\350\204\261\346\225\217.md"
@@ -0,0 +1,3 @@
+# 数据脱敏
+
+数据脱敏说的就是我们根据特定的规则对敏感信息数据进行变形,比如我们把手机号、身份证号某些位数使用 * 来代替。
\ No newline at end of file
diff --git "a/docs/system-design/website-architecture/8 \345\274\240\345\233\276\350\257\273\346\207\202\345\244\247\345\236\213\347\275\221\347\253\231\346\212\200\346\234\257\346\236\266\346\236\204.md" "b/docs/system-design/website-architecture/8 \345\274\240\345\233\276\350\257\273\346\207\202\345\244\247\345\236\213\347\275\221\347\253\231\346\212\200\346\234\257\346\236\266\346\236\204.md"
deleted file mode 100644
index f975930f7ee..00000000000
--- "a/docs/system-design/website-architecture/8 \345\274\240\345\233\276\350\257\273\346\207\202\345\244\247\345\236\213\347\275\221\347\253\231\346\212\200\346\234\257\346\236\266\346\236\204.md"
+++ /dev/null
@@ -1,47 +0,0 @@
-> 本文是作者读 《大型网站技术架构》所做的思维导图,在这里分享给各位,公众号(JavaGuide)后台回复:“架构”。即可获得下面图片的源文件以及思维导图源文件!
-
-
-
-- [1. 大型网站架构演化](#1-大型网站架构演化)
-- [2. 大型架构模式](#2-大型架构模式)
-- [3. 大型网站核心架构要素](#3-大型网站核心架构要素)
-- [4. 瞬时响应:网站的高性能架构](#4-瞬时响应网站的高性能架构)
-- [5. 万无一失:网站的高可用架构](#5-万无一失网站的高可用架构)
-- [6. 永无止境:网站的伸缩性架构](#6-永无止境网站的伸缩性架构)
-- [7. 随机应变:网站的可扩展性架构](#7-随机应变网站的可扩展性架构)
-- [8. 固若金汤:网站的安全机构](#8-固若金汤网站的安全机构)
-
-
-
-
-### 1. 大型网站架构演化
-
-
-
-### 2. 大型架构模式
-
-
-
-### 3. 大型网站核心架构要素
-
-
-
-### 4. 瞬时响应:网站的高性能架构
-
-
-
-### 5. 万无一失:网站的高可用架构
-
-
-
-### 6. 永无止境:网站的伸缩性架构
-
-
-
-### 7. 随机应变:网站的可扩展性架构
-
-
-
-### 8. 固若金汤:网站的安全机构
-
-
diff --git "a/docs/system-design/website-architecture/\345\205\263\344\272\216\345\244\247\345\236\213\347\275\221\347\253\231\347\263\273\347\273\237\346\236\266\346\236\204\344\275\240\344\270\215\345\276\227\344\270\215\346\207\202\347\232\20410\344\270\252\351\227\256\351\242\230.md" "b/docs/system-design/website-architecture/\345\205\263\344\272\216\345\244\247\345\236\213\347\275\221\347\253\231\347\263\273\347\273\237\346\236\266\346\236\204\344\275\240\344\270\215\345\276\227\344\270\215\346\207\202\347\232\20410\344\270\252\351\227\256\351\242\230.md"
deleted file mode 100644
index 194cc52bc7b..00000000000
--- "a/docs/system-design/website-architecture/\345\205\263\344\272\216\345\244\247\345\236\213\347\275\221\347\253\231\347\263\273\347\273\237\346\236\266\346\236\204\344\275\240\344\270\215\345\276\227\344\270\215\346\207\202\347\232\20410\344\270\252\351\227\256\351\242\230.md"
+++ /dev/null
@@ -1,190 +0,0 @@
-下面这些问题都是一线大厂的真实面试问题,不论是对你面试还是说拓宽知识面都很有帮助。之前发过一篇[8 张图读懂大型网站技术架构](https://mp.weixin.qq.com/s?__biz=MzU4NDQ4MzU5OA==&mid=2247484416&idx=1&sn=6ced00d65491ef8fd33151bdfa8895c9&chksm=fd985261caefdb779412974a6a7207c93d0c2da5b28489afb74acd2fee28505daebbadb018ff&token=177958022&lang=zh_CN#rd) 可以作为不太了解大型网站系统技术架构朋友的入门文章。
-
-
-
-- [1. 你使用过哪些组件或者方法来提升网站性能,可用性以及并发量](#1-你使用过哪些组件或者方法来提升网站性能可用性以及并发量)
-- [2. 设计高可用系统的常用手段](#2-设计高可用系统的常用手段)
-- [3. 现代互联网应用系统通常具有哪些特点?](#3-现代互联网应用系统通常具有哪些特点)
-- [4. 谈谈你对微服务领域的了解和认识](#4-谈谈你对微服务领域的了解和认识)
-- [5. 谈谈你对 Dubbo 和 Spring Cloud 的认识\(两者关系\)](#5-谈谈你对-dubbo-和-spring-cloud-的认识两者关系)
-- [6. 性能测试了解吗?说说你知道的性能测试工具?](#6-性能测试了解吗说说你知道的性能测试工具)
-- [7. 对于一个单体应用系统,随着产品使用的用户越来越多,网站的流量会增加,最终单台服务器无法处理那么大的流量怎么办?](#7-对于一个单体应用系统随着产品使用的用户越来越多网站的流量会增加最终单台服务器无法处理那么大的流量怎么办)
-- [8. 大表优化的常见手段](#8-大表优化的常见手段)
-- [9. 在系统中使用消息队列能带来什么好处?](#9-在系统中使用消息队列能带来什么好处)
- - [1) 通过异步处理提高系统性能](#1-通过异步处理提高系统性能)
-- [2) 降低系统耦合性](#2-降低系统耦合性)
-- [10. 说说自己对 CAP 定理,BASE 理论的了解](#10-说说自己对-cap-定理base-理论的了解)
- - [CAP 定理](#cap-定理)
- - [BASE 理论](#base-理论)
-- [参考](#参考)
-
-
-
-
-### 1. 你使用过哪些组件或者方法来提升网站性能,可用性以及并发量
-
-1. **提高硬件能力、增加系统服务器**。(当服务器增加到某个程度的时候系统所能提供的并发访问量几乎不变,所以不能根本解决问题)
-2. **使用缓存**(本地缓存:本地可以使用JDK自带的 Map、Guava Cache.分布式缓存:Redis、Memcache.本地缓存不适用于提高系统并发量,一般是用在程序中。比如Spring是如何实现单例的呢?大家如果看过源码的话,应该知道,S把已经初始过的变量放在一个Map中,下次再要使用这个变量的时候,先判断Map中有没有,这也就是系统中常见的单例模式的实现。)
-3. **消息队列** (解耦+削峰+异步)
-4. **采用分布式开发** (不同的服务部署在不同的机器节点上,并且一个服务也可以部署在多台机器上,然后利用 Nginx 负载均衡访问。这样就解决了单点部署(All In)的缺点,大大提高的系统并发量)
-5. **数据库分库(读写分离)、分表(水平分表、垂直分表)**
-6. **采用集群** (多台机器提供相同的服务)
-7. **CDN 加速** (将一些静态资源比如图片、视频等等缓存到离用户最近的网络节点)
-8. **浏览器缓存**
-9. **使用合适的连接池**(数据库连接池、线程池等等)
-10. **适当使用多线程进行开发。**
-
-
-### 2. 设计高可用系统的常用手段
-
-1. **降级:** 服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。根据服务方式:可以拒接服务,可以延迟服务,也有时候可以随机服务。根据服务范围:可以砍掉某个功能,也可以砍掉某些模块。总之服务降级需要根据不同的业务需求采用不同的降级策略。主要的目的就是服务虽然有损但是总比没有好;
-2. **限流:** 防止恶意请求流量、恶意攻击,或者防止流量超出系统峰值;
-3. **缓存:** 避免大量请求直接落到数据库,将数据库击垮;
-4. **超时和重试机制:** 避免请求堆积造成雪崩;
-5. **回滚机制:** 快速修复错误版本。
-
-
-### 3. 现代互联网应用系统通常具有哪些特点?
-
-1. 高并发,大流量;
-2. 高可用:系统7×24小时不间断服务;
-3. 海量数据:需要存储、管理海量数据,需要使用大量服务器;
-4. 用户分布广泛,网络情况复杂:许多大型互联网都是为全球用户提供服务的,用户分布范围广,各地网络情况千差万别;
-5. 安全环境恶劣:由于互联网的开放性,使得互联网更容易受到攻击,大型网站几乎每天都会被黑客攻击;
-6. 需求快速变更,发布频繁:和传统软件的版本发布频率不同,互联网产品为快速适应市场,满足用户需求,其产品发布频率是极高的;
-7. 渐进式发展:与传统软件产品或企业应用系统一开始就规划好全部的功能和非功能需求不同,几乎所有的大型互联网网站都是从一个小网站开始,渐进地发展起来。
-
-### 4. 谈谈你对微服务领域的了解和认识
-
-现在大公司都在用并且未来的趋势都是 Spring Cloud,而阿里开源的 Spring Cloud Alibaba 也是 Spring Cloud 规范的实现 。
-
-我们通常把 Spring Cloud 理解为一系列开源组件的集合,但是 Spring Cloud并不是等同于 Spring Cloud Netflix 的 Ribbon、Feign、Eureka(停止更新)、Hystrix 这一套组件,而是抽象了一套通用的开发模式。它的目的是通过抽象出这套通用的模式,让开发者更快更好地开发业务。但是这套开发模式运行时的实际载体,还是依赖于 RPC、网关、服务发现、配置管理、限流熔断、分布式链路跟踪等组件的具体实现。
-
-Spring Cloud Alibaba 是官方认证的新一套 Spring Cloud 规范的实现,Spring Cloud Alibaba 是一套国产开源产品集合,后续还会有中文 reference 和一些原理分析文章,所以,这对于国内的开发者是非常棒的一件事。阿里的这一举动势必会推动国内微服务技术的发展,因为在没有 Spring Cloud Alibaba 之前,我们的第一选择是 Spring Cloud Netflix,但是它们的文档都是英文的,出问题后排查也比较困难, 在国内并不是有特别多的人精通。Spring Cloud Alibaba 由阿里开源组件和阿里云产品组件两部分组成,其致力于提供微服务一站式解决方案,方便开发者通过 Spring Cloud 编程模型轻松开发微服务应用。
-
-另外,Apache Dubbo Ecosystem 是围绕 Apache Dubbo 打造的微服务生态,是经过生产验证的微服务的最佳实践组合。在阿里巴巴的微服务解决方案中,Dubbo、Nacos 和 Sentinel,以及后续将开源的微服务组件,都是 Dubbo EcoSystem 的一部分。阿里后续也会将 Dubbo EcoSystem 集成到 Spring Cloud 的生态中。
-
-### 5. 谈谈你对 Dubbo 和 Spring Cloud 的认识(两者关系)
-
-具体可以看公众号-阿里巴巴中间件的这篇文章:[独家解读:Dubbo Ecosystem - 从微服务框架到微服务生态](https://mp.weixin.qq.com/s/iNVctXw7tUGHhnF0hV84ww)
-
-Dubbo 与 Spring Cloud 并不是竞争关系,Dubbo 作为成熟的 RPC 框架,其易用性、扩展性和健壮性已得到业界的认可。未来 Dubbo 将会作为 Spring Cloud Alibaba 的 RPC 组件,并与 Spring Cloud 原生的 Feign 以及 RestTemplate 进行无缝整合,实现“零”成本迁移。
-
-在阿里巴巴的微服务解决方案中,Dubbo、Nacos 和 Sentinel,以及后续将开源的微服务组件,都是 Dubbo EcoSystem 的一部分。我们后续也会将 Dubbo EcoSystem 集成到 Spring Cloud 的生态中。
-
-### 6. 性能测试了解吗?说说你知道的性能测试工具?
-
-性能测试指通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。性能测试是总称,通常细分为:
-
-1. **基准测试:** 在给系统施加较低压力时,查看系统的运行状况并记录相关数做为基础参考
-2. **负载测试:** 是指对系统不断地增加压力或增加一定压力下的持续时间,直到系统的某项或多项性能指标达到安全临界值,例如某种资源已经达到饱和状态等 。此时继续加压,系统处理能力会下降。
-3. **压力测试:** 超过安全负载情况下,不断施加压力(增加并发请求),直到系统崩溃或无法处理任何请求,依此获得系统最大压力承受能力。
-4. **稳定性测试:** 被测试系统在特定硬件、软件、网络环境下,加载一定业务压力(模拟生产环境不同时间点、不均匀请求,呈波浪特性)运行一段较长时间,以此检测系统是否稳定。
-
-后端程序员或者测试平常比较常用的测试工具是 JMeter(官网:[https://jmeter.apache.org/](https://jmeter.apache.org/))。Apache JMeter 是一款基于Java的压力测试工具(100%纯Java应用程序),旨在加载测试功能行为和测量性能。它最初被设计用于 Web 应用测试但后来扩展到其他测试领域。
-
-### 7. 对于一个单体应用系统,随着产品使用的用户越来越多,网站的流量会增加,最终单台服务器无法处理那么大的流量怎么办?
-
-这个时候就要考虑扩容了。《亿级流量网站架构核心技术》这本书上面介绍到我们可以考虑下面几步来解决这个问题:
-
-- 第一步,可以考虑简单的扩容来解决问题。比如增加系统的服务器,提高硬件能力等等。
-- 第二步,如果简单扩容搞不定,就需要水平拆分和垂直拆分数据/应用来提升系统的伸缩性,即通过扩容提升系统负载能力。
-- 第三步,如果通过水平拆分/垂直拆分还是搞不定,那就需要根据现有系统特性,架构层面进行重构甚至是重新设计,即推倒重来。
-
-对于系统设计,理想的情况下应支持线性扩容和弹性扩容,即在系统瓶颈时,只需要增加机器就可以解决系统瓶颈,如降低延迟提升吞吐量,从而实现扩容需求。
-
-如果你想扩容,则支持水平/垂直伸缩是前提。在进行拆分时,一定要清楚知道自己的目的是什么,拆分后带来的问题如何解决,拆分后如果没有得到任何收益就不要为了
-拆而拆,即不要过度拆分,要适合自己的业务。
-
-### 8. 大表优化的常见手段
-
- 当MySQL单表记录数过大时,数据库的CRUD性能会明显下降,一些常见的优化措施如下:
-
-1. **限定数据的范围:** 务必禁止不带任何限制数据范围条件的查询语句。比如:我们当用户在查询订单历史的时候,我们可以控制在一个月的范围内;
-2. **读/写分离:** 经典的数据库拆分方案,主库负责写,从库负责读;
-3. **垂直分区:** **根据数据库里面数据表的相关性进行拆分。** 例如,用户表中既有用户的登录信息又有用户的基本信息,可以将用户表拆分成两个单独的表,甚至放到单独的库做分库。**简单来说垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表。** 如下图所示,这样来说大家应该就更容易理解了。**垂直拆分的优点:** 可以使得行数据变小,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。**垂直拆分的缺点:** 主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应用层进行Join来解决。此外,垂直分区会让事务变得更加复杂;
-4. **水平分区:** **保持数据表结构不变,通过某种策略存储数据分片。这样每一片数据分散到不同的表或者库中,达到了分布式的目的。 水平拆分可以支撑非常大的数据量。** 水平拆分是指数据表行的拆分,表的行数超过200万行时,就会变慢,这时可以把一张的表的数据拆成多张表来存放。举个例子:我们可以将用户信息表拆分成多个用户信息表,这样就可以避免单一表数据量过大对性能造成影响。水平拆分可以支持非常大的数据量。需要注意的一点是:分表仅仅是解决了单一表数据过大的问题,但由于表的数据还是在同一台机器上,其实对于提升MySQL并发能力没有什么意义,所以 **水平拆分最好分库** 。水平拆分能够 **支持非常大的数据量存储,应用端改造也少**,但 **分片事务难以解决** ,跨界点Join性能较差,逻辑复杂。《Java工程师修炼之道》的作者推荐 **尽量不要对数据进行分片,因为拆分会带来逻辑、部署、运维的各种复杂度** ,一般的数据表在优化得当的情况下支撑千万以下的数据量是没有太大问题的。如果实在要分片,尽量选择客户端分片架构,这样可以减少一次和中间件的网络I/O。
-
-**下面补充一下数据库分片的两种常见方案:**
-
-- **客户端代理:** **分片逻辑在应用端,封装在jar包中,通过修改或者封装JDBC层来实现。** 当当网的 **Sharding-JDBC** 、阿里的TDDL是两种比较常用的实现。
-- **中间件代理:** **在应用和数据中间加了一个代理层。分片逻辑统一维护在中间件服务中。** 我们现在谈的 **Mycat** 、360的Atlas、网易的DDB等等都是这种架构的实现。
-
-### 9. 在系统中使用消息队列能带来什么好处?
-
-**《大型网站技术架构》第四章和第七章均有提到消息队列对应用性能及扩展性的提升。**
-
-#### 1) 通过异步处理提高系统性能
-
-如上图,**在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列之后,用户的请求数据发送给消息队列之后立即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。**
-
-通过以上分析我们可以得出**消息队列具有很好的削峰作用的功能**——即**通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。** 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。如下图所示:
-
-因为**用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败**。因此使用消息队列进行异步处理之后,需要**适当修改业务流程进行配合**,比如**用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功**,以免交易纠纷。这就类似我们平时手机订火车票和电影票。
-
-### 2) 降低系统耦合性
-我们知道模块分布式部署以后聚合方式通常有两种:1.**分布式消息队列**和2.**分布式服务**。
-
-> **先来简单说一下分布式服务:**
-
-目前使用比较多的用来构建**SOA(Service Oriented Architecture面向服务体系结构)**的**分布式服务框架**是阿里巴巴开源的**Dubbo**.如果想深入了解Dubbo的可以看我写的关于Dubbo的这一篇文章:**《高性能优秀的服务框架-dubbo介绍》**:[https://juejin.im/post/5acadeb1f265da2375072f9c](https://juejin.im/post/5acadeb1f265da2375072f9c)
-
-> **再来谈我们的分布式消息队列:**
-
-我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。
-
-我们最常见的**事件驱动架构**类似生产者消费者模式,在大型网站中通常用利用消息队列实现事件驱动结构。如下图所示:
-
-**消息队列使利用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。** 从上图可以看到**消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合**,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。**对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计**。
-
-消息接受者对消息进行过滤、处理、包装后,构造成一个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是一系列流程。
-
-**另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息。**
-
-**备注:** 不要认为消息队列只能利用发布-订阅模式工作,只不过在解耦这个特定业务环境下是使用发布-订阅模式的,**比如在我们的ActiveMQ消息队列中还有点对点工作模式**,具体的会在后面的文章给大家详细介绍,这一篇文章主要还是让大家对消息队列有一个更透彻的了解。
-
-> 这个问题一般会在上一个问题问完之后,紧接着被问到。“使用消息队列会带来什么问题?”这个问题要引起重视,一般我们都会考虑使用消息队列会带来的好处而忽略它带来的问题!
-
-### 10. 说说自己对 CAP 定理,BASE 理论的了解
-
-#### CAP 定理
-
-
-在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点:
-
-- **一致性(Consistence)** :所有节点访问同一份最新的数据副本
-- **可用性(Availability)**:每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据
-- **分区容错性(Partition tolerance)** : 分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。
-
-CAP仅适用于原子读写的NOSQL场景中,并不适合数据库系统。现在的分布式系统具有更多特性比如扩展性、可用性等等,在进行系统设计和开发时,我们不应该仅仅局限在CAP问题上。
-
-**注意:不是所谓的3选2(不要被网上大多数文章误导了):**
-
-大部分人解释这一定律时,常常简单的表述为:“一致性、可用性、分区容忍性三者你只能同时达到其中两个,不可能同时达到”。实际上这是一个非常具有误导性质的说法,而且在CAP理论诞生12年之后,CAP之父也在2012年重写了之前的论文。
-
-**当发生网络分区的时候,如果我们要继续服务,那么强一致性和可用性只能2选1。也就是说当网络分区之后P是前提,决定了P之后才有C和A的选择。也就是说分区容错性(Partition tolerance)我们是必须要实现的。**
-
-我在网上找了很多文章想看一下有没有文章提到这个不是所谓的3选2,用百度半天没找到了一篇,用谷歌搜索找到一篇比较不错的,如果想深入学习一下CAP就看这篇文章把,我这里就不多BB了:**《分布式系统之CAP理论》 :** [https://www.cnblogs.com/hxsyl/p/4381980.html](https://www.cnblogs.com/hxsyl/p/4381980.html)
-
-
-#### BASE 理论
-
-**BASE** 是 **Basically Available(基本可用)** 、**Soft-state(软状态)** 和 **Eventually Consistent(最终一致性)** 三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果,其来源于对大规模互联网系统分布式实践的总结,是基于CAP定理逐步演化而来的,它大大降低了我们对系统的要求。
-
-**BASE理论的核心思想:** 即使无法做到强一致性,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到最终一致性。也就是牺牲数据的一致性来满足系统的高可用性,系统中一部分数据不可用或者不一致时,仍需要保持系统整体“主要可用”。
-
-
-**BASE理论三要素:**
-
-
-
-1. **基本可用:** 基本可用是指分布式系统在出现不可预知故障的时候,允许损失部分可用性。但是,这绝不等价于系统不可用。 比如: **①响应时间上的损失**:正常情况下,一个在线搜索引擎需要在0.5秒之内返回给用户相应的查询结果,但由于出现故障,查询结果的响应时间增加了1~2秒;**②系统功能上的损失**:正常情况下,在一个电子商务网站上进行购物的时候,消费者几乎能够顺利完成每一笔订单,但是在一些节日大促购物高峰的时候,由于消费者的购物行为激增,为了保护购物系统的稳定性,部分消费者可能会被引导到一个降级页面;
-2. **软状态:** 软状态指允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行数据同步的过程存在延时;
-3. **最终一致性:** 最终一致性强调的是系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态。因此,最终一致性的本质是需要系统保证最终数据能够达到一致,而不需要实时保证系统数据的强一致性。
-
-### 参考
-
-- 《大型网站技术架构》
-- 《亿级流量网站架构核心技术》
-- 《Java工程师修炼之道》
-- https://www.cnblogs.com/puresoul/p/5456855.html
diff --git "a/docs/system-design/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\244\247\346\217\255\347\247\230.md" "b/docs/system-design/\345\256\232\346\227\266\344\273\273\345\212\241.md"
similarity index 99%
rename from "docs/system-design/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\244\247\346\217\255\347\247\230.md"
rename to "docs/system-design/\345\256\232\346\227\266\344\273\273\345\212\241.md"
index 752f8879588..026bfa075db 100644
--- "a/docs/system-design/Java\345\256\232\346\227\266\344\273\273\345\212\241\345\244\247\346\217\255\347\247\230.md"
+++ "b/docs/system-design/\345\256\232\346\227\266\344\273\273\345\212\241.md"
@@ -1,3 +1,5 @@
+# Java定时任务大揭秘
+
## 为什么需要定时任务?
我们来看一下几个非常常见的业务场景:
diff --git a/docs/tools/database/CHINER.md b/docs/tools/database/CHINER.md
new file mode 100644
index 00000000000..a9543afad2a
--- /dev/null
+++ b/docs/tools/database/CHINER.md
@@ -0,0 +1,100 @@
+# CHINER: 干掉 PowerDesigner,这个国产数据库建模工具很强!
+
+大家好,我是 Guide!
+
+今天给小伙伴们分享一个我平时经常使用的国产数据库建模工具,非常好用!
+
+这个数据库建模工具的名字叫做 **CHINER** [kaɪˈnər] 。可能大部分小伙伴都没有听过这个工具,不过,相信大部分小伙伴应该都听说过 CHINER 的前身 **PDMan**。
+
+CHINER 是 CHINESE Entity Relation 的缩写,翻译过来就是国产实体关系图工具,中文名称为:**元数建模**,也作:"**CHINER[元数建模]**"公开使用。
+
+CHINER 对 PDMan 的架构设计进行了大幅改善,并对 PDMan 做到高度兼容。
+
+CHINER 的界面简单,功能简洁,非常容易上手。并且,可以直接导入 PowerDesigner 文件、PDMan 文件,还可以直接从数据库或者 DDL 语句直接导入。
+
+
+
+CHINER 的技术栈:React+Electron+Java 。
+
+* Gitee 地址:https://gitee.com/robergroup/chiner 。
+* 操作手册: https://www.yuque.com/chiner/docs/manual 。
+
+## 快速体验
+
+### 下载安装
+
+CHINER 提供了 **Windows** 、**Mac** 、**Linux** 下的一键安装包,我们直接下载即可。
+
+> 下载地址:https://gitee.com/robergroup/chiner/releases
+
+需要注意的是:如果你当前使用的 Chrome 浏览器的话,无法直接点击链接下载。你可以更换浏览器下载或者右键链接选择链接存储为...。
+
+
+
+打开软件之后,界面如下图所示。
+
+
+
+我这里以电商项目参考模板来演示 CHINER 的基本操作。
+
+### 模块化管理
+
+电商项目比较复杂,我们可以将其拆分为一个一个独立的模块(表分组),每个模块下有数据表,视图,关系图,数据字典。
+
+像这个电商项目就创建了 3 个模块:消费端、商家端、平台端。
+
+
+
+不过,对于一些比较简单的项目比如博客系统、企业管理系统直接使用简单模式即可。
+
+### 数据库表管理
+
+右键数据表即可创建新的数据库表,点击指定的数据库表即可对指定的数据库表进行设计。
+
+
+
+并且,数据表字段可以直接关联数据字典。
+
+
+
+如果需要创建视图的话,直接右键视图即可。视图是从一个或多个表导出的虚拟的表,其内容由查询定义。具有普通表的结构,但是不实现数据存储。
+
+
+
+数据库视图可以方便我们进行查询。不过,数据库视图会影响数据库性能,通常不建议使用。
+
+### 关系图
+
+我平时在项目中比较常见的 **ER 关联关系图** ,可以使用 CHINER 进行手动维护。
+
+如果你需要添加新的数据库表到关系图的话,直接拖拽指定的数据库表到右边的关系图展示界面即可。另外,表与表之间的关联也需要你手动对相关联的字段进行连接。
+
+
+
+手动进行维护,说实话还是比较麻烦的,也比较容易出错。
+
+像 [Navicat Data Modeler](https://www.navicat.com.cn/products/navicat-data-modeler) 在这方面就强多了,它可以自动生成 ER 图。
+
+
+
+### 数据库表代码模板
+
+支持直接生成对应表的 SQL 代码(支持 MySQL、Oracle、SQL Server、PostgreSQL 等数据库)并且还提供了 Java 和 C# 的 JavaBean。
+
+
+
+### 导出数据库表
+
+你可以选择导出 DDL、Word 文档、数据字典 SQL、当前关系图的图片。
+
+
+
+### 数据库逆向
+
+你还可以连接数据库,逆向解析数据库。
+
+
+
+数据库连接成功之后,我们点击右上角的菜单 `导入—> 从数据库导入` 即可。
+
+
diff --git a/docs/tools/database/DBeaver.md b/docs/tools/database/DBeaver.md
new file mode 100644
index 00000000000..f57f9450b8b
--- /dev/null
+++ b/docs/tools/database/DBeaver.md
@@ -0,0 +1,85 @@
+# DBeaver:开源数据库管理工具。
+
+[《再见,Navicat!同事安利的这个IDEA的兄弟,真香!》](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247489523&idx=1&sn=4e96972842bdcea2e05cb267d17c5e8e&chksm=cea25838f9d5d12e45a9939370eccf2bff7177038e70437ea0e01d64030118852ee66ae72284&token=2000865596&lang=zh_CN#rd) 这篇文章发了之后很多人抱怨Datagrip 的占用内存太大,很多人推荐了 DBeaver 这款开源免费的数据库管理工具。于是,我昨夜简单体验了一下 DBeaver ,然后写了这篇文章。
+
+## DBeaver 概览
+
+DBeaver 是一个基于 Java 开发 ,并且支持几乎所有的数据库产品的开源数据库管理工具。
+
+DBeaver 社区版不光支持关系型数据库比如MySQL、PostgreSQL、MariaDB、SQLite、Oracle、Db2、SQL Server,还比如 SQLite、H2这些内嵌数据库。还支持常见的全文搜索引擎比如 Elasticsearch 和 Solr、大数据相关的工具比如Hive和 Spark。
+
+
+
+甚至说,DBeaver 的商业版本还支持各种 NoSQL 数据库。
+
+
+
+## 使用
+
+**DBeaver 虽然小巧,但是功能还是十分强大的。基本的表设计、SQL执行、ER图、数据导入导出等等常用功能都不在话下。**
+
+**我下面只简单演示一下基本的数据库的创建以及表的创建。**
+
+### 下载安装
+
+官方网提供的下载地址:https://dbeaver.io/download/ ,你可以根据自己的操作系统选择合适的版本进行下载安装。
+
+比较简单,这里就不演示了。
+
+### 连接数据库
+
+**1.选择自己想要的连接的数据库,然后点击下一步即可(第一次连接可能需要下载相关驱动)。**
+
+我这里以MySQL为例。
+
+
+
+**2.输入数据库的地址、用户名和密码等信息,然后点击完成即可连接**
+
+点击完成之前,你可以先通过左下方的测试连接来看一下数据库是否可以被成功连接上。
+
+
+
+### 新建数据库
+
+右键-> 新建数据库(MySQL 用户记得使用 utf8mb4而不是 utf8)
+
+
+
+### 数据库表相关操作
+
+#### 新建表
+
+
+
+#### 新建列
+
+
+
+#### 创建约束(主键、唯一键)
+
+
+
+
+
+#### 插入数据
+
+我们通过 SQL 编辑器插入数据:
+
+
+
+```java
+INSERT into user(id,name,phone,password) values ('A00001','guide哥','181631312315','123456');
+INSERT into user(id,name,phone,password) values ('A00002','guide哥2','181631312313','123456');
+INSERT into user(id,name,phone,password) values ('A00003','guide哥3','181631312312','123456');
+```
+
+## 总结
+
+总的来说,简单体验之后感觉还是很不错的,占用内存也确实比 DataGrip 确实要小很多。
+
+各位小伙伴可以自行体验一下。毕竟免费并且开源,还是很香的!
+
+
+
+
diff --git a/docs/tools/database/screw.md b/docs/tools/database/screw.md
new file mode 100644
index 00000000000..30542e17efe
--- /dev/null
+++ b/docs/tools/database/screw.md
@@ -0,0 +1,296 @@
+# screw:一键生成数据库文档,堪称数据库界的Swagger
+
+在项目中,我们经常需要整理数据库表结构文档。
+
+一般情况下,我们都是手动整理数据库表结构文档,当表结构有变动的时候,自己手动进行维护。
+
+数据库表少的时候还好,数据库表多了之后,手动整理和维护数据库表结构文档简直不要太麻烦,而且,还非常容易出错!
+
+**有没有什么好用的工具帮助我们自动生成数据库表结构文档呢?**
+
+当然有!Github 上就有一位朋友开源了一款数据库表结构文档自动生成工具—— **screw** 。
+
+项目地址: https://github.com/pingfangushi/screw 。
+
+
+
+screw 翻译过来的意思就是螺丝钉,作者希望这个工具能够像螺丝钉一样切实地帮助到我们的开发工作。
+
+目前的话,screw 已经支持市面上大部分常见的数据库比如 MySQL、MariaDB、Oracle、SqlServer、PostgreSQL、TiDB。
+
+另外,screw 使用起来也非常简单,根据官网提示,不用 10 分钟就能成功在本地使用起来!
+
+## 快速入门
+
+为了验证 screw 自动生成数据库表结构文档的效果,我们首先创建一个简单的存放博客数据的数据库表。
+
+```sql
+CREATE TABLE `blog` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
+ `title` varchar(255) NOT NULL COMMENT '博客标题',
+ `content` longtext NOT NULL COMMENT '博客内容',
+ `description` varchar(255) DEFAULT NULL COMMENT '博客简介',
+ `cover` varchar(255) DEFAULT NULL COMMENT '博客封面图片地址',
+ `views` int(11) NOT NULL DEFAULT '0' COMMENT '博客阅读次数',
+ `user_id` bigint(20) DEFAULT '0' COMMENT '发表博客的用户ID',
+ `channel_id` bigint(20) NOT NULL COMMENT '博客分类ID',
+ `recommend` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否推荐',
+ `top` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否置顶',
+ `comment` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否开启评论',
+ `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COMMENT='博客';
+```
+
+### 基于 Java 代码
+
+#### 引入依赖
+
+创建一个普通的 Maven 项目即可!然后引入 screw、HikariCP、MySQL 这 3 个依赖。
+
+```xml
+
+
+ cn.smallbun.screw
+ screw-core
+ 1.0.5
+
+
+
+ com.zaxxer
+ HikariCP
+ 3.4.5
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.20
+
+```
+
+你可以通过下面的地址在 mvnrepository 获取最新版本的 screw。
+
+> https://mvnrepository.com/artifact/cn.smallbun.screw/screw-core
+
+#### 编写代码
+
+生成数据库文档的代码的整个代码逻辑还是比较简单的,我们只需要经过下面 5 步即可:
+
+```java
+// 1.获取数据源
+DataSource dataSource = getDataSource();
+// 2.获取数据库文档生成配置(文件路径、文件类型)
+EngineConfig engineConfig = getEngineConfig();
+// 3.获取数据库表的处理配置,可忽略
+ProcessConfig processConfig = getProcessConfig();
+// 4.Screw 完整配置
+Configuration config = getScrewConfig(dataSource, engineConfig, processConfig);
+// 5.执行生成数据库文档
+new DocumentationExecute(config).execute();
+```
+
+**1、获取数据库源**
+
+对数据库以及数据库连接池进行相关配置。务必将数据库相关的配置修改成你自己的。
+
+```java
+/**
+ * 获取数据库源
+ */
+private static DataSource getDataSource() {
+ //数据源
+ HikariConfig hikariConfig = new HikariConfig();
+ hikariConfig.setDriverClassName("com.mysql.cj.jdbc.Driver");
+ hikariConfig.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/javaguide-blog");
+ hikariConfig.setUsername("root");
+ hikariConfig.setPassword("123456");
+ //设置可以获取tables remarks信息
+ hikariConfig.addDataSourceProperty("useInformationSchema", "true");
+ hikariConfig.setMinimumIdle(2);
+ hikariConfig.setMaximumPoolSize(5);
+ return new HikariDataSource(hikariConfig);
+}
+```
+
+**2、获取文件生成配置**
+
+这一步会指定数据库文档生成的位置、文件类型以及文件名称。
+
+```java
+/**
+ * 获取文件生成配置
+ */
+private static EngineConfig getEngineConfig() {
+ //生成配置
+ return EngineConfig.builder()
+ //生成文件路径
+ .fileOutputDir("/Users/guide/Documents/代码示例/screw-demo/doc")
+ //打开目录
+ .openOutputDir(true)
+ //文件类型
+ .fileType(EngineFileType.HTML)
+ //生成模板实现
+ .produceType(EngineTemplateType.freemarker)
+ //自定义文件名称
+ .fileName("数据库结构文档").build();
+}
+```
+
+如果不配置生成文件路径的话,默认也会存放在项目的 `doc` 目录下。
+
+另外,我们这里指定生成的文件格式为 HTML。除了 HTML 之外,screw 还支持 Word 、Markdown 这两种文件格式。
+
+不太建议生成 Word 格式,比较推荐 Markdown 格式。
+
+**3、获取数据库表的处理配置**
+
+这一步你可以指定只生成哪些表:
+
+```java
+/**
+ * 获取数据库表的处理配置,可忽略
+ */
+private static ProcessConfig getProcessConfig() {
+ return ProcessConfig.builder()
+ // 指定只生成 blog 表
+ .designatedTableName(new ArrayList<>(Collections.singletonList("blog")))
+ .build();
+}
+```
+
+还可以指定忽略生成哪些表:
+
+```java
+private static ProcessConfig getProcessConfig() {
+ ArrayList ignoreTableName = new ArrayList<>();
+ ignoreTableName.add("test_user");
+ ignoreTableName.add("test_group");
+ ArrayList ignorePrefix = new ArrayList<>();
+ ignorePrefix.add("test_");
+ ArrayList ignoreSuffix = new ArrayList<>();
+ ignoreSuffix.add("_test");
+ return ProcessConfig.builder()
+ //忽略表名
+ .ignoreTableName(ignoreTableName)
+ //忽略表前缀
+ .ignoreTablePrefix(ignorePrefix)
+ //忽略表后缀
+ .ignoreTableSuffix(ignoreSuffix)
+ .build();
+}
+```
+
+这一步也可以省略。如果不指定 `ProcessConfig` 的话,就会按照默认配置来!
+
+**4、生成 screw 完整配置**
+
+根据前面 3 步,生成 screw 完整配置。
+
+```java
+private static Configuration getScrewConfig(DataSource dataSource, EngineConfig engineConfig, ProcessConfig processConfig) {
+ return Configuration.builder()
+ //版本
+ .version("1.0.0")
+ //描述
+ .description("数据库设计文档生成")
+ //数据源
+ .dataSource(dataSource)
+ //生成配置
+ .engineConfig(engineConfig)
+ //生成配置
+ .produceConfig(processConfig)
+ .build();
+}
+```
+
+**5、执行生成数据库文档**
+
+
+
+下图就是生成的 HTML 格式的数据库设计文档。
+
+
+
+### 基于 Maven 插件
+
+除了基于 Java 代码这种方式之外,你还可以通过 screw 提供的 Maven 插件来生成数据库文档。方法也非常简单!
+
+**1、配置 Maven 插件**
+
+务必将数据库相关的配置修改成你自己的。
+
+```xml
+
+
+
+ cn.smallbun.screw
+ screw-maven-plugin
+ 1.0.5
+
+
+
+ com.zaxxer
+ HikariCP
+ 3.4.5
+
+
+
+ mysql
+ mysql-connector-java
+ 8.0.20
+
+
+
+
+ root
+
+ 123456
+
+ com.mysql.cj.jdbc.Driver
+
+ jdbc:mysql://127.0.0.1:3306/javaguide-blog
+
+ MD
+
+ true
+
+ freemarker
+
+ 数据库结构文档
+
+ 数据库设计文档生成
+
+ ${project.version}
+
+ 数据库文档
+
+
+
+ compile
+
+ run
+
+
+
+
+
+
+```
+
+**2、手动执行生成数据库文档**
+
+
+
+我们这里指定生成的是 Markdown 格式。
+
+
+
+下图就是生成的 Markdown 格式的数据库设计文档,效果还是非常不错的!
+
+
+
+
+
+
diff --git a/docs/tools/Docker.md b/docs/tools/docker/docker.md
similarity index 96%
rename from docs/tools/Docker.md
rename to docs/tools/docker/docker.md
index d94550deb9b..26e0c636274 100644
--- a/docs/tools/Docker.md
+++ b/docs/tools/docker/docker.md
@@ -1,3 +1,5 @@
+# Docker 基本概念解读
+
**本文只是对 Docker 的概念做了较为详细的介绍,并不涉及一些像 Docker 环境的安装以及 Docker 的一些常见操作和命令。**
## 一 认识容器
@@ -36,7 +38,7 @@
**容器:**
-
+
通过上面这三张抽象图,我们可以大概通过类比概括出: **容器虚拟化的是操作系统而不是硬件,容器之间是共享同一套操作系统资源的。虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统。因此容器的隔离级别会稍低一些。**
@@ -46,8 +48,6 @@
## 二 再来谈谈 Docker 的一些概念
-
-
### 2.1 什么是 Docker?
说实话关于 Docker 是什么并太好说,下面我通过四点向你说明 Docker 到底是个什么东西。
@@ -57,8 +57,6 @@
- **Docker 能够自动执行重复性任务,例如搭建和配置开发环境,从而解放了开发人员以便他们专注在真正重要的事情上:构建杰出的软件。**
- **用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。**
-
-
### 2.2 Docker 思想
- **集装箱**
@@ -92,11 +90,11 @@
传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;而容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核,而且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
-
+
### 3.2 容器与虚拟机总结
-
+
- **容器是一个应用层抽象,用于将代码和依赖资源打包在一起。** **多个容器可以在同一台机器上运行,共享操作系统内核,但各自作为独立的进程在用户空间中运行** 。与虚拟机相比, **容器占用的空间较少**(容器镜像大小通常只有几十兆),**瞬间就能完成启动** 。
@@ -108,7 +106,7 @@
就我而言,对于两者无所谓谁会取代谁,而是两者可以和谐共存。
-
+
---
@@ -242,7 +240,7 @@ docker rmi f6509bac4980 # 或者 docker rmi mysql
如果你搜索 Docker 官网,会发现如下的字样:**“Docker - Build, Ship, and Run Any App, Anywhere”**。那么 Build, Ship, and Run 到底是在干什么呢?
-
+
- **Build(构建镜像)** : 镜像就像是集装箱包括文件以及运行环境等等资源。
- **Ship(运输镜像)** :主机和仓库间运输,这里的仓库就像是超级码头一样。
diff --git "a/docs/tools/Docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md" "b/docs/tools/docker/docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md"
similarity index 99%
rename from "docs/tools/Docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md"
rename to "docs/tools/docker/docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md"
index 7e9b03bcce5..5348b4a510f 100644
--- "a/docs/tools/Docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md"
+++ "b/docs/tools/docker/docker\344\273\216\345\205\245\351\227\250\345\210\260\345\256\236\346\210\230.md"
@@ -1,3 +1,5 @@
+# Docker从入门到上手干事
+
## Docker介绍
### 什么是 Docker?
@@ -11,7 +13,7 @@
官网地址:https://www.docker.com/ 。
-
+
### 为什么要用 Docker?
diff --git a/docs/tools/Git.md b/docs/tools/git/git-intro.md
similarity index 92%
rename from docs/tools/Git.md
rename to docs/tools/git/git-intro.md
index 8dd6c316c3f..2cfb2e95ef8 100644
--- a/docs/tools/Git.md
+++ b/docs/tools/git/git-intro.md
@@ -1,27 +1,4 @@
-
-
-- [版本控制](#版本控制)
- - [什么是版本控制](#什么是版本控制)
- - [为什么要版本控制](#为什么要版本控制)
- - [本地版本控制系统](#本地版本控制系统)
- - [集中化的版本控制系统](#集中化的版本控制系统)
- - [分布式版本控制系统](#分布式版本控制系统)
-- [认识 Git](#认识-git)
- - [Git 简史](#git-简史)
- - [Git 与其他版本管理系统的主要区别](#git-与其他版本管理系统的主要区别)
- - [Git 的三种状态](#git-的三种状态)
-- [Git 使用快速入门](#git-使用快速入门)
- - [获取 Git 仓库](#获取-git-仓库)
- - [记录每次更新到仓库](#记录每次更新到仓库)
- - [一个好的 Git 提交消息](#一个好的-Git-提交消息)
- - [推送改动到远程仓库](#推送改动到远程仓库)
- - [远程仓库的移除与重命名](#远程仓库的移除与重命名)
- - [查看提交历史](#查看提交历史)
- - [撤销操作](#撤销操作)
- - [分支](#分支)
-- [推荐阅读](#推荐阅读)
-
-
+# Git 入门
## 版本控制
diff --git "a/docs/tools/Github\346\212\200\345\267\247.md" "b/docs/tools/git/github\346\212\200\345\267\247.md"
similarity index 99%
rename from "docs/tools/Github\346\212\200\345\267\247.md"
rename to "docs/tools/git/github\346\212\200\345\267\247.md"
index c77cc2cfab6..1142b3e38e1 100644
--- "a/docs/tools/Github\346\212\200\345\267\247.md"
+++ "b/docs/tools/git/github\346\212\200\345\267\247.md"
@@ -1,3 +1,5 @@
+# Github小技巧
+
我使用 Github 已经有 5 年多了,今天毫无保留地把自己觉得比较有用的 Github 小技巧送给关注 JavaGuide 的各位小伙伴。
这篇文章肝了很久,就挺用心的,大家看内容就知道了。
diff --git a/docs/tools/readme.md b/docs/tools/readme.md
new file mode 100644
index 00000000000..258557b4412
--- /dev/null
+++ b/docs/tools/readme.md
@@ -0,0 +1,19 @@
+---
+icon: tool
+---
+
+# 常用开发工具总结
+
+## 数据库
+
+- [CHINER: 干掉 PowerDesigner,这个国产数据库建模工具很强!](./database/CHINER.md)
+- [DBeaver:开源数据库管理工具。](./database/DBeaver.md)
+- [screw:一键生成数据库文档,堪称数据库界的Swagger](./database/screw.md)
+
+## Git
+
+- [Git 入门](./git/git-intro.md)
+- [Github 小技巧](./git/git-intro.md)
+
+## Docker
+
diff --git a/docs/update-history.md b/docs/update-history.md
deleted file mode 100644
index 030772a2c33..00000000000
--- a/docs/update-history.md
+++ /dev/null
@@ -1,12 +0,0 @@
-**2020-03-07**
-
-[refer](https://github.com/Snailclimb/JavaGuide/commit/9e6424ffd63cd6664a03dd84ec1a9dc32cf3b2e5)
-
-将面试指南部分的文章移除,避免JavaGuide因为内容的膨胀而过于臃肿。移除部分目前是通过 PDF 文档的形式来分享,详见[JavaGuide面试突击版](./javaguide面试突击版.md)。
-
-**2020-02-29**
-
-[refer](https://github.com/Snailclimb/JavaGuide/commit/e86ee6761dc5fe03f410711b28bc3a119e9ff731)
-
-对整体知识体系结构进行了调整和完善。
-
diff --git "a/docs/\345\205\254\344\274\227\345\217\267\345\216\206\345\217\262\346\226\207\347\253\240\346\261\207\346\200\273.md" "b/docs/\345\205\254\344\274\227\345\217\267\345\216\206\345\217\262\346\226\207\347\253\240\346\261\207\346\200\273.md"
deleted file mode 100644
index 5741f71402b..00000000000
--- "a/docs/\345\205\254\344\274\227\345\217\267\345\216\206\345\217\262\346\226\207\347\253\240\346\261\207\346\200\273.md"
+++ /dev/null
@@ -1,210 +0,0 @@
-## 热文
-
-
-
-- [盘点阿里巴巴 15 款开发者工具](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485159&idx=1&sn=c97c087c45ad6dfc0ef61d80a9d0f702&scene=21#wechat_redirect)
-- [蚂蚁金服2019实习生面经总结(已拿口头offer)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485147&idx=1&sn=90e525a83a451d8c20298a7ef2d35ab9&scene=21#wechat_redirect)
-- [一千行 MySQL 学习笔记](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485025&idx=1&sn=1f4e19fc77af28f6795feff6ce7465b9&scene=21#wechat_redirect)
-- [可能是把Java内存区域讲的最清楚的一篇文章](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485068&idx=1&sn=c37267fe59978dbfcd6a9a54eee1c502&scene=21#wechat_redirect)
-- [搞定 JVM 垃圾回收就是这么简单](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484877&idx=1&sn=f54d41b68f0cd6cc7c0348a2fddbda9f&chksm=cea24a06f9d5c3102bfef946ba6c7cc5df9a503ccb14b9b141c54e179617e4923c260c0b0a01&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [【原创】Java学习路线以及方法推荐](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485290&idx=1&sn=569fa9724aae83bff3a353aefc5b7f1c&scene=21#wechat_redirect)
-- [技术面试复习大纲](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485505&idx=1&sn=f7d916334c078bc3fdc2933f889b5016&chksm=cea2478af9d5ce9cafcfe9a053e49e84296d8b1929f79844bba59c8c3d8b56753f34a2c2f6a9&token=1701499214&lang=zh_CN&scene=21#wechat_redirect)
-
-## Java
-
-
-### 必看书籍
-
-- [Java学习必备书籍推荐终极版!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485113&idx=1&sn=e4dd1bb22778e4e9139bf29d98a7492b&chksm=cea24972f9d5c064e5b454b84b9bc0d42f4aec007f20f79b564398e6dec7c0cdcda0e64193b5&token=1482344439&lang=zh_CN&scene=21#wechat_redirect)
-
-### 基础
-
-- [关于Java基础你不得不会的34个问题](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485015&idx=1&sn=5daa243c3359b88fc88b951f9d08b273&chksm=cea2499cf9d5c08a7698559a2fc27078c6b35856bc2d3588172bf64708c115d4b35d3de80cd9&token=1913747689&lang=zh_CN&scene=21#wechat_redirect)
-- [剖析面试最常见问题之 Java 基础知识](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485173&idx=1&sn=9605f89ed0893b674d14b0c8cf4dc942&chksm=cea2493ef9d5c028a969bb89b53f48fbdd72b975319a844319e3111b15d5dbbc350d91ea5b5a&token=1667678311&lang=zh_CN&scene=21#wechat_redirect)
-
-### Java8新特性
-
-- [Java 8 新特性最佳指南](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484744&idx=1&sn=9db31dca13d327678845054af75efb74&chksm=cea24a83f9d5c3956f4feb9956b068624ab2fdd6c4a75fe52d5df5dca356a016577301399548&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [看完这篇文章,别说自己不会用Lambda表达式了!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485425&idx=1&sn=3cc01bc7c42549b6b6aa62b3656e02d1&chksm=cea2483af9d5c12cd10174dac4465a631b14a6d6a09495b018a98e01c698e86368d26b3be03d&token=1667678311&lang=zh_CN&scene=21#wechat_redirect)
-
-### JVM
-
-- [Java内存区域](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485068&idx=1&sn=c37267fe59978dbfcd6a9a54eee1c502&scene=21#wechat_redirect)
-- [垃圾回收](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484877&idx=1&sn=f54d41b68f0cd6cc7c0348a2fddbda9f&chksm=cea24a06f9d5c3102bfef946ba6c7cc5df9a503ccb14b9b141c54e179617e4923c260c0b0a01&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [谈Java类文件结构](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485250&idx=2&sn=33793bcce3f2ff31b83cf2f9c32df153&scene=21#wechat_redirect)
-- [类加载过程](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485264&idx=2&sn=8c97f7e7d7ad36bc50e713572dbd1529&scene=21#wechat_redirect)
-
-### 并发编程
-
-- [并发编程面试必备:JUC 中的 Atomic 原子类总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484834&idx=1&sn=7d3835091af8125c13fc6db765f4c5bd&chksm=cea24a69f9d5c37ff88a8328214cb48b06afb9dc82e46cd924d2595f109ea28922212f9e653c&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [并发编程面试必备:AQS 原理以及 AQS 同步组件总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484832&idx=1&sn=f902febd050eac59d67fc0804d7e1ad5&chksm=cea24a6bf9d5c37d6b505fe1d43e4fb709729149f1f77344b4a0f5956cab5020a2e102f2adf2&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [BATJ都爱问的多线程面试题](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484831&idx=1&sn=e22d2832a436dbb94233272429d4c4c4&chksm=cea24a54f9d5c3420e96aa94e3d893f4cf825852fff0b4a7e4e241cc229f4666f3dc4d53955e&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-- [通俗易懂,JDK 并发容器总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484797&idx=1&sn=e28462eec497e38053d9fb9ba17ff022&chksm=cea24ab6f9d5c3a05b5ad36111e93d824ce964442366bc8add1cd77cb432057e4995592c8024&token=1082669959&lang=zh_CN&scene=21#wechat_redirect)
-
-### 代码质量
-
-- [八点建议助您写出优雅的Java代码](https://mp.weixin.qq.com/s/o3BGTdAa8VufcIKU0ScBqA)
-- [十分钟搞懂Java效率工具Lombok使用与原理](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485385&idx=2&sn=a7c3fb4485ffd8c019e5541e9b1580cd&chksm=cea24802f9d5c1144eee0da52cfc0cc5e8ee3590990de3bb642df4d4b2a8cd07f12dd54947b9&token=1667678311&lang=zh_CN#rd)
-- [如何写出让同事无法维护的代码?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485413&idx=2&sn=70336d94018ad93d67cfacb4aeceb01b&chksm=cea2482ef9d5c1382d8a009e2ecd680c3b6ac3c7c02810af8901970e69c431273113ca7e4447&token=1667678311&lang=zh_CN#rd)
-- [Code Review最佳实践](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485494&idx=1&sn=c7f160fd1bb13a20b887493003acbbf9&chksm=cea247fdf9d5ceebf3b98bd7c524d0ecc672d4bcb10a70fae90390abd862538aa3283c93375b&token=1701499214&lang=zh_CN&scene=21#wechat_redirect)
-- [后端开发必备的 RestFul API 知识](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485510&idx=1&sn=e9273322ae638c8465a606737109ab97&chksm=cea2478df9d5ce9b58b9ff1f1e2ecca99e961b911adcec3d5a579b41e01151160cfb2891d91b&token=1701499214&lang=zh_CN&scene=21#wechat_redirect)
-
-## 网络
-
-- [搞定计算机网络面试,看这篇就够了(补充版)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484889&idx=1&sn=5f9e6f5c29f9514701c246573d15d9fa&chksm=cea24a12f9d5c3041efd5cf864eb69b76aea6ef9c000a72b16d54794aab97d4fb53515a77147&token=1082669959&lang=zh_CN#rd)
-
-## 系统设计
-
-### Spring
-
-- [Spring常见问题总结(补充版)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485576&idx=1&sn=f993349f12650a68904e1d99d2465131&chksm=cea24743f9d5ce55ffe543a0feaf2c566382024b625b59283482da6ab0cbcf2a3c9dc5b64a53&token=2133161636&lang=zh_CN#rd)
-- [面试官:“谈谈Spring中都用到了那些设计模式?”。](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485303&idx=1&sn=9e4626a1e3f001f9b0d84a6fa0cff04a&chksm=cea248bcf9d5c1aaf48b67cc52bac74eb29d6037848d6cf213b0e5466f2d1fda970db700ba41&token=1667678311&lang=zh_CN#rd)
-- [可能是最漂亮的Spring事务管理详解](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484943&idx=1&sn=46b9082af4ec223137df7d1c8303ca24&chksm=cea249c4f9d5c0d2b8212a17252cbfb74e5fbe5488b76d829827421c53332326d1ec360f5d63&token=1082669959&lang=zh_CN#rd)
-- [SpringMVC 工作原理详解](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484846&idx=1&sn=490014ea65669c1a1e73e25d7b9fa569&chksm=cea24a65f9d5c373d31d6cdd61297db21de63462c1c03c34b7025a0d0b93f1182b2ad7e33cab&token=1082669959&lang=zh_CN#rd)
-- [Spring编程式和声明式事务实例讲解](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484942&idx=1&sn=b0d9e6f1af243bbf7f34ede5a6d2277d&chksm=cea249c5f9d5c0d3da9206b753bb7734d47d8d8b43edcc02bdf6f139e34e1db512cf5ed32217&token=1082669959&lang=zh_CN#rd)
-- [一文轻松搞懂Spring中bean的作用域与生命周期](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484865&idx=2&sn=178c6e64e6c12172e77efdd669eb86a7&chksm=cea24a0af9d5c31c389ae7817613a336f00c330021f73c90afe383c8caf6ea07a9e1f949c68d&token=1082669959&lang=zh_CN#rd)
-
-### SpringBoot
-
-- [超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484809&idx=1&sn=a789eba40404e6501d51b24345b28906&chksm=cea24a42f9d5c3544babde7f33790fc54f02ebc2f589ce9fa116bbb9c7b0c0cfb1bc314d17de&token=1082669959&lang=zh_CN#rd)
-- [基于 SpringBoot2.0+优雅整合 SpringBoot+Mybatis](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484805&idx=2&sn=0e148af5baebae53b3fd365cff689046&chksm=cea24a4ef9d5c35862efc9c67b0619f7e8ade4b75e1001189ededccd8fd35ca5cd19fda074b9&token=1082669959&lang=zh_CN#rd)
-- [新手也能实现,基于SpirngBoot2.0+ 的 SpringBoot+Mybatis 多数据源配置](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484803&idx=1&sn=9179890db39721a59bb815b7f985ec2d&chksm=cea24a48f9d5c35e73d3df4b29d340e1a4c76d43b220c0f9535e77b43a74ff049ee7b89a4a38&token=1082669959&lang=zh_CN#rd)
-- [SpringBoot 整合 阿里云OSS 存储服务,快来免费搭建一个自己的图床](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484801&idx=1&sn=22d97f9c963d45820559d7226874e33f&chksm=cea24a4af9d5c35cac3177921801287b1ad983eabb6e18cf30302fc235b7f699401510ea2a59&token=1082669959&lang=zh_CN#rd)
-- [Spring Boot 实现热部署的一种简单方式](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485586&idx=2&sn=01788bf8c64de91d085a01c1f4f5159d&chksm=cea24759f9d5ce4fe914aa43e517f16b7f4066de3096be09d01500596ca63ad9f1eef4b8fffa&token=2133161636&lang=zh_CN#rd)
-- [SpringBoot 处理异常的几种常见姿势](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485568&idx=2&sn=c5ba880fd0c5d82e39531fa42cb036ac&chksm=cea2474bf9d5ce5dcbc6a5f6580198fdce4bc92ef577579183a729cb5d1430e4994720d59b34&token=2133161636&lang=zh_CN#rd)
-- [5分钟搞懂如何在Spring Boot中Schedule Tasks](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485563&idx=1&sn=7419341f04036a10b141b74624a3f8c9&chksm=cea247b0f9d5cea6440759e6d49b4e77d06f4c99470243a10c1463834e873ca90266413fbc92&token=2133161636&lang=zh_CN#rd)
-
-### MyBatis
-
-- [面试官:“谈谈MyBatis中都用到了那些设计模式?”。](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485369&idx=1&sn=a493d646e126cd1c19ce9f1fc9c724c9&chksm=cea24872f9d5c16462d82f033699d7ad3177964100f8c8958ce9b8e0872e246f552ae6ac423f&token=1667678311&lang=zh_CN#rd)
-
-## 数据库
-
-### MySQL
-
-- [MySQL知识点总结[修订版]](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485390&idx=1&sn=43511395093d2e0deb64f89c8af1805e&chksm=cea24805f9d5c113026292c7681238b1c65c09958588aa5c70e37249e384f5c965f87ef438ad&token=1667678311&lang=zh_CN#rd)
-- [【思维导图-索引篇】搞定数据库索引就是这么简单](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484848&idx=1&sn=77a0e6e82944ec385f5df17e91ce3bf2&chksm=cea24a7bf9d5c36d4b289cccb017292f9f36da9f3c887fd2b93ecd6af021fcf30121ba09799f&token=1082669959&lang=zh_CN#rd)
-- [一条SQL语句在MySQL中如何执行的](https://mp.weixin.qq.com/s/QU4-RSqVC88xRyMA31khMg)
-- [一文带你轻松搞懂事务隔离级别(图文详解)](https://mp.weixin.qq.com/s/WhK3SrkMDTj1_o2zp64ArQ)
-- [详记一次MySQL千万级大表优化过程!](https://mp.weixin.qq.com/s/SbpM_q_-nIKJn7_TSmrW8A)
-
-### Redis
-
-- [史上最全Redis高可用技术解决方案大全](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484850&idx=1&sn=3238360bfa8105cf758dcf7354af2814&chksm=cea24a79f9d5c36fb2399aafa91d7fb2699b5006d8d037fe8aaf2e5577ff20ae322868b04a87&token=1082669959&lang=zh_CN#rd)
-- [redis 总结——重构版](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484858&idx=1&sn=8e222ea6115e0b69cac91af14d2caf36&chksm=cea24a71f9d5c367148dccec3d5ddecf5ecd8ea096b5c5ec32f22080e66ac3c343e99151c9e0&token=1082669959&lang=zh_CN#rd)
-
-## 面试相关
-
-- [面试中常见的几道智力题 来看看你会做几道?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484923&idx=1&sn=e1fd890a1a7290f996dc8d7ca4b2d599&chksm=cea24a30f9d5c326f5498929decb7b2d9e39d8806b74c823ccf46fe9fba778d5d9aa644292db&token=1082669959&lang=zh_CN#rd)
-- [面试中常见的几道智力题 来看看你会做几道(2)?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484917&idx=1&sn=8587b384b42927618067c0e3a56083a9&chksm=cea24a3ef9d5c328a5fd97441de1ccfaf42f9296e5f491b1fa4be9422431d6f26dac36a75e16&token=1082669959&lang=zh_CN#rd)
-- [[算法总结] 搞定 BAT 面试——几道常见的子符串算法题](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484869&idx=1&sn=785d0dce653aa1abdbc542007da830e8&chksm=cea24a0ef9d5c31853ae1114844041f12daf88ef753fb019980e466f32922c50d332e1d1fc2c&token=1082669959&lang=zh_CN#rd)
-- [[BAT面试必备] ——几道常见的链表算法题](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484862&idx=1&sn=015a4eb2f66978010d68c1305a46cfb5&chksm=cea24a75f9d5c363683aadf3ac434b8baf9ff5be8d2939d7875ebb3a742780b568a0926a2cc4&token=1082669959&lang=zh_CN#rd)
-- [如何判断一个元素在亿级数据中是否存在?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484796&idx=1&sn=25c190a95ac53b81063f7acda936c994&chksm=cea24ab7f9d5c3a1819605008bfc92834eddf37ca3ad24b913fab558b5d00ed5306c5d6aab55&token=1082669959&lang=zh_CN#rd)
-- [可能是一份最适合你的后端面试指南(部分内容前端同样适用)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484840&idx=1&sn=cf4611ac290ae3cbb381fe52aa76b60b&chksm=cea24a63f9d5c375215f7539ff0f3d6320f091d5f8b73e95c724ec9a31d3b5baa98c3f5a1012&token=1082669959&lang=zh_CN#rd)
-- [GitHub 上四万 Star 大佬的求职回忆](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484802&idx=1&sn=58e204718559f6cf94d3d9cd9614ebc2&chksm=cea24a49f9d5c35f8d53f79801aea21fdd3c06ff4b6c16167e8211f627eea8c5a0ce334fd240&token=1082669959&lang=zh_CN#rd)
-- [这7个问题,可能大部分Java程序员都比较关心吧!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484786&idx=1&sn=4f61c62c0213602a106ce20db7768a93&chksm=cea24ab9f9d5c3afe7b5c90f6a8782adef93e916a46685aa8c46b752fddadf88273748c7f1ab&token=1082669959&lang=zh_CN#rd)
-- [2018年BATJ面试题精选](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484774&idx=1&sn=2aaaafcecd2bc6b519a11fa0fc1f66fa&chksm=cea24aadf9d5c3bb69359b0973930387885de75b444837df4f34ac14eebbabe498605660ae48&token=1082669959&lang=zh_CN#rd)
-- [一位大佬的亲身经历总结:简历和面试的技巧](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485409&idx=1&sn=47b09ec432929306d39762b13364b04b&chksm=cea2482af9d5c13cc91e8e679f0b823e667b616866519af1523d1d8b4e550cfdaa2f57b21bf3&token=1667678311&lang=zh_CN#rd)
-- [包装严重的IT行业,作为面试官,我是如何甄别应聘者的包装程度](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485404&idx=1&sn=b0c5b9e55bb6f7e71585c1b2e769fd87&chksm=cea24817f9d5c101cfa45a5d2707445030259f030d91f48c068450c5a280457ee25fa51b3f24&token=1667678311&lang=zh_CN#rd)
-- [面试官:你是如何使用JDK来实现自己的缓存(支持高并发)?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485347&idx=1&sn=8da3919089909d39dbf0745225ca0dad&chksm=cea24868f9d5c17eaec7eba2a4a3b63ed46dff87cb08b3f5d491e96890d8f375735cfcc77562&token=1667678311&lang=zh_CN#rd)
-
-### 面经
-
-- [5面阿里,终获offer](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484747&idx=1&sn=bff601fd1d314f670cb44171ea1925dd&chksm=cea24a80f9d5c396619acaa9f77207019f72d43749559b5a401359915e01b51598a687c48203&token=1082669959&lang=zh_CN#rd)
-- [记一次蚂蚁金服的面试经历](https://mp.weixin.qq.com/s/LIhtyspty9Kz1qRg1b8N-w)
-- [2019年蚂蚁金服、头条、拼多多的面试总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485167&idx=1&sn=a35fad235a6bb2b6e31f1ff37e72bfd7&chksm=cea24924f9d5c032cbbeffc87cd366e9aa7b209897a26ad5c7f7b1b766b3c34a2c9b6870006c&token=1667678311&lang=zh_CN#rd)
-- [蚂蚁金服2019实习生面经总结(已拿口头offer)](https://mp.weixin.qq.com/s/ktq2UOvi5qI1FymWIgp8jw)
-- [2019年蚂蚁金服面经(已拿Offer)!附答案!!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485251&idx=1&sn=21e5da0d76dd71d165f19015ebeba780&chksm=cea24888f9d5c19e041a145e6da3d4fa94f63b34c71d43f10c29340c7d51a4a23971904d19b5&token=1667678311&lang=zh_CN#rd)
-
-### 备战面试系列
-
-- [【备战春招/秋招系列】程序员的简历就该这样写](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484830&idx=1&sn=2e868311f79f4a52a0f3be383050c810&source=41#wechat_redirect)
-- [【备战春招/秋招系列】初出茅庐的程序员该如何准备面试?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484829&idx=1&sn=29e0e08d9da0f343f14c16bb3ac92beb&chksm=cea24a56f9d5c340ecb67a186b3c8fb5ef30ff481bfbdec3249f2145b3f376fd2d6dc19fbefc&token=1082669959&lang=zh_CN#rd)
-- [【备战春招/秋招系列】Java程序员必备书单](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484826&idx=1&sn=cf015aca00e420d476c3cb456a11d994&chksm=cea24a51f9d5c34730dcdb538c99cb58d23496ebe8c51fb191dd629ab28c802f97662aef3366&token=1082669959&lang=zh_CN#rd)
-- [【备战春招/秋招系列】面试官问你“有什么问题问我吗?”,你该如何回答?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484755&idx=1&sn=4a09256062642c714f83ed03cb083846&chksm=cea24a98f9d5c38e8e040c332bf58ccac48a93190e059b9f39e4249eae579b8d32238cea88dd&token=1082669959&lang=zh_CN#rd)
-- [【备战春招/秋招系列】美团面经总结基础篇 (附详解答案)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484825&idx=1&sn=a0ec65a5f2b268a6f4d22c3bb9790126&chksm=cea24a52f9d5c344922e4dcd4b9650d63ad5c4d843208e3fb7f21bcffa144a6bab0d748cdfbb&token=1082669959&lang=zh_CN#rd)
-- [【备战春招/秋招系列】美团面经总结进阶篇 (附详解答案)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484822&idx=1&sn=efefe8a5a1ff9a54a57601edab134a04&chksm=cea24a5df9d5c34b36e8b12beb574ca31ae771de3881237c4f02be61b52e38f763d2d6137dd3&token=1082669959&lang=zh_CN#rd)
-- [【备战春招/秋招系列】美团Java面经总结终结篇 (附详解答案)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484815&idx=1&sn=4dd1a280fb95c59366c73897c77049fb&chksm=cea24a44f9d5c3524b301ecf313382ea78b6ac821b4d5e9f9cf51346fc10839c1e234e7cb3ed&token=1082669959&lang=zh_CN#rd)
-
-### 面试现场
-
-- [【面试现场】如何实现可以获取最小值的栈?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484863&idx=2&sn=ac674bb0cf29b782aa0e6e9365defa4b&chksm=cea24a74f9d5c362b22459ceda77e635366a17175cd30bbdce14bc729e5417b137175a90331b&token=1082669959&lang=zh_CN#rd)
-- [【面试现场】为什么要分稳定排序和非稳定排序?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484856&idx=2&sn=af47a53a913b42b064a6e158d165fd2f&chksm=cea24a73f9d5c365084c65d30372f1ae35893ad3ec751da71e14ce5fda07b17ab5f0da90f663&token=1082669959&lang=zh_CN#rd)
-- [【面试现场】如何找到字符串中的最长回文子串?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484855&idx=1&sn=e75a06c56fe3b8802f18b04ef4df1c43&chksm=cea24a7cf9d5c36ab8090506442fa131a3d332343e953567c5f78dbef5aed0b6ed317b25af9f&token=1082669959&lang=zh_CN#rd)
-- [【面试现场】如何在10亿数中找出前1000大的数](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484845&idx=1&sn=6a235c6181c0f46630a9a22ef762a23b&chksm=cea24a66f9d5c3709e9618a1e418535d467053273123b81fda3897b4431a02a105703fd22644&token=1082669959&lang=zh_CN#rd)
-
-## 算法
-
-- [【算法技巧】位运算装逼指南](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485292&idx=1&sn=330e7f8c972bd7ed368aca7ccb434493&chksm=cea248a7f9d5c1b1f5387adbda961f0aa02c6f575fd9367937b9c15be1b241222b340f61dc5e&token=1667678311&lang=zh_CN#rd)
-
-## Github 热门Java项目推荐
-
-- [近几个月Github上最热门的Java项目一览](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484908&idx=1&sn=a95d37194f03b7e4aae1612e1785bf44&chksm=cea24a27f9d5c331d818fa1b2b564f9d5e9ff245a969a50e98944b909d6e45c0ebde544f982e&token=1082669959&lang=zh_CN#rd)(2018-07-20)
-- [推荐10个Java方向最热门的开源项目(8月)](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484876&idx=1&sn=3cab92ee5bda6b47bf7232724461f6a3&chksm=cea24a07f9d5c31106d0806b1bd8bae8821511b0a32879fb4f4b3bec7823db1f62e23821b07b&token=1082669959&lang=zh_CN#rd)( 2018-08-28)
-- [Github上 Star 数相加超过 7w+ 的三个面试相关的仓库推荐](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484819&idx=1&sn=6d83101ee504a6ab19ef07fb32650876&chksm=cea24a58f9d5c34ef9f3a7374c5147b1ff85e18ca4e59e21c4edf7d63bc1bd8c5c241e0c532b&token=1082669959&lang=zh_CN#rd)( 2018-11-17)
-- [11月 Github Trending 榜最热门的 10 个 Java 项目](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484805&idx=1&sn=acee5bd6c3f861c65be3a2fb8843e1f5&chksm=cea24a4ef9d5c358c263cb4605acc6b6254635c28c496a9a10aee0dc80293f457a9af2e90d1c&token=1082669959&lang=zh_CN#rd)( 2018-12-01)
-- [盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484789&idx=1&sn=2ad9fabb8fc7fae3bd3756ea05594344&chksm=cea24abef9d5c3a889b6cb8e00cb18abbb694d189c84a24fa1ed337ad4c56194cd39316dc6a5&token=1082669959&lang=zh_CN#rd)( 2018-12-24)
-- [12月GithubTrending榜Java项目总结,多了几个新面孔](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484784&idx=1&sn=3c98b2e6aa97014a8fb4bf837be40f52&chksm=cea24abbf9d5c3ad3ab779749f6a75ed9bc4321986056a65f5f04033c9cc626a382ebe597278&token=1082669959&lang=zh_CN#rd)(2019-01-02)
-- [1月份Github上收获最多star的10个项目](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484761&idx=1&sn=db6441c08f5ae8d75978384108cc852d&chksm=cea24a92f9d5c3846858a91aa7dc6b258f91407e2a22a1c7b2e46a8e5dd4d9a9ef443eed3b0e&token=1082669959&lang=zh_CN#rd)(2019-02-01)
-- [2019年2月份Github上收获最多Star的10个Java项目](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484749&idx=1&sn=a66a1e3707839454539d93499dcadfad&chksm=cea24a86f9d5c3902d07fc4614347606200536ddf9ee7464fe12bbbce5c1bd186ad9894f13e3&token=1082669959&lang=zh_CN#rd)(2019-03-05)
-- [3月Github最热门的10个Java开源项目](https://mp.weixin.qq.com/s/HYXFWeko2tGPCWhy-yrtEw)
-- [五一假期充电指南:4月Github最热门的Java项目推荐](https://mp.weixin.qq.com/s/3485Z0cbD1FvcWZMQTnRsw)
-
-## 架构
-
-- [8 张图读懂大型网站技术架构](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484863&idx=1&sn=8b7c8ce77f5927564d69587688114c79&chksm=cea24a74f9d5c362b7140d18bfc198e7f39572b938e597d1725e4dcf541a12b33d8db6ac1b45&token=1082669959&lang=zh_CN#rd)
-- [【面试精选】关于大型网站系统架构你不得不懂的10个问题](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484760&idx=1&sn=c41df36f538ab3d8907e23bf8f6d2cd5&chksm=cea24a93f9d5c3851f8a699fdf068f767e3571c38e1b2995297a3e5725f9ad024c6de2bcb100&token=1082669959&lang=zh_CN#rd)
-- [分布式系统的经典基础理论](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484941&idx=1&sn=e0812a9ccfde06550e24c23c4bb5ef1d&chksm=cea249c6f9d5c0d0bd16fc26c7af606c775868f1f06d81fbff2f8093d2a686c3b3befe9b971c&token=1082669959&lang=zh_CN#rd)
-- [软件开发的七条原则](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484938&idx=1&sn=597b1aec42d22caad051b3694816fb27&chksm=cea249c1f9d5c0d73bcedc02499cb44822f6b5ab9dcccd7f1a03f830aed158a1b9abec416efc&token=1082669959&lang=zh_CN#rd)
-- [关于分布式计算的一些概念](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484935&idx=2&sn=2394583a73b41cca431e392a28b0b4cb&chksm=cea249ccf9d5c0da5d1d4b8cf2dffb00ae1b6b605afe6da426112f3208898c2cca6249865146&token=1082669959&lang=zh_CN#rd)
-
-## 工具
-
-- [Git入门看这一篇就够了!](https://mp.weixin.qq.com/s/ylyHOuEPX4tDvOc7-SxMmw)
-- [团队开发中的 Git 实践](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485550&idx=1&sn=a0fa847b009c3c8c60c20773f0870dbf&chksm=cea247a5f9d5ceb317906f37d7dfbd44aebbe2206764cd8b50a25110c3125c7be3507ce3729e&token=2133161636&lang=zh_CN#rd)
-- [IDEA中的Git操作,看这一篇就够了!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485578&idx=1&sn=8f8ab9d597e1448053e5da380fff3e54&chksm=cea24741f9d5ce5791722dd3da12dfa3de5aa9d742e0cc78d0b72a89d75a48e6d84512265c30&token=2133161636&lang=zh_CN#rd)
-- [一文搞懂如何在Intellij IDEA中使用Debug,超级详细!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485250&idx=1&sn=9e1f270996441094104a06fc909c60f5&chksm=cea24889f9d5c19fbc6024779ca476a3ee141efa457fc86cc8c33a8f06a1c2b1e7b4922426c2&token=1667678311&lang=zh_CN#rd)
-- [十分钟搞懂Java效率工具Lombok使用与原理](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485385&idx=2&sn=a7c3fb4485ffd8c019e5541e9b1580cd&chksm=cea24802f9d5c1144eee0da52cfc0cc5e8ee3590990de3bb642df4d4b2a8cd07f12dd54947b9&token=913106598&lang=zh_CN&scene=21#wechat_redirect)
-
-## 效率
-
-- [推荐几个可以提升工作效率的Chrome插件](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485315&idx=1&sn=f5e91a9386a6911acbff4d7721065563&chksm=cea24848f9d5c15ec3bc0efab93351ca7481a609e901d9c9c07816a7a9737cdcdc1b5f6497db&token=1667678311&lang=zh_CN#rd)
-
-## 思维开阔
-
-- [不就是个短信登录API嘛,有这么复杂吗?](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485181&idx=1&sn=7a7a7ce0671e8c5456add8da098501c2&chksm=cea24936f9d5c020fa1e339a819a17e7ae6099f1c5072d9ea235cf9fca45437d96cb117f7f10&token=1667678311&lang=zh_CN#rd)
-
-## 进阶
-
-- [可能是把Docker的概念讲的最清楚的一篇文章](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484921&idx=1&sn=d40518712a04b3c37d7c8fcd3e696e90&chksm=cea24a32f9d5c3243db78a227ba4e77618e679bbc856cf1974fccbd474c44847672f21658147&token=1082669959&lang=zh_CN#rd)
-- [后端必备——数据通信知识(RPC、消息队列)一站式总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484920&idx=1&sn=c7167df0b36522935896565973d02cc9&chksm=cea24a33f9d5c325fc663c95ebc221060ae2d5eeee254472558a99fdfc2837b31d3b9ae51a12&token=1082669959&lang=zh_CN#rd)
-- [可能是全网把 ZooKeeper 概念讲的最清楚的一篇文章](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484868&idx=1&sn=af1e49c5f7dc89355255a4d46bafc005&chksm=cea24a0ff9d5c3195a690d2c85f09cd8901717674f52e10b0e6fd588d69de15de76b8184307d&token=1082669959&lang=zh_CN#rd)
-- [外行人都能看懂的SpringCloud,错过了血亏!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484813&idx=1&sn=d87c01aff031f35be6b88a61f5782da5&chksm=cea24a46f9d5c35023a54e20fa1319b4cd31c33b094e2fd161bb8667ab77b8b403af62cfb3b5&token=1082669959&lang=zh_CN#rd)
-- [关于 Dubbo 的重要入门知识点总结](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484753&idx=1&sn=32d987bf9f6208e30326877b111cad61&chksm=cea24a9af9d5c38cc7eb4d9bfeaa07e72003a1bf304a0fedc3fabb2a87f01c98b5a7d1c80d53&token=1082669959&lang=zh_CN#rd)
-- [Java 工程师成神之路 | 2019正式版](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484759&idx=1&sn=5a706091c1db2b585f0a93c75bca14da&chksm=cea24a9cf9d5c38a245bdc63a0c90934b02f582c34a8dfb4ef01cd149d4829d799cb9e9bd464&token=1082669959&lang=zh_CN#rd)
-- [聊一聊开发常用小工具](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484769&idx=1&sn=0968ce79f4d31d982b9f1ce24b051432&chksm=cea24aaaf9d5c3bc5feb0ef4e814990c9e108b72a0691193b1dda29642ee2ff74da5026016f6&token=1082669959&lang=zh_CN#rd)
-- [新手也能看懂,消息队列其实很简单](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484794&idx=1&sn=61585fe69eedb3654ee2f9c9cd67e1a1&chksm=cea24ab1f9d5c3a7fd07dd49244f69fc85a5a523ee5353fc9e442dcad2ca0dd1137ed563fcbe&token=1082669959&lang=zh_CN#rd)
-
-## 杂文闲记
-
-- [一只准准程序员的唠叨](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484932&idx=1&sn=a4f3057ecd4412cb8b18e92058b29680&chksm=cea249cff9d5c0d97580310f6666a4e0c42cfd1ba13dd759850e489c9386dce8c5c35b0a1a95&token=1082669959&lang=zh_CN#rd)(2018-06-09)
-- [说几件近期的小事](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484900&idx=1&sn=745e8f6027da369ef5f8e349cb5d6657&chksm=cea24a2ff9d5c339c925322ffacdc72dd37bda63238dfb3452540085c1695681e2e79070e2a7&token=1082669959&lang=zh_CN#rd)(2018-08-02)
-- [选择技术方向都要考虑哪些因素](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484898&idx=1&sn=fd2ebf9ffd37ab5de1de09cd3272ac0a&chksm=cea24a29f9d5c33fa48f5a57de864cd9382a730578fb18d78b7f06b45504aede18b235b9bc9e&token=1082669959&lang=zh_CN#rd)(2018-08-04)
-- [结束了我短暂的秋招,说点自己的感受](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484842&idx=1&sn=4489dfab0ef2479122b71407855afc71&chksm=cea24a61f9d5c3774a8ed67c5fcc3234cb0741fbe831152986e5d1c8fb4f36a003f4fb2f247e&token=1082669959&lang=zh_CN#rd)(2018-10-22)
-- [【周日闲谈】最近想说的几件小事](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484818&idx=1&sn=e14b0a08537456eb15ba49cf5e70ff74&chksm=cea24a59f9d5c34fe0a9e0567d867b85a81d1f19b0ea8e6a3c14161e436508de9adfeb2a5e6a&token=1082669959&lang=zh_CN#rd)(2018-11-18)
-- [做公众号这一年的经历和一件“大事”](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484746&idx=1&sn=a519a9e3d638bff5c65008f7de167e4b&chksm=cea24a81f9d5c397ca9ac5668ba6cb18b38065e0e282a34ebc077a2dea98de3f1eb285ea5f09&token=1082669959&lang=zh_CN#rd)(2019-03-10)
-- [几经周折,公众号终于留言功能啦!](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485007&idx=1&sn=096a436cd6a9251c23b8effc3cfa5076&chksm=cea24984f9d5c092d1f7740d1c3e0ea347562ba0aa597507ce275c5bdf1c8bd608328ee756ba&token=1082669959&lang=zh_CN#rd)(2019-03-15)
-- [写在毕业季的大学总结!细数一下大学干过的“傻事”。](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485358&idx=1&sn=3aaf1163fe13351e06c76b70f2bd33bd&chksm=cea24865f9d5c1735b51c707c8f5ade16af7eca304540205ab0fb1284f99034d418b9858d7db&token=1667678311&lang=zh_CN#rd) (2019-06-11)
-- [入职一个月的职场小白,谈谈自己这段时间的感受](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485540&idx=1&sn=4492eece8f7738e99350118040e14a79&chksm=cea247aff9d5ceb9e7c67f418d8a8518c550fd7dd269bf2c9bdef83309502273b4b9f1e7021f&token=1333232257&lang=zh_CN&scene=21#wechat_redirect)
-
-## 其他好文推荐
-
-- [谈恋爱也要懂https](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484821&idx=1&sn=e6ce4ec607a6c9b20edbd64fbeb0f6c5&chksm=cea24a5ef9d5c3480d3de284fc1038b51c2464152e25a350960efd81acd21f71d7e0eeb78c77&token=1082669959&lang=zh_CN#rd)
-- [快速入门大厂后端面试必备的 Shell 编程](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484810&idx=1&sn=0b622ae617b863ef1cc3a32c17b8b755&chksm=cea24a41f9d5c357199073c1e4692b7da7dcbd1809cf634a6cfec8c64c12250efc5274992f06&token=1082669959&lang=zh_CN#rd)
-- [为什么阿里巴巴禁止工程师直接使用日志系统(Log4j、Logback)中的 API](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484808&idx=1&sn=4774ecc18069e4ddc85f68877cff1ae3&chksm=cea24a43f9d5c35520a454d51e72c6084d38f505969835011f4dd36f76c78303af46780802c9&token=1082669959&lang=zh_CN#rd)
-- [一文搞懂 RabbitMQ 的重要概念以及安装](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484792&idx=1&sn=d34fdbb6cb21c231361038a7317ac2a4&chksm=cea24ab3f9d5c3a5c742de10cd0f7c77425b2144c86d2515d3e5d2011f4d16af12110c2de986&token=1082669959&lang=zh_CN#rd)
-- [漫话:如何给女朋友解释什么是RPC](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484795&idx=1&sn=64eb2dcac07cf6904ca79b14f408df9e&chksm=cea24ab0f9d5c3a6970c3fbbdcaa16d5230b51abed9bacd1cd2ea3192cccea4aba0ef2d1a9de&token=1082669959&lang=zh_CN#rd)
-- [Java人才市场年度盘点:转折与终局](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484779&idx=1&sn=a930b09a1783bca68e927cbe7d7a54a6&chksm=cea24aa0f9d5c3b6864ab3585a4cc5de1fa89ffc07538f2c55382776bfee0c369d7d74af7c79&token=1082669959&lang=zh_CN#rd)
-- [Github 上日获 800多 star 的阿里微服务架构分布式事务解决方案 FESCAR开源啦](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484776&idx=2&sn=bcd1cf6d72653bfff83724f1dbae0425&chksm=cea24aa3f9d5c3b5e9667f1e15f295d323efb3b2c8da6c9059f5e8b5e176b9cb1bf80cd1a78f&token=1082669959&lang=zh_CN#rd)
-- [Cloud Toolkit新版本发布,开发效率 “biu” 起来了](https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484771&idx=2&sn=0eef929baacca950099ea8651f0e5cb2&chksm=cea24aa8f9d5c3bed5f359e6da981ac950dca8f31a93f1fe321d7de7908d843855604e79a4da&token=1082669959&lang=zh_CN#rd)
-- [我觉得技术人员该有的提问方式](https://mp.weixin.qq.com/s/eTEah5WOdfC3EAPbhpOKBA)
\ No newline at end of file
diff --git a/index.html b/index.html
old mode 100644
new mode 100755
index 6b0768a5feb..8f2161cb0cb
--- a/index.html
+++ b/index.html
@@ -1,77 +1,92 @@
-
-
-
-
-
- JavaGuide
-
-
-
-
-
-
-
-
-
-
- 图解计算机基础
- 知识星球
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
+
+ JavaGuide
+
+
+
+
+
+
+
+
+
+
+ 图解计算机基础
+ 知识星球
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git "a/media/pictures/database/B+\346\240\221.png" "b/media/pictures/database/B+\346\240\221.png"
deleted file mode 100644
index 4261da2af77..00000000000
Binary files "a/media/pictures/database/B+\346\240\221.png" and /dev/null differ
diff --git "a/media/pictures/database/B+\346\240\221\344\272\214\347\272\247\347\264\242\345\274\225(\350\276\205\345\212\251\347\264\242\345\274\225).png" "b/media/pictures/database/B+\346\240\221\344\272\214\347\272\247\347\264\242\345\274\225(\350\276\205\345\212\251\347\264\242\345\274\225).png"
deleted file mode 100644
index 8ffc07767a1..00000000000
Binary files "a/media/pictures/database/B+\346\240\221\344\272\214\347\272\247\347\264\242\345\274\225(\350\276\205\345\212\251\347\264\242\345\274\225).png" and /dev/null differ
diff --git "a/media/pictures/database/B+\346\240\221\347\264\242\345\274\225.png" "b/media/pictures/database/B+\346\240\221\347\264\242\345\274\225.png"
deleted file mode 100644
index ddbf2fc1cef..00000000000
Binary files "a/media/pictures/database/B+\346\240\221\347\264\242\345\274\225.png" and /dev/null differ
diff --git "a/media/pictures/database/B+\346\240\221\350\246\206\347\233\226\347\264\242\345\274\225.png" "b/media/pictures/database/B+\346\240\221\350\246\206\347\233\226\347\264\242\345\274\225.png"
deleted file mode 100644
index 2bb74ea358a..00000000000
Binary files "a/media/pictures/database/B+\346\240\221\350\246\206\347\233\226\347\264\242\345\274\225.png" and /dev/null differ
diff --git "a/media/pictures/database/Mysql\347\264\242\345\274\225\346\226\207\344\273\266\346\210\252\345\233\276.png" "b/media/pictures/database/Mysql\347\264\242\345\274\225\346\226\207\344\273\266\346\210\252\345\233\276.png"
deleted file mode 100644
index 1c77319e1a2..00000000000
Binary files "a/media/pictures/database/Mysql\347\264\242\345\274\225\346\226\207\344\273\266\346\210\252\345\233\276.png" and /dev/null differ
diff --git "a/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225(\345\244\232\345\210\227\347\264\242\345\274\225).png" "b/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225(\345\244\232\345\210\227\347\264\242\345\274\225).png"
deleted file mode 100644
index bdc3118497f..00000000000
Binary files "a/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225(\345\244\232\345\210\227\347\264\242\345\274\225).png" and /dev/null differ
diff --git "a/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225\344\271\213\346\237\245\350\257\242\346\235\241\344\273\266\347\224\237\346\225\210.png" "b/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225\344\271\213\346\237\245\350\257\242\346\235\241\344\273\266\347\224\237\346\225\210.png"
deleted file mode 100644
index e88d5436a13..00000000000
Binary files "a/media/pictures/database/\350\201\224\345\220\210\347\264\242\345\274\225\344\271\213\346\237\245\350\257\242\346\235\241\344\273\266\347\224\237\346\225\210.png" and /dev/null differ
diff --git a/media/pictures/jvm/java_jvm_compose_garbage_collector.png b/media/pictures/jvm/java_jvm_compose_garbage_collector.png
deleted file mode 100644
index 5f8729c5294..00000000000
Binary files a/media/pictures/jvm/java_jvm_compose_garbage_collector.png and /dev/null differ
diff --git a/media/pictures/jvm/java_jvm_garbage_collector_parameters.png b/media/pictures/jvm/java_jvm_garbage_collector_parameters.png
deleted file mode 100644
index 6116bfb60cf..00000000000
Binary files a/media/pictures/jvm/java_jvm_garbage_collector_parameters.png and /dev/null differ
diff --git a/media/pictures/jvm/java_jvm_heap_parameters.png b/media/pictures/jvm/java_jvm_heap_parameters.png
deleted file mode 100644
index 06d906c87ad..00000000000
Binary files a/media/pictures/jvm/java_jvm_heap_parameters.png and /dev/null differ
diff --git a/media/pictures/jvm/java_jvm_suggest_parameters.png b/media/pictures/jvm/java_jvm_suggest_parameters.png
deleted file mode 100644
index 55ca4f42c3c..00000000000
Binary files a/media/pictures/jvm/java_jvm_suggest_parameters.png and /dev/null differ
diff --git a/package.json b/package.json
new file mode 100644
index 00000000000..066b4c57fb2
--- /dev/null
+++ b/package.json
@@ -0,0 +1,16 @@
+{
+ "name": "javaguide-blog",
+ "version": "1.0.0",
+ "description": "A project of vuepress-theme-hope",
+ "license": "MIT",
+ "scripts": {
+ "build": "vuepress build docs",
+ "clean-dev": "vuepress dev docs --no-cache",
+ "dev": "vuepress dev docs",
+ "eject-theme": "vuepress eject-hope docs"
+ },
+ "devDependencies": {
+ "vuepress": "^1.8.2",
+ "vuepress-theme-hope": "^1.20.5"
+ }
+}
diff --git a/submission.html b/submission.html
deleted file mode 100644
index b291af73d07..00000000000
--- a/submission.html
+++ /dev/null
@@ -1,231 +0,0 @@
-
-
-
-
-Untitled
-
-
-前言 如果你有不错的大厂面试经历
如果你对某一个Java知识点有过深刻的见解和记录
如果你有什么学习编程的经验分享给其他人
......
如果你想,你都可以把这些整理成文章投稿给我,你的文章将被更多人看到,你所写的东西也可能会默默影响到很多人。
欢迎的文章类型 本公众号主要接受下面几类文章投稿:
大厂Java面试经历、面试总结、面试注意事项等等 对某一个Java知识点的深刻讲解 技术热点 一些行业内不错的人物或者公司传记 ...... 因为本公众号主要是Java方向,所以还有其他Java方向的文章都可以投稿。
投稿的要求很简单,你能把一个知识点讲清楚就好,JavaGuide 里面还有很多知识点没有加,我觉得都是不错的方向(内容我会帮你完善)。 这个投稿的目的是完善开源项目 JavaGuide 的同时能够让大家自主去学习并总结知识点。
奖励 投稿自己的原创文章成功之后不仅可以顺利加入32k+star 的开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide 扩大自己的竞争力,还会有50元左右的任意书籍或者50元现金奖励(对于不错的文章会更高)。
投稿方式 下面 2 种方式都可以
将你的文章以 Markdown 格式发送到我的邮箱:koushuangbwcx@163.com ; 直接在 Github : https://github.com/Snailclimb/JavaGuide 提PR也可以 。 如果你也是公众号号主,你也有自己不错的文章想投稿给我的话,虽然你不会有奖励,但是发了你的文章之后,肯定会为你带来一些新人关注。
-
-
\ No newline at end of file