# 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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。