synchronized 介绍
概述
synchronized
是 Java 语言中的一个关键字,用于控制对共享资源的访问。它可以修饰方法、代码块或类,确保同一时刻只有一个线程可以执行被修饰的代码。
底层原理
synchronized
的底层原理是使用锁(Lock)来实现互斥访问。每个对象都拥有一个互斥锁,当一个线程获取对象的锁之后,其他线程试图获取该锁时会阻塞,直到该线程释放锁。
JDK 1.7 和 JDK 1.8 中的 synchronized 区别
JDK 1.7 synchronized 的底层实现
在 JDK 1.7 中,synchronized
的底层实现使用的是 “重量级锁”(heavyweight lock)。它是一种基于操作系统互斥锁的实现。
具体实现过程如下:
- 当一个线程试图进入一个
synchronized
代码块时,会先尝试获取对象的锁。 - 如果锁是可用的,则线程会成功获取锁并进入代码块。
- 如果锁已经被其他线程持有,则当前线程会阻塞,直到该线程释放锁。
- 线程执行完
synchronized
代码块后,会释放锁。
重量级锁的实现细节:
- 重量级锁使用的是 “互斥锁”(Mutex) 来实现。互斥锁是一种操作系统提供的同步机制,可以保证同一时刻只有一个线程可以持有锁。
- 每个对象都拥有一个互斥锁,称为 “监视器锁”(monitor lock)。
- 线程获取锁的操作称为 “加锁”(lock),释放锁的操作称为 “解锁”(unlock)。
重量级锁的缺点:
- 重量级锁的实现比较复杂,会带来一定的性能开销。
- 重量级锁是全局性的,也就是说,即使只有一个线程需要访问共享资源,也需要获取整个对象的锁,这可能会导致其他线程的阻塞。
JDK 1.8 synchronized 的底层实现:
在 JDK 1.8 中,synchronized 的底层实现依赖于对象的 “对象头”(object header)。对象头是对象内部存储的一部分数据,用于存储对象的运行时信息,包括锁信息、哈希码、GC 信息等。
对象头的结构:
- Mark Word: 存储对象的锁信息,包括锁标志、偏向锁信息、轻量级锁信息等。
- Klass Word: 存储对象的类型信息,指向对象的类元数据。
- 其他信息: 存储对象的哈希码、GC 信息等。
锁标志:
- 锁标志是一个 32 位的比特位,用于表示对象的锁状态。
- 锁标志的低 16 位表示对象的锁状态,包括无锁、偏向锁、轻量级锁、重量级锁等。
- 锁标志的高 16 位表示对象的哈希码。
偏向锁:
- 偏向锁是一种优化手段,在没有竞争的情况下,直接将锁分配给第一个获取锁的线程。
- 偏向锁的信息存储在锁标志的低 4 位中。
轻量级锁:
- 轻量级锁是一种优化手段,使用 CAS 操作来实现互斥访问。
- 轻量级锁的信息存储在锁标志的低 12 位中。
重量级锁:
- 重量级锁是一种传统的锁实现,使用操作系统互斥锁来实现。
- 当锁升级为重量级锁时,会使用对象的监视器锁。
总结:
在 JDK 1.7 中,synchronized
使用的是 “重量级锁”(heavyweight lock),它是一种基于操作系统互斥锁的实现。重量级锁的实现比较复杂,会带来一定的性能开销。
在 JDK 1.8 中,synchronized
引入了 “轻量级锁”(lightweight lock) 和 “偏向锁”(biased lock) 两种优化手段。轻量级锁使用的是 CAS 操作来实现互斥访问,性能比重量级锁更高。偏向锁则是在没有竞争的情况下,直接将锁分配给第一个获取锁的线程,进一步提高性能。
synchronized 的使用:
synchronized 可以修饰方法、代码块或类。
- 修饰方法: 表示整个方法都加锁
- 修饰代码块: 表示只对代码块中的代码加锁
- 修饰类: 表示对类的所有静态方法和静态变量加锁
synchronized 的示例:
Java
public class SynchronizedExample {
private static int count = 0;
public static void main(String[] args) {
// 使用 synchronized 修饰方法
synchronized void increment() {
count++;
}
// 使用 synchronized 修饰代码块
synchronized (this) {
count++;
}
// 使用 synchronized 修饰类
synchronized (SynchronizedExample.class) {
count++;
}
}
}
synchronized 的替代方案:
- ReentrantLock: 可重入锁,可以避免死锁
- ReadWriteLock: 读写锁,可以提高读操作的性能
- StampedLock: 戳锁,可以提高性能和灵活性
总结
synchronized
是 Java 语言中一种重要的同步机制,可以有效地保证共享资源的访问安全。在 JDK 1.8 中,synchronized
进行了优化,性能得到了进一步提升。Java 中提供了其他一些同步机制,例如 ReentrantLock
、Semaphore
和 java.util.concurrent
包中的并发类。