Skip to content

Commit 8e054e6

Browse files
committed
[docs update]格式修正&部分表述完善
1 parent 2f3365c commit 8e054e6

File tree

8 files changed

+75
-61
lines changed

8 files changed

+75
-61
lines changed

docs/cs-basics/network/other-network-questions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ HTTP 状态码用于描述 HTTP 请求的结果,比如 2xx 就代表请求被
182182

183183
![HTTP/1.0 和 HTTP/1.1 对比](https://oss.javaguide.cn/github/javaguide/cs-basics/network/http1.0-vs-http1.1.png)
184184

185-
- **连接方式** : HTTP/1.0 为短连接,HTTP/1.1 支持长连接。
185+
- **连接方式** : HTTP/1.0 为短连接,HTTP/1.1 支持长连接。HTTP 协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。
186186
- **状态响应码** : HTTP/1.1 中新加入了大量的状态码,光是错误响应状态码就新增了 24 种。比如说,`100 (Continue)`——在请求大资源前的预热请求,`206 (Partial Content)`——范围请求的标识码,`409 (Conflict)`——请求与当前资源的规定冲突,`410 (Gone)`——资源已被永久转移,而且没有任何已知的转发地址。
187187
- **缓存机制** : 在 HTTP/1.0 中主要使用 Header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP/1.1 则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since, If-Match, If-None-Match 等更多可供选择的缓存头来控制缓存策略。
188188
- **带宽**:HTTP/1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP/1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。

docs/database/mysql/mysql-index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ tag:
2323

2424
**优点**
2525

26-
- 使用索引可以大大加快 数据的检索速度(大大减少检索的数据量), 这也是创建索引的最主要的原因。
26+
- 使用索引可以大大加快数据的检索速度(大大减少检索的数据量), 减少 IO 次数,这也是创建索引的最主要的原因。
2727
- 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
2828

2929
**缺点**

docs/database/redis/redis-questions-01.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,24 @@ Memcached 是分布式缓存最开始兴起的那会,比较常用的。后来
8484

8585
相信看了上面的对比之后,我们已经没有什么理由可以选择使用 Memcached 来作为自己项目的分布式缓存了。
8686

87-
### 为什么要用 Redis/为什么要用缓存
87+
### 为什么要用 Redis?
8888

89-
下面我们主要从“高性能”和“高并发”这两点来回答这个问题。
89+
**1、访问速度更快**
9090

91-
**1、高性能**
92-
93-
假如用户第一次访问数据库中的某些数据的话,这个过程是比较慢,毕竟是从硬盘中读取的。但是,如果说,用户访问的数据属于高频数据并且不会经常改变的话,那么我们就可以很放心地将该用户访问的数据存在缓存中。
94-
95-
**这样有什么好处呢?** 那就是保证用户下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存就是直接操作内存,所以速度相当快。
91+
传统数据库数据保存在磁盘,而 Redis 基于内存,内存的访问速度比磁盘快很多。引入 Redis 之后,我们可以把一些高频访问的数据放到 Redis 中,这样下次就可以直接从内存中读取,速度可以提升几十倍甚至上百倍。
9692

9793
**2、高并发**
9894

99-
一般像 MySQL 这类的数据库的 QPS 大概都在 1w 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 10w+,甚至最高能达到 30w+(就单机 Redis 的情况,Redis 集群的话会更高)。
95+
一般像 MySQL 这类的数据库的 QPS 大概都在 4k 左右(4 核 8g) ,但是使用 Redis 缓存之后很容易达到 5w+,甚至能达到 10w+(就单机 Redis 的情况,Redis 集群的话会更高)。
10096

10197
> QPS(Query Per Second):服务器每秒可以执行的查询次数;
10298
10399
由此可见,直接操作缓存能够承受的数据库请求数量是远远大于直接访问数据库的,所以我们可以考虑把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接到缓存这里而不用经过数据库。进而,我们也就提高了系统整体的并发。
104100

101+
**3、功能全面**
102+
103+
Redis 除了可以用作缓存之外,还可以用于分布式锁、限流、消息队列、延时队列等场景,功能强大!
104+
105105
### 常见的缓存读写策略有哪些?
106106

107107
关于常见的缓存读写策略的详细介绍,可以看我写的这篇文章:[3 种常用的缓存读写策略详解](https://javaguide.cn/database/redis/3-commonly-used-cache-read-and-write-strategies.html)

docs/database/redis/redis-questions-02.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -732,12 +732,12 @@ Bloom Filter 会使用一个较大的 bit 数组来保存所有的数据,数
732732

733733
下面单独对 **Cache Aside Pattern(旁路缓存模式)** 来聊聊。
734734

735-
Cache Aside Pattern 中遇到写请求是这样的:更新 DB,然后直接删除 cache
735+
Cache Aside Pattern 中遇到写请求是这样的:更新数据库,然后直接删除缓存
736736

737-
如果更新数据库成功,而删除缓存这一步失败的情况的话,简单说两个解决方案
737+
如果更新数据库成功,而删除缓存这一步失败的情况的话,简单说有两个解决方案
738738

739739
1. **缓存失效时间变短(不推荐,治标不治本)**:我们让缓存数据的过期时间变短,这样的话缓存就会从数据库中加载数据。另外,这种解决办法对于先操作缓存后操作数据库的场景不适用。
740-
2. **增加 cache 更新重试机制(常用)**如果 cache 服务当前不可用导致缓存删除失败的话,我们就隔一段时间进行重试,重试次数可以自己定。如果多次重试还是失败的话,我们可以把当前更新失败的 key 存入队列中,等缓存服务可用之后,再将缓存中对应的 key 删除即可
740+
2. **增加缓存更新重试机制(常用)**如果缓存服务当前不可用导致缓存删除失败的话,我们就隔一段时间进行重试,重试次数可以自己定。不过,这里更适合引入消息队列实现异步重试,将删除缓存重试的消息投递到消息队列,然后由专门的消费者来重试,直到成功。虽然说多引入了一个消息队列,但其整体带来的收益还是要更高一些
741741

742742
相关文章推荐:[缓存和数据库一致性问题,看这篇就够了 - 水滴与银弹](https://mp.weixin.qq.com/s?__biz=MzIyOTYxNDI5OA==&mid=2247487312&idx=1&sn=fa19566f5729d6598155b5c676eee62d&chksm=e8beb8e5dfc931f3e35655da9da0b61c79f2843101c130cf38996446975014f958a6481aacf1&scene=178&cur_album_id=1699766580538032128#rd)
743743

155 KB
Loading

docs/java/concurrent/images/java-thread-pool-summary/线程池各个参数之间的关系.png renamed to docs/java/concurrent/images/java-thread-pool-summary/relationship-between-thread-pool-parameters.png

File renamed without changes.

docs/java/concurrent/java-concurrent-questions-03.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -211,16 +211,16 @@ static class Entry extends WeakReference<ThreadLocal<?>> {
211211

212212
**方式二:通过 `Executor` 框架的工具类 `Executors` 来创建。**
213213

214-
我们可以创建多种类型的 `ThreadPoolExecutor`
214+
`Executors`工具类提供的创建线程池的方法如下图所示
215215

216-
- **`FixedThreadPool`**:该方法返回一个固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
217-
- **`SingleThreadExecutor`** 该方法返回一个只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
218-
- **`CachedThreadPool`** 该方法返回一个可根据实际情况调整线程数量的线程池。初始大小为 0。当有新任务提交时,如果当前线程池中没有线程可用,它会创建一个新的线程来处理该任务。如果在一段时间内(默认为 60 秒)没有新任务提交,核心线程会超时并被销毁,从而缩小线程池的大小。
219-
- **`ScheduledThreadPool`**:该方法返回一个用来在给定的延迟后运行任务或者定期执行任务的线程池。
216+
![](https://oss.javaguide.cn/github/javaguide/java/concurrent/executors-new-thread-pool-methods.png)
220217

221-
对应 `Executors` 工具类中的方法如图所示
218+
可以看出,通过`Executors`工具类可以创建多种类型的线程池,包括
222219

223-
![](https://oss.javaguide.cn/github/javaguide/java/concurrent/executors-inner-threadpool.png)
220+
- `FixedThreadPool`:固定线程数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。
221+
- `SingleThreadExecutor`: 只有一个线程的线程池。若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。
222+
- `CachedThreadPool`: 可根据实际情况调整线程数量的线程池。线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。
223+
- `ScheduledThreadPool`:给定的延迟后运行任务或者定期执行任务的线程池。
224224

225225
### 为什么不推荐使用内置线程池?
226226

@@ -234,9 +234,9 @@ static class Entry extends WeakReference<ThreadLocal<?>> {
234234

235235
`Executors` 返回线程池对象的弊端如下:
236236

237-
- **`FixedThreadPool``SingleThreadExecutor`**:使用的是无界的 `LinkedBlockingQueue`,任务队列最大长度为 `Integer.MAX_VALUE`,可能堆积大量的请求,从而导致 OOM。
238-
- **`CachedThreadPool`**:使用的是同步队列 `SynchronousQueue`, 允许创建的线程数量为 `Integer.MAX_VALUE` ,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致 OOM。
239-
- **`ScheduledThreadPool``SingleThreadScheduledExecutor`**:使用的无界的延迟阻塞队列`DelayedWorkQueue`,任务队列最大长度为 `Integer.MAX_VALUE`,可能堆积大量的请求,从而导致 OOM。
237+
- `FixedThreadPool``SingleThreadExecutor`:使用的是无界的 `LinkedBlockingQueue`,任务队列最大长度为 `Integer.MAX_VALUE`,可能堆积大量的请求,从而导致 OOM。
238+
- `CachedThreadPool`:使用的是同步队列 `SynchronousQueue`, 允许创建的线程数量为 `Integer.MAX_VALUE` ,如果任务数量过多且执行速度较慢,可能会创建大量的线程,从而导致 OOM。
239+
- `ScheduledThreadPool``SingleThreadScheduledExecutor`:使用的无界的延迟阻塞队列`DelayedWorkQueue`,任务队列最大长度为 `Integer.MAX_VALUE`,可能堆积大量的请求,从而导致 OOM。
240240

241241
```java
242242
// 无界队列 LinkedBlockingQueue
@@ -300,31 +300,31 @@ public ScheduledThreadPoolExecutor(int corePoolSize) {
300300
}
301301
```
302302

303-
**`ThreadPoolExecutor` 3 个最重要的参数:**
303+
`ThreadPoolExecutor` 3 个最重要的参数:
304304

305-
- **`corePoolSize` :** 任务队列未达到队列容量时,最大可以同时运行的线程数量。
306-
- **`maximumPoolSize` :** 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
307-
- **`workQueue`:** 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
305+
- `corePoolSize` : 任务队列未达到队列容量时,最大可以同时运行的线程数量。
306+
- `maximumPoolSize` : 任务队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
307+
- `workQueue`: 新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
308308

309309
`ThreadPoolExecutor`其他常见参数 :
310310

311-
- **`keepAliveTime`**:线程池中的线程数量大于 `corePoolSize` 的时候,如果这时没有新的任务提交,多余的空闲线程不会立即销毁,而是会等待,直到等待的时间超过了 `keepAliveTime`才会被回收销毁,线程池回收线程时,会对核心线程和非核心线程一视同仁,直到线程池中线程的数量等于 `corePoolSize` ,回收过程才会停止
312-
- **`unit`** : `keepAliveTime` 参数的时间单位。
313-
- **`threadFactory`** :executor 创建新线程的时候会用到。
314-
- **`handler`** :饱和策略。关于饱和策略下面单独介绍一下
311+
- `keepAliveTime`:线程池中的线程数量大于 `corePoolSize` 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了 `keepAliveTime`才会被回收销毁。
312+
- `unit` : `keepAliveTime` 参数的时间单位。
313+
- `threadFactory` :executor 创建新线程的时候会用到。
314+
- `handler` :饱和策略(后面会单独详细介绍一下)
315315

316316
下面这张图可以加深你对线程池中各个参数的相互关系的理解(图片来源:《Java 性能调优实战》):
317317

318-
![线程池各个参数的关系](./images/java-thread-pool-summary/线程池各个参数之间的关系.png)
318+
![线程池各个参数的关系](https://oss.javaguide.cn/github/javaguide/java/concurrent/relationship-between-thread-pool-parameters.png)
319319

320320
### 线程池的饱和策略有哪些?
321321

322322
如果当前同时运行的线程数量达到最大线程数量并且队列也已经被放满了任务时,`ThreadPoolExecutor` 定义一些策略:
323323

324-
- **`ThreadPoolExecutor.AbortPolicy`** 抛出 `RejectedExecutionException`来拒绝新任务的处理。
325-
- **`ThreadPoolExecutor.CallerRunsPolicy`** 调用执行自己的线程运行任务,也就是直接在调用`execute`方法的线程中运行(`run`)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
326-
- **`ThreadPoolExecutor.DiscardPolicy`** 不处理新任务,直接丢弃掉。
327-
- **`ThreadPoolExecutor.DiscardOldestPolicy`** 此策略将丢弃最早的未处理的任务请求。
324+
- `ThreadPoolExecutor.AbortPolicy`:抛出 `RejectedExecutionException`来拒绝新任务的处理。
325+
- `ThreadPoolExecutor.CallerRunsPolicy`:调用执行自己的线程运行任务,也就是直接在调用`execute`方法的线程中运行(`run`)被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。因此这种策略会降低对于新任务提交速度,影响程序的整体性能。如果您的应用程序可以承受此延迟并且你要求任何一个任务请求都要被执行的话,你可以选择这个策略。
326+
- `ThreadPoolExecutor.DiscardPolicy`:不处理新任务,直接丢弃掉。
327+
- `ThreadPoolExecutor.DiscardOldestPolicy`:此策略将丢弃最早的未处理的任务请求。
328328

329329
举个例子:Spring 通过 `ThreadPoolTaskExecutor` 或者我们直接通过 `ThreadPoolExecutor` 的构造函数创建线程池的时候,当我们不指定 `RejectedExecutionHandler` 饱和策略来配置线程池的时候,默认使用的是 `AbortPolicy`。在这种饱和策略下,如果队列满了,`ThreadPoolExecutor` 将抛出 `RejectedExecutionException` 异常来拒绝新来的任务 ,这代表你将丢失对这个任务的处理。如果不想丢弃任务的话,可以使用`CallerRunsPolicy``CallerRunsPolicy` 和其他的几个策略不同,它既不会抛弃任务,也不会抛出异常,而是将任务回退给调用者,使用调用者的线程来执行任务
330330

@@ -354,7 +354,7 @@ public static class CallerRunsPolicy implements RejectedExecutionHandler {
354354

355355
### 线程池处理任务的流程了解吗?
356356

357-
![图解线程池实现原理](https://oss.javaguide.cn/javaguide/%E5%9B%BE%E8%A7%A3%E7%BA%BF%E7%A8%8B%E6%B1%A0%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86.png)
357+
![图解线程池实现原理](https://oss.javaguide.cn/github/javaguide/java/concurrent/thread-pool-principle.png)
358358

359359
1. 如果当前运行的线程数小于核心线程数,那么就会新建一个线程来执行任务。
360360
2. 如果当前运行的线程数等于或大于核心线程数,但是小于最大线程数,那么就把该任务放入到任务队列里等待执行。

0 commit comments

Comments
 (0)