@@ -286,7 +286,7 @@ JDK1.6 对锁的实现引入了大量的优化,如偏向锁、轻量级锁、
286
286
### 2.3. 并发编程的三个重要特性
287
287
288
288
1 . ** 原子性** : 一个的操作或者多次操作,要么所有的操作全部都得到执行并且不会收到任何因素的干扰而中断,要么所有的操作都执行,要么都不执行。` synchronized ` 可以保证代码片段的原子性。
289
- 2 . ** 可见性** :当一个变量对共享变量进行了修改 ,那么另外的线程都是立即可以看到修改后的最新值。` volatile ` 关键字可以保证共享变量的可见性。
289
+ 2 . ** 可见性** :当一个线程对共享变量进行了修改 ,那么另外的线程都是立即可以看到修改后的最新值。` volatile ` 关键字可以保证共享变量的可见性。
290
290
3 . ** 有序性** :代码在执行的过程中的先后顺序,Java 在编译器以及运行期间的优化,代码的执行顺序未必就是编写代码时候的顺序。` volatile ` 关键字可以禁止指令进行重排序优化。
291
291
292
292
### 2.4. 说说 synchronized 关键字和 volatile 关键字的区别
@@ -465,14 +465,14 @@ static class Entry extends WeakReference<ThreadLocal<?>> {
465
465
466
466
### 4.1. 为什么要用线程池?
467
467
468
- > ** 池化技术相比大家已经屡见不鲜了 ,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。**
468
+ > ** 池化技术想必大家已经屡见不鲜了 ,线程池、数据库连接池、Http 连接池等等都是对这个思想的应用。池化技术的思想主要是为了减少每次获取资源的消耗,提高对资源的利用率。**
469
469
470
470
** 线程池** 提供了一种限制和管理资源(包括执行一个任务)。 每个** 线程池** 还维护一些基本统计信息,例如已完成任务的数量。
471
471
472
472
这里借用《Java 并发编程的艺术》提到的来说一下** 使用线程池的好处** :
473
473
474
474
- ** 降低资源消耗** 。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
475
- - ** 提高响应速度** 。当任务到达时,任务可以不需要的等到线程创建就能立即执行 。
475
+ - ** 提高响应速度** 。当任务到达时,任务可以不需要等到线程创建就能立即执行 。
476
476
- ** 提高线程的可管理性** 。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
477
477
478
478
### 4.2. 实现 Runnable 接口和 Callable 接口的区别
@@ -601,7 +601,7 @@ public ThreadPoolExecutor(int corePoolSize,
601
601
602
602
** ` ThreadPoolExecutor ` 3 个最重要的参数:**
603
603
604
- - ** ` corePoolSize ` :** 核心线程数线程数定义了最小可以同时运行的线程数量 。
604
+ - ** ` corePoolSize ` :** 核心线程数定义了最小可以同时运行的线程数量 。
605
605
- ** ` maximumPoolSize ` :** 当队列中存放的任务达到队列容量的时候,当前可以同时运行的线程数量变为最大线程数。
606
606
- ** ` workQueue ` :** 当新任务来的时候会先判断当前运行的线程数量是否达到核心线程数,如果达到的话,新任务就会被存放在队列中。
607
607
@@ -803,7 +803,7 @@ public void execute(Runnable command) {
803
803
804
804
![ 图解线程池实现原理] ( images/java线程池学习总结/图解线程池实现原理.png )
805
805
806
- 现在,让我们在回到 4.6 节我们写的 Demo, 现在应该是不是很容易就可以搞懂它的原理了呢 ?
806
+ 现在,让我们在回到 4.6 节我们写的 Demo, 现在是不是很容易就可以搞懂它的原理了呢 ?
807
807
808
808
没搞懂的话,也没关系,可以看看我的分析:
809
809
@@ -919,7 +919,7 @@ AQS 的全称为(`AbstractQueuedSynchronizer`),这个类在` java.util.con
919
919
920
920
![ AQS类] ( https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/AQS类.png )
921
921
922
- AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出应用广泛的大量的同步器 ,比如我们提到的 ` ReentrantLock ` ,` Semaphore ` ,其他的诸如 ` ReentrantReadWriteLock ` ,` SynchronousQueue ` ,` FutureTask ` 等等皆是基于 AQS 的。当然,我们自己也能利用 AQS 非常轻松容易地构造出符合我们自己需求的同步器。
922
+ AQS 是一个用来构建锁和同步器的框架,使用 AQS 能简单且高效地构造出大量应用广泛的同步器 ,比如我们提到的 ` ReentrantLock ` ,` Semaphore ` ,其他的诸如 ` ReentrantReadWriteLock ` ,` SynchronousQueue ` ,` FutureTask ` 等等皆是基于 AQS 的。当然,我们自己也能利用 AQS 非常轻松容易地构造出符合我们自己需求的同步器。
923
923
924
924
### 6.2. AQS 原理分析
925
925
@@ -933,7 +933,7 @@ AQS 原理这部分参考了部分博客,在 5.2 节末尾放了链接。
933
933
934
934
** AQS 核心思想是,如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制 AQS 是用 CLH 队列锁实现的,即将暂时获取不到锁的线程加入到队列中。**
935
935
936
- > CLH(Craig,Landin, and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。
936
+ > CLH(Craig,Landin and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。
937
937
938
938
看个 AQS(AbstractQueuedSynchronizer)原理图:
939
939
0 commit comments