您好,登录后才能下订单哦!
# 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()等非阻塞方法
ReadWriteLocksynchronized性能已大幅优化// 危险!字符串常量池具有全局性
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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。