当前位置: 代码网 > it编程>编程语言>Java > 浅谈Java并发编程之synchronized有序性误区

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

2026年02月13日 Java 我要评论
许多开发者误以为synchronized能完全禁止指令重排序,而实际上它仅能保证线程间的操作顺序,真正禁用重排序需依赖volatile。一、synchronized的有序性保证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有序性内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com