浅谈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有序性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot项目如何使用Maven打包并带上依赖

    Spring Boot项目如何使用Maven打包并带上依赖

    在这篇博客中,介绍如何使用Maven将Spring Boot项目及其依赖项打包成一个可执行的jar文件。我们将使用Spring Boot的spring-boot-maven-plugin插件来完成这个任务,感兴趣的朋友跟随小编一起看看吧
    2023-06-06
  • SpringBoot整合Swagger3生成接口文档的示例代码

    SpringBoot整合Swagger3生成接口文档的示例代码

    Swagger 是一个 RESTful API 的开源框架,它的主要目的是帮助开发者设计、构建、文档化和测试 Web API,本文给大家介绍了SpringBoot整合Swagger3生成接口文档的流程,并通过代码讲解的非常详细,需要的朋友可以参考下
    2024-04-04
  • 详解Java设计模式中的装饰模式

    详解Java设计模式中的装饰模式

    装饰模式是指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。本文将为大家详细介绍一下装饰模式,感兴趣的可以了解一下
    2021-12-12
  • 手把手教你如何在idea中搭建SpringBoot项目

    手把手教你如何在idea中搭建SpringBoot项目

    这篇文章主要介绍了如何搭建一个SpringBoot项目,包括环境准备、创建新项目、探索项目结构以及展望未来,通过详细的步骤和实用的技巧,帮助开发者快速上手SpringBoot开发,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2025-02-02
  • Java并发编程之死锁相关知识整理

    Java并发编程之死锁相关知识整理

    前篇文章在讲解线程安全的时候,有提到过为了保证每个线程都能正常执行共享资源操作,Java引入了锁机制,虽然这样使多线程改善了系统的处理能力,然而也带来了新的问题,其中之一:死锁,需要的朋友可以参考下
    2021-06-06
  • Springboot项目如何兼容老的Spring项目问题

    Springboot项目如何兼容老的Spring项目问题

    这篇文章主要介绍了Springboot项目如何兼容老的Spring项目问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • IDEA 自动生成 JPA 实体类的图文教程

    IDEA 自动生成 JPA 实体类的图文教程

    这篇文章主要介绍了IDEA 自动生成 JPA 实体类的图文教程,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Spring Boot集成教程之异步调用Async

    Spring Boot集成教程之异步调用Async

    在项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行,我们可以使用多线程来并行的处理任务,也可以使用spring提供的异步处理方式@Async。需要的朋友们下面来一起看看吧。
    2018-03-03
  • java中Cookie被禁用后Session追踪问题

    java中Cookie被禁用后Session追踪问题

    这篇文章主要介绍了Java中Cookie被禁用后Session追踪问题,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-03-03
  • Java数据存储的“双子星”对决(Map和Set的区别)

    Java数据存储的“双子星”对决(Map和Set的区别)

    文章主要介绍了Java中Map和Set两种数据结构的定义、实现、方法及应用场景,Map用于存储键值对,键唯一,值可重复;Set用于存储唯一元素,无序,两者都提供了丰富的操作方法,如添加、删除、查找等,感兴趣的朋友一起看看吧
    2025-02-02

最新评论