synchronized是如何保证原子性、可见性、有序性的?

1 个回答

  • 柳擎
    今朝有酒今朝醉,明日愁来明日愁。
    #### **1. 原子性** **原子性**是指一个操作是不可中断的,无论线程切换还是异常,都不会影响操作的完整性。 - **实现方式**: 1. **通过字节码指令 monitorenter 和 monitorexit 实现**: - `monitorenter`:当线程执行 `synchronized` 修饰的代码时,首先尝试获取对象的 Monitor 锁。 - `monitorexit`:线程退出同步代码块或方法时,释放对象的锁。 2. **加锁机制**: - 当一个线程持有了锁,其他线程无法进入同步代码块,只能等待锁被释放。 3. **重入锁支持**: - 同一线程可以多次获取锁,而不被其他线程抢占,直到线程主动释放锁。 - **作用**: - 锁机制确保同一时刻只有一个线程可以访问同步代码块,从而保证了操作的原子性。 #### **2. 可见性** **可见性**是指当一个线程修改了变量的值,其他线程能立即看到最新值。 - **实现方式**: 1. **主存与工作内存同步**: - 每次线程进入同步代码块(加锁时),会清空工作内存中缓存的变量值,从主存重新加载最新值。 - 每次线程退出同步代码块(解锁时),会将修改后的变量值从工作内存刷新回主存。 2. **锁释放规则**: - 线程对变量的修改在释放锁之前,必须同步回主存;其他线程获取锁时会从主存中重新加载变量值。 - **作用**: - 确保线程对共享变量的修改对其他线程立即可见。 #### **3. 有序性** **有序性**是指程序的执行顺序按照代码的先后顺序执行。 - **实现方式**: 1. **通过内存屏障(Memory Barrier)**: - 在进入和退出同步块时插入内存屏障,禁止代码重排序。 - 进入同步块前的写操作和退出同步块后的读操作不会被重排。 2. **单线程保证**: - `synchronized` 的代码块在同一时间只能被一个线程访问,相当于单线程执行,天然保证了有序性。 3. **遵循 as-if-serial 语义**: - 编译器和 CPU 会确保重排序不影响单线程执行的最终结果。 - **作用**: - 确保代码执行的逻辑顺序不被破坏。 ### **总结** | 特性 | 实现机制 | 保证效果 | |----------|-------------------------------------------------------------------------------------------|-------------------------------------------------------------| | **原子性** | 通过 Monitor 锁和 `monitorenter` / `monitorexit` 字节码指令,实现同步代码块互斥访问。 | 确保线程操作不可中断,操作完整性得到保障。 | | **可见性** | 通过锁释放规则,保证线程退出同步代码块时变量值刷新到主存,其他线程重新加载主存值。 | 确保线程间共享变量的修改对其他线程可见。 | | **有序性** | 通过内存屏障和单线程执行语义,禁止重排序;同步块内的代码逻辑顺序保持不变。 | 确保线程按预期顺序执行代码,不出现乱序问题。 | `synchronized` 是一种简单而强大的同步机制,虽然性能可能不如其他高级同步工具(如 `Lock`),但在需要确保原子性、可见性和有序性的场景下,依然是有效的选择。
    发布于 2025-01-02 21:39 •IP属地 北京
    举报
    评论
    收藏