|
@@ -1,25 +1,25 @@
|
|
|
## 为什么wait和notify必须放在synchronized中?
|
|
|
|
|
|
-在Java中,wait()和notify()是Object类的两个方法,它们用于实现线程间的协作。wait()使一个线程进入等待状态,直到另一个线程发出通知唤醒它。而notify()则用于唤醒正在等待的线程。
|
|
|
+在Java中,`wait()`和`notify()`是`Object`类的两个方法,它们用于实现线程间的协作。`wait()`使一个线程进入等待状态,直到另一个线程发出通知唤醒它。而notify()则用于唤醒正在等待的线程。
|
|
|
|
|
|
-wait()和notify()必须放在synchronized块中是因为这些方法依赖于对象的监视器锁(也称为互斥锁)。只有获得了对象的监视器锁(该锁即为调用wait方法的对象)的线程才能调用wait()和notify()方法。如果这些方法不在同步块中使用,就无法保证线程安全性。
|
|
|
+`wait()`和`notify()`必须放在`synchronized`块中是因为这些方法依赖于对象的监视器锁(也称为互斥锁)。只有获得了对象的监视器锁(该锁即为调用`wait`方法的对象)的线程才能调用`wait()`和`notify()`方法。如果这些方法不在同步块中使用,就无法保证线程安全性。
|
|
|
|
|
|
-当一个线程调用wait()方法时,它会释放持有的锁并进入等待状态,等待其他线程调用notify()方法来唤醒它。如果wait()方法不在同步块中使用,那么该线程在释放锁之后可能已经被其他线程修改了。这样,即使其他线程调用了notify()方法唤醒了它,该线程也无法正确地处理唤醒事件。
|
|
|
+当一个线程调用`wait()`方法时,它会释放持有的锁并进入等待状态,等待其他线程调用`notify()`方法来唤醒它。如果`wait()`方法不在同步块中使用,那么该线程在释放锁之后可能已经被其他线程修改了。这样,即使其他线程调用了`notify()`方法唤醒了它,该线程也无法正确地处理唤醒事件。
|
|
|
|
|
|
-同样,notify()方法也必须在同步块中使用。如果一个线程在未获得锁的情况下调用notify()方法,那么它将无法通知任何等待的线程。因为它没有获取锁,所以它不能访问共享数据或执行必要的同步操作来确保正确的通知。
|
|
|
+同样,`notify()`方法也必须在同步块中使用。如果一个线程在未获得锁的情况下调用`notify()`方法,那么它将无法通知任何等待的线程。因为它没有获取锁,所以它不能访问共享数据或执行必要的同步操作来确保正确的通知。
|
|
|
|
|
|
-因此,使用wait()和notify()方法时,必须在同步块中使用它们,以确保线程之间的安全性并避免出现竞态条件。
|
|
|
+因此,使用`wait()`和`notify()`方法时,必须在同步块中使用它们,以确保线程之间的安全性并避免出现竞态条件。
|
|
|
|
|
|
## volatile 关键字
|
|
|
|
|
|
-在Java中,volatile关键字是用于保证多线程环境下变量的可见性和有序性。
|
|
|
+在Java中,`volatile`关键字是用于保证多线程环境下变量的可见性和有序性。
|
|
|
|
|
|
-1. 保证变量可见性:被volatile关键字声明代表变量是共享且不稳定的,每次使用它都到主存中进行读取,并且强制刷新到内存。
|
|
|
-2. 保证变量有序性:JVM 具有指令重排的特性,可以保证程序执行效率更高,但是volatile关键字会进制指令重排保证其有序性。
|
|
|
+1. 保证变量可见性:被`volatile`关键字声明代表变量是共享且不稳定的,每次使用它都到主存中进行读取,并且强制刷新到内存。
|
|
|
+2. 保证变量有序性:JVM 具有指令重排的特性,可以保证程序执行效率更高,但是`volatile`关键字会禁止指令重排保证其有序性。
|
|
|
|
|
|
## volatile 关键字底层原理
|
|
|
|
|
|
-`volatile`是通过编译器在生成字节码时,在指令序列中添加“**内存屏障**”来保证变量可见性。
|
|
|
+`volatile`是通过编译器在生成字节码时,在指令序列中添加**内存屏障**来保证变量可见性。
|
|
|
|
|
|
JMM层面的“**内存屏障**”:
|
|
|
|
|
@@ -38,15 +38,15 @@ JVM的实现会在volatile读写前后均加上内存屏障,在一定程度上
|
|
|
> **volatile 写操作**
|
|
|
> **StoreLoad**
|
|
|
|
|
|
-**禁止指令重排,汇编层面**
|
|
|
+禁止指令重排,汇编层面
|
|
|
|
|
|
-> **lock 前缀**:lock不是内存屏障,而是一种锁。执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU
|
|
|
+> **lock 前缀:lock不是内存屏障,而是一种锁。执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU**
|
|
|
|
|
|
## synchronized 关键字
|
|
|
|
|
|
`synchronized` 是 Java 中的一个关键字,翻译成中文是同步的意思,主要解决的是多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。
|
|
|
|
|
|
-在JDK1.6之前synchronized关键字基于操作系统mutux互斥变量实现,该操作较为重量级,但是在JDK1.6之后进行的JVM层面的锁优化。效率大大提升,优化后的锁主要分为一下四类
|
|
|
+在JDK1.6之前`synchronized`关键字基于操作系统`mutux`互斥变量实现,该操作较为重量级,但是在JDK1.6之后进行的JVM层面的锁优化。效率大大提升,优化后的锁主要分为一下四类
|
|
|
|
|
|
1. 无锁状态
|
|
|
2. 偏向锁状态
|
|
@@ -63,11 +63,11 @@ JVM的实现会在volatile读写前后均加上内存屏障,在一定程度上
|
|
|
|
|
|
* `volatile` 关键字是线程同步的轻量级实现,所以性能肯定比`synchronized`关键字要好 。
|
|
|
|
|
|
-* `volatile` 关键字只能用于变量而 `synchronized` 关键字可以修饰方法以及代码块 。
|
|
|
+* `volatile` 关键字只能作用于变量,而 `synchronized` 关键字可以修饰方法以及代码块 。
|
|
|
|
|
|
-* `volatile` 关键字能保证数据的可见性,但不能保证数据的原子性。`synchronized` 关键字两者都能保证。
|
|
|
+* `volatile` 关键字能保证数据的可见性。而`synchronized` 关键字能保证数据原子性。
|
|
|
|
|
|
-* `volatile`关键字主要用于解决变量在多个线程之间的可见性,而 `synchronized` 关键字解决的是多个线程之间访问资源的同步性。
|
|
|
+* `volatile` 关键字主要用于解决变量在多个线程之间的可见性,而 `synchronized` 关键字解决的是多个线程之间访问资源的同步性。
|
|
|
|
|
|
## ReentrantLock锁
|
|
|
|
|
@@ -158,8 +158,6 @@ AQS提供了一种通用的框架,用于实现线程间的协作和同步操
|
|
|
* **`ThreadPoolExecutor.DiscardPolicy`:** 不处理新任务,直接丢弃掉。
|
|
|
* **`ThreadPoolExecutor.DiscardOldestPolicy`:** 此策略将丢弃最早的未处理的任务请求。
|
|
|
|
|
|
-我们这里使用自定义的饱和策略,即为新建一个线程去处理饱和任务
|
|
|
-
|
|
|
### 如何设定线程池的大小?
|
|
|
|
|
|
* **CPU 密集型任务(N+1)**
|