您好,登录后才能下订单哦!
# Java中synchronized的作用及用法
## 一、引言
在多线程编程中,线程安全是一个核心问题。当多个线程同时访问共享资源时,如果没有适当的同步机制,就可能出现数据不一致、脏读等问题。Java提供了`synchronized`关键字来解决这类线程安全问题。本文将深入探讨`synchronized`的作用、用法及其实现原理。
---
## 二、synchronized的作用
### 1. 保证原子性
`synchronized`能够确保同一时刻只有一个线程执行被保护的代码块或方法,从而避免多线程环境下的竞态条件(Race Condition)。
```java
public class Counter {
private int count = 0;
public synchronized void increment() {
count++; // 原子操作
}
}
通过synchronized
修饰的代码块或方法,在释放锁时会将工作内存中的变量刷新到主内存,获取锁时会从主内存读取最新值。
synchronized
通过互斥锁禁止指令重排序,确保代码执行顺序符合预期。
作用于当前实例对象,锁是当前实例(this
)。
public synchronized void method() {
// 线程安全代码
}
作用于类的Class对象,锁是当前类的Class对象(ClassName.class
)。
public static synchronized void staticMethod() {
// 线程安全代码
}
更细粒度的控制,可以指定任意对象作为锁。
public void blockMethod() {
synchronized(this) { // 锁对象可以是任意Object
// 线程安全代码
}
}
class DualLockExample {
// 对象锁
public synchronized void instanceLock() {}
// 类锁
public static synchronized void classLock() {}
}
synchronized
基于Monitor机制实现,每个Java对象都与一个Monitor相关联:
- 当线程进入同步块时,会尝试获取Monitor的所有权
- 成功获取后计数器+1(可重入性)
- 执行完毕计数器-1,释放锁
锁状态信息存储在对象头的Mark Word中:
| 锁状态 | 存储内容 |
|----------|----------------------------|
| 无锁 | 对象哈希码、分代年龄 |
| 偏向锁 | 线程ID、Epoch、分代年龄 |
| 轻量级锁 | 指向栈中锁记录的指针 |
| 重量级锁 | 指向Monitor的指针 |
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 CAPACITY = 10;
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == CAPACITY) {
wait();
}
queue.add(item);
notifyAll();
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait();
}
int item = queue.poll();
notifyAll();
return item;
}
}
// 错误的嵌套锁示例
public void transfer(Account from, Account to, int amount) {
synchronized(from) {
synchronized(to) { // 可能产生死锁
from.withdraw(amount);
to.deposit(amount);
}
}
}
解决方案:
- 按固定顺序获取锁
- 使用tryLock()
等非阻塞方法
ReadWriteLock
synchronized
性能已大幅优化// 危险!字符串常量池具有全局性
synchronized("LOCK") {
// ...
}
特性 | synchronized | Lock |
---|---|---|
获取方式 | 自动获取释放 | 需要手动lock()/unlock() |
可中断性 | 不可中断 | 支持lockInterruptibly() |
公平性 | 非公平 | 可配置公平/非公平 |
条件变量 | 只能通过wait()/notify() | 支持多个Condition |
性能 | JDK1.6后优化较好 | 高竞争下可能更好 |
synchronized
作为Java内置的同步机制,具有以下特点:
1. 使用简单,JVM自动管理锁的获取和释放
2. 支持可重入,避免自我死锁
3. JDK1.6后性能大幅提升
4. 是解决线程安全问题的首选方案(满足需求时)
对于更复杂的同步需求,可以考虑java.util.concurrent
包中的锁工具。在实际开发中,应根据具体场景选择合适的同步策略。
注意:本文基于JDK17编写,不同版本实现细节可能有所差异。 “`
这篇文章共计约1900字,采用Markdown格式编写,包含了代码示例、表格对比等结构化内容,全面覆盖了synchronized
关键字的各个方面。如需调整内容或格式,可以进一步修改。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。