网站首页 > 文章精选 正文
synchronized 是 Java 语言中一种用于实现线程同步的关键字,它通过监视器锁(Monitor Lock)来确保多个线程在同一时间只能有一个线程执行被 synchronized 关键字修饰的方法或代码块。synchronized 可以用于方法、静态方法和代码块,并能确保同一时间内对某个共享资源的操作是线程安全的。
synchronized 的使用
synchronized 关键字的使用主要有三种方式:
- 实例方法上的同步:持有的是对象锁(Object Lock)。
public synchronized void instanceMethod() {
// 线程安全的实例方法
}
- 静态方法上的同步:持有的是类锁(Class Lock)。
public static synchronized void staticMethod() {
// 线程安全的静态方法
}
- 代码块上的同步:可以对任意对象加锁。
public void method() {
synchronized (this) {
// 线程安全的代码块
}
}
public void methodWithCustomLock() {
Object lockObject = new Object();
synchronized (lockObject) {
// 线程安全的代码块
}
}
synchronized 的工作原理
synchronized 关键字基于监视器锁(Monitor Lock)实现底层同步机制。具体来说,它依赖于 Java 对象头 中的 Monitor(监视器)来管理锁的状态。每个对象都有一个监视器,当一个线程进入同步方法或代码块时,它会获取该对象的监视器,而当退出时,它会释放监视器。
JVM 实现原理
synchronized 的真正实现依靠 JVM 完成。下面我将深入分析其工作机制。
对象头
在 HotSpot JVM 中,对象头包含以下两部分:
- Mark Word:这是一个非常复杂的结构,用于存储对象的运行时数据,包括哈希码、GC状态、锁信息等。
- Class Metadata Address:指向对象的类信息。
具体来说,当对象被 synchronized 修饰时,Mark Word 中的内容会变化以反映当前锁的状态。
锁的状态
锁的状态随着竞争程度的不同而升级,共有四种状态:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态。
- 无锁状态(Unlocked):对象创建初始状态,Mark Word中存储的是对象的哈希码。
- 偏向锁状态(Biased Locking):偏向锁优化用于减少无竞争加锁的开销,通过将锁偏向第一个成功获取它的线程。
- 轻量级锁状态(Lightweight Locking):当偏向锁被另一个线程获取时,升级为轻量级锁。轻量级锁通过CAS(Compare-And-Swap)操作尝试加锁。
- 重量级锁状态(Heavyweight Locking):当轻量级锁竞争失败时,升级为重量级锁。重量级锁是通过操作系统的互斥量(Mutex)来实现的,会导致线程挂起和唤醒,代价较高。
锁升级过程如下图所示:
无锁状态 -> 偏向锁状态 -> 轻量级锁状态 -> 重量级锁状态
进入和退出同步块
在字节码层面,Java 的同步由 monitorenter 和 monitorexit 指令实现。每个 synchronized 代码块都会被编译成这些字节码指令。
- 进入同步块(monitorenter):线程尝试获取对象的监视器。如果成功,则进入同步块,否则线程将被阻塞。
- 退出同步块(monitorexit):线程释放对象的监视器。如果有其他线程在等待该监视器,则唤醒它们。
在 JVM 执行时,将会检查对象头中 Mark Word 的状态,并根据对象当前的锁状态进行相应的处理,例如获取锁、升级锁等。
示例代码和分析
下面是一个关于 synchronized 关键字的示例,展示了它如何用于实例方法、静态方法和代码块上的同步:
public class SynchronizedExample {
private int count = 0;
// 实例方法上的同步
public synchronized void increment() {
count++;
}
// 静态方法上的同步
public static synchronized void staticIncrement() {
// 静态变量的操作
}
// 代码块上的同步
public void blockIncrement() {
synchronized (this) {
count++;
}
}
// 多线程环境下测试
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
example.increment();
}
};
Thread thread1 = new Thread(task);
Thread thread2 = new Thread(task);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.count); // 期望值 2000
}
}
总结
- synchronized 是Java用于实现线程同步的关键字,确保在同一时间只有一个线程执行被修饰的方法或代码块。
- 它基于监视器锁实现,同步的底层机制依赖于对象头中的 Mark Word。
- 锁随着竞争程度的不同可以升级,从无锁状态到偏向锁、轻量级锁和重量级锁。
- JVM 使用 monitorenter 和 monitorexit 指令实现同步的进入和退出过程。
通过理解synchronized的工作原理和实际应用,可以更好地编写线程安全的Java代码,也能有效地在需要时进行性能优化。希望这篇文章对你理解synchronized有所帮助。
猜你喜欢
- 2024-12-26 Java高级:条件队列与同步器Synchronizer的原理+AQS的应用
- 2024-12-26 浅谈Java多线程与并发原理 java多线程并发调用接口
- 2024-12-26 Java 基础(四)集合源码解析 List java集合linkedlist
- 2024-12-26 synchronized和lock的区别 54.synchronized 和 lock 有什么区别?
- 2024-12-26 异步 vs 同步:程序员必备的核心知识,理解这两者差异,你就是高手
- 2024-12-26 ArrayList 、 LinkedList、Vector的区别
- 2024-12-26 java面试基础题(实战后的总结) java面试必考300题
- 2024-12-26 synchronized底层细究(硬核) synchronized底层原理是什么
- 2024-12-26 为什么 95% 的 Java 程序员,都是用不好 Synchronized?
- 2024-12-26 100+道高频Java面试题 java面试高频知识点
- 最近发表
- 标签列表
-
- newcoder (56)
- 字符串的长度是指 (45)
- drawcontours()参数说明 (60)
- unsignedshortint (59)
- postman并发请求 (47)
- python列表删除 (50)
- 左程云什么水平 (56)
- 计算机网络的拓扑结构是指() (45)
- 稳压管的稳压区是工作在什么区 (45)
- 编程题 (64)
- postgresql默认端口 (66)
- 数据库的概念模型独立于 (48)
- 产生系统死锁的原因可能是由于 (51)
- 数据库中只存放视图的 (62)
- 在vi中退出不保存的命令是 (53)
- 哪个命令可以将普通用户转换成超级用户 (49)
- noscript标签的作用 (48)
- 联合利华网申 (49)
- swagger和postman (46)
- 结构化程序设计主要强调 (53)
- 172.1 (57)
- apipostwebsocket (47)
- 唯品会后台 (61)
- 简历助手 (56)
- offshow (61)