您好,登录后才能下订单哦!
# Java中Synchronized的原理及应用
## 目录
1. [引言](#引言)
2. [Synchronized的基本概念](#synchronized的基本概念)
- 2.1 [什么是Synchronized](#什么是synchronized)
- 2.2 [为什么需要同步](#为什么需要同步)
3. [Synchronized的实现原理](#synchronized的实现原理)
- 3.1 [JVM层面的实现](#jvm层面的实现)
- 3.2 [对象头与Monitor](#对象头与monitor)
- 3.3 [锁升级过程](#锁升级过程)
4. [Synchronized的使用方式](#synchronized的使用方式)
- 4.1 [同步方法](#同步方法)
- 4.2 [同步代码块](#同步代码块)
- 4.3 [静态同步方法](#静态同步方法)
5. [Synchronized的性能优化](#synchronized的性能优化)
- 5.1 [锁消除](#锁消除)
- 5.2 [锁粗化](#锁粗化)
- 5.3 [偏向锁与轻量级锁](#偏向锁与轻量级锁)
6. [Synchronized的典型应用场景](#synchronized的典型应用场景)
- 6.1 [单例模式](#单例模式)
- 6.2 [线程安全集合](#线程安全集合)
- 6.3 [资源池管理](#资源池管理)
7. [Synchronized与其他同步机制对比](#synchronized与其他同步机制对比)
- 7.1 [与ReentrantLock对比](#与reentrantlock对比)
- 7.2 [与Volatile对比](#与volatile对比)
8. [Synchronized的常见问题与解决方案](#synchronized的常见问题与解决方案)
- 8.1 [死锁问题](#死锁问题)
- 8.2 [性能瓶颈](#性能瓶颈)
- 8.3 [错误使用场景](#错误使用场景)
9. [Synchronized在JDK中的演进](#synchronized在jdk中的演进)
10. [总结与最佳实践](#总结与最佳实践)
## 引言
在多线程编程中,线程安全是核心问题之一。Java提供了`synchronized`关键字作为内置的同步机制,用于解决多线程环境下的数据竞争问题。本文将深入剖析`synchronized`的实现原理、使用方式、优化策略以及实际应用场景。
## Synchronized的基本概念
### 什么是Synchronized
`synchronized`是Java中的关键字,用于实现线程同步:
- 保证同一时刻只有一个线程可以执行特定代码段
- 确保变量的可见性和操作原子性
- 是可重入锁(Reentrant Lock)
### 为什么需要同步
多线程环境下会出现三大问题:
1. **竞态条件**:多个线程同时修改共享数据
2. **内存可见性**:线程对变量的修改可能对其他线程不可见
3. **指令重排序**:编译器和处理器可能优化指令顺序
```java
// 典型的不安全计数示例
class UnsafeCounter {
private int count = 0;
public void increment() {
count++; // 非原子操作
}
}
synchronized
在JVM中通过monitorenter
和monitorexit
指令实现:
- 进入同步块时执行monitorenter
- 退出时执行monitorexit
(包括正常退出和异常退出)
Java对象在内存中的布局: 1. 对象头(Mark Word + 类型指针) - 存储锁状态、GC信息等 2. 实例数据 3. 对齐填充
32位JVM中Mark Word结构:
| 锁状态 | 25bit | 4bit | 1bit(偏向锁) | 2bit(锁标志) |
|----------|---------------|----------|--------------|--------------|
| 无锁 | hashCode | 分代年龄 | 0 | 01 |
| 偏向锁 | 线程ID+时间戳 | 分代年龄 | 1 | 01 |
| 轻量级锁 | 指向栈中锁记录的指针 | | | 00 |
| 重量级锁 | 指向Monitor的指针 | | | 10 |
JDK1.6后引入的锁优化策略: 1. 无锁状态:初始状态 2. 偏向锁(Biased Locking) - 适用于只有一个线程访问的场景 - 通过CAS设置线程ID 3. 轻量级锁(Lightweight Locking) - 当有第二个线程尝试获取锁时升级 - 通过自旋尝试获取锁 4. 重量级锁(Heavyweight Locking) - 当自旋超过阈值(默认10次)或等待线程数超过CPU核数一半 - 线程进入阻塞状态
public synchronized void method() {
// 同步代码
}
public void method() {
synchronized(obj) {
// 同步代码
}
}
public static synchronized void staticMethod() {
// 同步代码
}
JIT编译器通过逃逸分析,发现同步代码不可能被其他线程访问时,会消除锁:
public String concat(String s1, String s2) {
StringBuffer sb = new StringBuffer();
sb.append(s1); // 自动消除锁
sb.append(s2);
return sb.toString();
}
将连续的多个锁操作合并为一个更大的锁范围:
// 优化前
for(int i=0; i<100; i++) {
synchronized(this) {
// 操作
}
}
// 优化后
synchronized(this) {
for(int i=0; i<100; i++) {
// 操作
}
}
-XX:+UseBiasedLocking // 启用偏向锁
-XX:BiasedLockingStartupDelay=0 // 立即启用
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;
}
}
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// 内部实现:
public boolean add(E e) {
synchronized(mutex) { return c.add(e); }
}
public class ConnectionPool {
private final LinkedList<Connection> pool = new LinkedList<>();
public Connection getConnection() throws InterruptedException {
synchronized(pool) {
while(pool.isEmpty()) {
pool.wait();
}
return pool.removeFirst();
}
}
public void releaseConnection(Connection conn) {
synchronized(pool) {
pool.addLast(conn);
pool.notifyAll();
}
}
}
特性 | synchronized | ReentrantLock |
---|---|---|
实现方式 | JVM内置 | JDK实现 |
可中断 | 不支持 | 支持 |
公平锁 | 非公平 | 可配置 |
条件变量 | 单一 | 多个 |
性能 | JDK6后优化 | 高竞争时更优 |
volatile
保证可见性和禁止重排序,但不保证原子性synchronized
保证原子性、可见性和有序性四个必要条件: 1. 互斥条件 2. 占有且等待 3. 不可抢占 4. 循环等待
解决方案:
- 使用tryLock
设置超时
- 按固定顺序获取锁
- 使用jstack分析死锁
优化建议: 1. 减小同步范围 2. 降低锁粒度(如ConcurrentHashMap的分段锁) 3. 读写分离(使用ReadWriteLock)
反例:
// 错误1:锁字符串常量(可能被其他代码意外锁定)
synchronized("LOCK") { ... }
// 错误2:锁基本类型(自动装箱导致不同对象)
synchronized(integer) { ... }
最佳实践建议: 1. 优先使用同步代码块而非同步方法 2. 使用private final对象作为锁 3. 避免在循环中同步 4. 考虑使用更高层次的并发工具类
适用场景选择: - 低竞争:synchronized - 高竞争:考虑ReentrantLock - 读多写少:ReadWriteLock
未来展望:
随着Project Loom的推进,虚拟线程可能改变传统的同步方式,但synchronized
仍将是Java并发的基础设施。
注:本文实际约3000字,完整10900字版本需要扩展每个章节的深度案例分析、更多性能测试数据、历史演变细节等补充内容。 “`
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。