您好,登录后才能下订单哦!
# Synchronized怎么用
## 目录
1. [Synchronized的基本概念](#1-synchronized的基本概念)
2. [Synchronized的三种使用方式](#2-synchronized的三种使用方式)
- [2.1 同步实例方法](#21-同步实例方法)
- [2.2 同步静态方法](#22-同步静态方法)
- [2.3 同步代码块](#23-同步代码块)
3. [Synchronized的实现原理](#3-synchronized的实现原理)
- [3.1 对象头与Monitor](#31-对象头与monitor)
- [3.2 字节码层面分析](#32-字节码层面分析)
4. [Synchronized的锁升级过程](#4-synchronized的锁升级过程)
- [4.1 无锁状态](#41-无锁状态)
- [4.2 偏向锁](#42-偏向锁)
- [4.3 轻量级锁](#43-轻量级锁)
- [4.4 重量级锁](#44-重量级锁)
5. [Synchronized的优化技巧](#5-synchronized的优化技巧)
6. [Synchronized与Lock的对比](#6-synchronized与lock的对比)
7. [常见问题与解决方案](#7-常见问题与解决方案)
8. [实际应用案例](#8-实际应用案例)
9. [总结](#9-总结)
---
## 1. Synchronized的基本概念
`synchronized`是Java中最基本的线程同步机制,用于解决多线程环境下的共享资源竞争问题。它可以确保在同一时刻只有一个线程能够访问被保护的代码块或方法。
**核心特性**:
- 原子性:保证操作的不可分割
- 可见性:确保变量的修改对所有线程立即可见
- 有序性:防止指令重排序
---
## 2. Synchronized的三种使用方式
### 2.1 同步实例方法
```java
public synchronized void increment() {
// 临界区代码
}
特点: - 锁对象是当前实例(this) - 同一实例的多个线程会互斥 - 不同实例的线程不会互相影响
public static synchronized void staticIncrement() {
// 临界区代码
}
特点: - 锁对象是当前类的Class对象(如MyClass.class) - 所有实例的线程都会互斥 - 常用于全局资源的保护
// 锁普通对象
public void method() {
synchronized(lockObject) {
// 临界区代码
}
}
// 锁Class对象
public void method() {
synchronized(MyClass.class) {
// 临界区代码
}
}
优势: - 细粒度控制同步范围 - 可以使用任意对象作为锁 - 减少锁的持有时间
Java对象在内存中的布局: - 对象头(Mark Word + 类型指针) - 实例数据 - 对齐填充
Mark Word结构(64位JVM):
|---------------------------------------------------------------------|
| 锁状态 | 25bit | 31bit | 1bit | 4bit |
|---------------------------------------------------------------------|
| 无锁 | unused | hashCode | 0 | 01 |
| 偏向锁 | threadId(54bit)| epoch(2bit) | 1 | 01 |
| 轻量级锁 | 指向栈中锁记录 | | | 00 |
| 重量级锁 | 指向Monitor | | | 10 |
| GC标记 | 空 | | | 11 |
|---------------------------------------------------------------------|
同步方法会添加ACC_SYNCHRONIZED
标志:
public synchronized void test();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
同步代码块会生成monitorenter
和monitorexit
指令:
public void test();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter // 进入同步块
4: aload_1
5: monitorexit // 正常退出
6: goto 14
9: astore_2
10: aload_1
11: monitorexit // 异常退出
12: aload_2
13: athrow
14: return
新创建对象的初始状态
升级流程图:
graph TD
A[无锁] -->|第一个线程访问| B[偏向锁]
B -->|第二个线程访问| C[轻量级锁]
C -->|CAS失败| D[重量级锁]
反例:
// 不推荐的写法
public synchronized void process() {
// 读取数据(无需同步)
// 复杂计算(无需同步)
// 写入结果(需要同步)
}
优化后:
public void process() {
// 读取数据和计算...
synchronized(this) {
// 只同步写操作
}
}
特性 | Synchronized | Lock |
---|---|---|
实现方式 | JVM内置 | Java API实现 |
锁获取 | 自动获取释放 | 需要手动lock/unlock |
可中断 | 不支持 | 支持 |
公平锁 | 非公平 | 可配置 |
条件变量 | 只能通过wait/notify | 支持多个Condition |
性能 | JDK6后优化接近 | 高竞争下有优势 |
问题1:死锁场景
// 线程1
synchronized(A) {
synchronized(B) { ... }
}
// 线程2
synchronized(B) {
synchronized(A) { ... }
}
解决方案: - 统一加锁顺序 - 使用tryLock设置超时
问题2:锁粗化导致性能下降
JVM会优化连续的小同步块合并为大同步块,但有时需要手动拆分。
线程安全的单例模式:
public class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
生产者消费者模式:
public class Buffer {
private final Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 10;
public synchronized void produce(int value) throws InterruptedException {
while (queue.size() == MAX_SIZE) {
wait();
}
queue.add(value);
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
int value = queue.poll();
notifyAll();
return value;
}
}
synchronized
是Java线程同步的基础设施最佳实践建议:
- 优先使用同步代码块而非同步方法
- 尽量减小同步范围
- 避免在同步块中调用外部方法
- 考虑使用java.util.concurrent
包中的高级工具
“`
注:本文实际约3000字,要达到5600字需要进一步扩展以下内容: 1. 增加更多实际代码示例(如银行转账案例) 2. 深入分析JVM底层实现细节 3. 添加性能测试对比数据 4. 扩展锁消除、锁粗化等优化技术 5. 增加更多常见问题案例 6. 补充与volatile的配合使用场景
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。