浅谈Java并发编程之synchronized有序性误区

 更新时间:2026年02月13日 09:29:40   作者:Johnny Lnex  
本文主要介绍了浅谈Java并发编程之synchronized有序性误区,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

许多开发者误以为synchronized能完全禁止指令重排序,而实际上它仅能保证线程间的操作顺序,真正禁用重排序需依赖volatile

一、synchronized的有序性保证

synchronized通过锁机制间接保证多线程操作的顺序性,具体规则基于 Happens-Before 原则

  • 锁的释放(unlock)操作 Happens-Before 后续的锁获取(lock)操作
    这意味着:
    • 线程A在同步块内对共享变量的修改,对线程B在获取同一锁后的操作完全可见
    • 线程间的操作顺序在逻辑上按锁的获取顺序执行。

示例:线程间可见性与顺序性

public class SynchronizedOrderDemo {
    private int value = 0;
    private final Object lock = new Object();

    // 线程A:写操作
    public void write() {
        synchronized (lock) {
            value = 42; // 写操作
        }
    }

    // 线程B:读操作
    public int read() {
        synchronized (lock) {
            return value; // 保证读到42
        }
    }
}

执行顺序

  1. 线程A先获取锁,写value = 42,释放锁。
  2. 线程B获取锁后,一定能读到value = 42

二、synchronized无法禁止指令重排序

尽管synchronized保证了线程间的顺序性,但同步块内部的指令仍可能被重排序(只要不影响单线程执行结果)。这种重排序对单线程透明,但可能导致多线程问题。

示例:同步块内的指令重排序

synchronized (lock) {
    int a = 1;  // 操作1
    int b = 2;  // 操作2
}
  • 可能的执行顺序:操作2可能在操作1之前执行。
  • 单线程结果一致:无论顺序如何,最终a=1b=2
  • 多线程隐患:若其他线程依赖ab的写入顺序,可能导致逻辑错误。

1.volatile的禁止重排序机制

volatile通过插入内存屏障,直接限制编译器和处理器的指令重排序:

  • 写操作:插入 StoreStore屏障StoreLoad屏障
  • 读操作:插入 LoadLoad屏障LoadStore屏障

示例:volatile禁止对象初始化的重排序

// 双重检查锁定(DCL)单例模式
public class Singleton {
    private static volatile Singleton instance; // volatile禁止重排序

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton(); // 初始化操作
                }
            }
        }
        return instance;
    }
}
  • volatile的隐患:
    对象初始化可能被重排序为:分配内存 → 返回引用 → 初始化对象。其他线程可能拿到未初始化的对象。
  • volatile的作用:
    强制按顺序执行:分配内存 → 初始化对象 → 返回引用。

三、对比

特性synchronizedvolatile
线程顺序性保证多线程间的操作顺序(通过锁的Happens-Before规则)不直接保证多线程顺序,仅确保单变量操作顺序
指令重排序允许同步块内部的重排序(单线程语义下)禁止与volatile变量相关的重排序
可见性通过锁释放-获取保证所有变量的可见性仅保证volatile变量的可见性
原子性保证同步块内操作的原子性不保证复合操作的原子性(如i++)
性能开销较高(涉及用户态与内核态切换)较低(仅内存屏障开销)

四、常见误区

1. 误区:synchronized能完全禁止指令重排序

  • 真相synchronized仅保证线程间的操作顺序,但同步块内的指令仍可能被重排序(不影响单线程结果即可)。
  • 示例
    若同步块内有两个无关变量的赋值,编译器可能调整其顺序。

2. 误区:volatile可替代锁

  • 错误示例
    private volatile int count = 0;
    public void increment() {
        count++; // 非原子操作,volatile无法保证线程安全
    }
    
  • 正确方案:使用AtomicIntegersynchronized

到此这篇关于浅谈Java并发编程之synchronized有序性误区的文章就介绍到这了,更多相关Java synchronized有序性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

到此这篇关于浅谈Java并发编程之synchronized有序性误区的文章就介绍到这了,更多相关Java synchronized有序性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java使用Tess4J实现图像识别方式

    Java使用Tess4J实现图像识别方式

    这篇文章主要介绍了Java使用Tess4J实现图像识别方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • RocketMQ实现消息分发的步骤

    RocketMQ实现消息分发的步骤

    RocketMQ 实现消息分发的核心机制是通过 Topic、Queue 和 Consumer Group 的配合实现的,下面给大家介绍RocketMQ实现消息分发的步骤,感兴趣的朋友一起看看吧
    2024-03-03
  • Java ClassLoader类加载器基础详解

    Java ClassLoader类加载器基础详解

    这篇文章主要为大家介绍了Java ClassLoader类加载器基础详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-09-09
  • 关于springboot响应式编程整合webFlux的问题

    关于springboot响应式编程整合webFlux的问题

    在springboot2.x版本中提供了webFlux依赖模块,该模块有两种模型实现:一种是基于功能性端点的方式,另一种是基于SpringMVC注解方式,今天通过本文给大家介绍springboot响应式编程整合webFlux的问题,感兴趣的朋友一起看看吧
    2022-01-01
  • SpringMVC的Dispatcher解读

    SpringMVC的Dispatcher解读

    这篇文章主要介绍了SpringMVC的Dispatcher用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Java利用多线程和分块实现快速读取文件

    Java利用多线程和分块实现快速读取文件

    在工作中经常会有接收文件并且读取落库的需求,读取方式都是串行读取,所以本文主要为大家介绍一下如何利用多线程和分块实现快速读取文件,希望对大家有所帮助
    2023-09-09
  • Spring解析配置类和扫描包路径的详细过程

    Spring解析配置类和扫描包路径的详细过程

    这篇文章主要介绍了Spring解析配置类和扫描包路径的详细过程,文中通过代码示例讲解的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-12-12
  • java中jdbcTemplate的queryForList(坑)

    java中jdbcTemplate的queryForList(坑)

    本文主要介绍了java中jdbcTemplate的queryForList,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • Java简单实现约瑟夫环算法示例

    Java简单实现约瑟夫环算法示例

    这篇文章主要介绍了Java简单实现约瑟夫环算法,简单描述了约瑟夫环问题,并结合实例形式分析了Java实现约瑟夫环的具体操作技巧,需要的朋友可以参考下
    2017-09-09
  • Java简单数组排序(冒泡法)

    Java简单数组排序(冒泡法)

    这篇文章主要介绍了Java简单数组排序,实例分析了基于冒泡法实现数组排序的相关技巧,简单实用,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10

最新评论