温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java中synchronized的作用及用法

发布时间:2021-06-18 16:04:38 来源:亿速云 阅读:303 作者:chen 栏目:编程语言
# Java中synchronized的作用及用法 ## 一、引言 在多线程编程中,线程安全是一个核心问题。当多个线程同时访问共享资源时,如果没有适当的同步机制,就可能出现数据不一致、脏读等问题。Java提供了`synchronized`关键字来解决这类线程安全问题。本文将深入探讨`synchronized`的作用、用法及其实现原理。 --- ## 二、synchronized的作用 ### 1. 保证原子性 `synchronized`能够确保同一时刻只有一个线程执行被保护的代码块或方法,从而避免多线程环境下的竞态条件(Race Condition)。 ```java public class Counter { private int count = 0; public synchronized void increment() { count++; // 原子操作 } } 

2. 保证可见性

通过synchronized修饰的代码块或方法,在释放锁时会将工作内存中的变量刷新到主内存,获取锁时会从主内存读取最新值。

3. 保证有序性

synchronized通过互斥锁禁止指令重排序,确保代码执行顺序符合预期。


三、synchronized的用法

1. 同步实例方法

作用于当前实例对象,锁是当前实例(this)。

public synchronized void method() { // 线程安全代码 } 

2. 同步静态方法

作用于类的Class对象,锁是当前类的Class对象(ClassName.class)。

public static synchronized void staticMethod() { // 线程安全代码 } 

3. 同步代码块

更细粒度的控制,可以指定任意对象作为锁。

public void blockMethod() { synchronized(this) { // 锁对象可以是任意Object // 线程安全代码 } } 

4. 类锁与对象锁的区别

  • 对象锁:不同实例的锁互不影响
  • 类锁:所有实例共享同一把锁
class DualLockExample { // 对象锁 public synchronized void instanceLock() {} // 类锁 public static synchronized void classLock() {} } 

四、synchronized的实现原理

1. JVM层面的实现

synchronized基于Monitor机制实现,每个Java对象都与一个Monitor相关联: - 当线程进入同步块时,会尝试获取Monitor的所有权 - 成功获取后计数器+1(可重入性) - 执行完毕计数器-1,释放锁

2. 锁的升级过程(JDK1.6优化)

  • 无锁状态:初始状态
  • 偏向锁:减少无竞争时的开销
  • 轻量级锁:通过CAS自旋尝试获取锁
  • 重量级锁:真正的互斥锁,涉及操作系统内核态切换

3. 对象头Mark Word结构

锁状态信息存储在对象头的Mark Word中:

| 锁状态 | 存储内容 | |----------|----------------------------| | 无锁 | 对象哈希码、分代年龄 | | 偏向锁 | 线程ID、Epoch、分代年龄 | | 轻量级锁 | 指向栈中锁记录的指针 | | 重量级锁 | 指向Monitor的指针 | 

五、使用示例

1. 线程安全的单例模式

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; } } 

2. 生产者消费者模型

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; } } 

六、注意事项

1. 避免死锁

// 错误的嵌套锁示例 public void transfer(Account from, Account to, int amount) { synchronized(from) { synchronized(to) { // 可能产生死锁 from.withdraw(amount); to.deposit(amount); } } } 

解决方案: - 按固定顺序获取锁 - 使用tryLock()等非阻塞方法

2. 性能考量

  • 减少同步代码块的范围
  • 对于读多写少的场景,考虑使用ReadWriteLock
  • JDK1.6后synchronized性能已大幅优化

3. 不要锁字符串常量

// 危险!字符串常量池具有全局性 synchronized("LOCK") { // ... } 

七、与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关键字的各个方面。如需调整内容或格式,可以进一步修改。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI