目录
1. synchronized 关键字的用法
synchronized 关键字主要是用于对其引用所指向的对象进行加锁
1. synchronized 关键字可以用来修饰方法定义
// 修饰实例方法
public synchronized void method() {
}
// 修饰静态方法
public static synchronized void sMethod() {
}
2. synchronized 关键字用来修饰代码块
Object o = new Object();
// synchronized 后面的括号里跟着指向对象的引用, 引用不能为 null
synchronized (o) {
}
synchronized (this) {
}
// 反射中, 指向当前类对象
synchronized (Math.class) {
}
2. 理解使用 synchronized 关键字
- synchronized (引用), 代表对当前"引用"所指的对象 进行加锁
- 一个线程在对一个引用所指的对象进行加锁时, 需要先判断该锁是否已经被占用, 若未被占用, 就可以进行加锁, 代表请求锁成功.
- 若请求锁失败, 该线程就会放弃 CPU 且放弃抢占 CPU 的资格, 从而进入到阻塞态(BLOCKED 状态 -----> 专门为 synchronized 所设计的一种阻塞状态), 等待锁的释放
3. 理解同步
对于多线程而言, 有线程间一定的干扰就是同步, 而线程间毫无联系就是异步
通常情况下, synchronized 修饰的方法就称为同步方法. 它可以使多个线程之间产生同步效果(通过加锁产生同步效果)
- 对实例方法加锁:
public synchronized void method() {
}
// 二者是等价的
public void method() {
synchronized (this) {
}
}
- 对静态方法加锁
public static synchronized void sMethod() {
}
// 二者是等价的
public static void sMethod() {
synchronized (类名.class) {
}
}
4. 怎样判断线程之间是否同步
1. 调用的方法是否都有加锁动作
2. 加锁加的是否是同一把锁(同一个对象)
5. 使用 synchronized 关键字怎样解决代码中的线程不安全隐患
无论什么方法, 解决代码中线程不安全隐患都需要从 原子性/内存可见性/代码重排序 三个角度出发
使用了synchronized 关键字
- 从原子行角度讲:
线程从请求锁成功到释放锁的这一过程中, 保证了原子性 - 从内存可见性角度讲:
(1). 请求锁成功后, JVM 会刷新线程的工作内存, 从而保证线程读到的数据是最新的
(2). 释放锁后, JVM 会将线程工作内存中的数据, 刷新回主内存中, 从而保证其他线程在读取工作内存中的数据时是最新的数据 - 从代码重排序角度讲:
对于 A, B, C三部分而言, 其各自内部可以随意重排序, 但是每一部分不能重排序其余部分