写点什么

一把锁的两种承诺:synchronized 如何同时保证互斥与内存可见性?

作者:poemyang
  • 2025-09-24
    北京
  • 本文字数:1384 字

    阅读完需:约 5 分钟

在多线程环境中,‌临界区(Critical Section)是指一次只能由一个线程执行的代码段,这些代码通常涉及对共享资源(如变量、数据结构、文件或数据库连接)的访问或修改。临界区的存在是为了解决并发控制中的两大核心问题。‌ 1)数据不一致性‌:如果多个线程同时对共享资源进行写操作,可能会破坏数据的完整性,导致其状态与预期不符。‌ 2)竞态条件:程序的执行结果依赖于线程调度和执行的偶然顺序,这使得程序行为变得不可预测,难以调试。



为了保护临界区,Java 提供了多种互斥(Mutual Exclusion)机制,其中 synchronized 关键字是最常用且强大的工具之一。synchronized 实现互斥的基础是 Java 中的每一个对象都可以作为锁,这个锁是排他的,在任意时刻只有两种状态:被占用和未被占用。当线程请求一个由其他线程持有的锁时,请求的线程会被阻塞,直到锁被释放。这种机制确保了在任何时刻,只有一个线程能够进入临界区执行代码。synchronized 有两种使用方式。1)synchronized 修饰方法:锁是当前实例对象。它修饰的方法称为同步方法。


public synchronized void method() {    // ...}
复制代码


2)synchronized 修饰代码块:锁是 synchronized 括号里配置的对象。它修饰的代码块称为同步代码块。


public void method() {
synchronized (this) { // ... }
}
复制代码


synchronized 与 happens-before 关系在 Java 内存模型中,对 synchronized 关键字建立如下的 happens-before 关系:释放锁的操作 happens-before 之后对同一把锁的获取的锁操作。


class LockingExample {    int x = 0;    public synchronized void set() {    // 1        x++;                            // 2    }                                   // 3
public synchronized void get() { // 4 int i = x; // 5 // ...... } //6}
复制代码


假设线程 A 执行 set()方法,随后线程 B 执行 get()方法。假设线程 A 获取锁执行 set()方法,在 set()方法中,对共享变量 x 自增+1,然后释放锁。线程 B 获取锁执行 get()方法,在 get()方法中,读取变量 x,并赋值给本地变量 i,然后释放锁。根据 happens-before 规则,可以确定线程 A 对 x 的修改 happens-before 线程 B 对 x 的读取,从而保证了数据的一致性。这个过程建立的 happens-before 关系可以分为 3 类。1)程序次序规则:1 happens-before 2,2 happens-before 3;4 happens-before 5,5 happens-before 6;2)监视器锁规则:3 happens-before 4;3)happens-before 的传递性规则: happens-before 5。上述 happens-before 关系的图形化表现形式如下。



synchronized 内存语义

synchronized 释放锁的内存语义:当线程释放锁时,Java 内存模型会把该线程对应的本地内存中的共享变量刷新到主内存中。A 线程释放锁后,共享数据的状态如图所示。



synchronized 获取锁的内存语义:当线程获取锁时,Java 内存模型会把该线程对应的本地内存置为无效。从而使得被监视器保护的临界区代码必须从主内存中读取共享变量。B 线程释放锁后,共享数据的状态如图所示。



对比锁释放-获取与 volatile 写-读的内存语义可以看出:锁释放与 volatile 写有相同的内存语义;锁获取与 volatile 读有相同的内存语义。这表明 synchronized 不仅提供了互斥访问的同步机制,还具备了 volatile 的内存可见性保障。


未完待续


很高兴与你相遇!如果你喜欢本文内容,记得关注哦!

发布于: 刚刚阅读数: 2
用户头像

poemyang

关注

让世界知道我的存在 2018-03-05 加入

技术/人文, 互联网

评论

发布
暂无评论
一把锁的两种承诺:synchronized如何同时保证互斥与内存可见性?_并发编程_poemyang_InfoQ写作社区