捐催制 发表于 2025-9-24 11:05:59

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

在多线程环境中,‌临界区(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的内存可见性保障。
未完待续
很高兴与你相遇!如果你喜欢本文内容,记得关注哦!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

孜尊 发表于 2025-12-9 15:06:00

感谢分享,下载保存了,貌似很强大

毁抨句 发表于 2025-12-10 14:36:15

热心回复!

户烫擞 发表于 2025-12-18 18:59:34

感谢分享,下载保存了,貌似很强大

背竽 发表于 2025-12-23 00:52:25

这个有用。

聊账 发表于 2025-12-29 17:04:57

谢谢楼主提供!

阴昭昭 发表于 2026-1-11 15:49:13

过来提前占个楼

蔬陶 发表于 2026-1-13 02:02:08

东西不错很实用谢谢分享

疝镜泛 发表于 2026-1-13 16:31:07

谢谢分享,试用一下

况雪柳 发表于 2026-1-13 19:16:46

这个好,看起来很实用

稼布欤 发表于 2026-1-15 09:39:35

懂技术并乐意极积无私分享的人越来越少。珍惜

劳欣笑 发表于 2026-1-19 01:01:49

喜欢鼓捣这些软件,现在用得少,谢谢分享!

古修蟑 发表于 2026-1-19 08:03:45

热心回复!

喳谍 发表于 2026-1-20 18:36:56

谢谢分享,辛苦了

孓访懔 发表于 2026-1-21 08:13:53

用心讨论,共获提升!

瞿佳悦 发表于 2026-1-22 12:02:33

感谢分享,学习下。

敞撬 发表于 2026-1-22 12:28:22

用心讨论,共获提升!

损注 发表于 2026-1-23 06:10:45

过来提前占个楼

恶凝毛 发表于 2026-1-24 09:52:07

yyds。多谢分享

乳杂丫 发表于 2026-1-26 10:21:41

感谢,下载保存了
页: [1] 2 3
查看完整版本: 一把锁的两种承诺:synchronized如何同时保证互斥与内存可见性?