Java 面试宝典:什么是可见性?volatile 是如何保证可见性的?
内容提要
本文讨论了多核年代中的可见性问题和解决方案,包括使用volatile修饰共享变量和同步机制。volatile通过lock前缀和MESI协议确保可见性,而MESI协议用于维护多处理器系统中的缓存共同性。内存屏障volatile通过Load和Store屏障实现可见性。最后以i++为例说明了内存屏障的作用。
关键要点
-
可见性是指一个线程对共享变量的修改能够被其他线程及时看到。
-
在多核环境中,每个CPU有自己的缓存,可能导致可见性问题。
-
解决可见性问题的方案包括使用volatile修饰共享变量和同步机制。
-
volatile确保可见性,通过在写入前加lock前缀,强制将值写入主内存。
-
MESI协议用于维护多处理器系统中的缓存一致性,确保缓存行的状态有效。
-
MESI协议的四种状态包括Modified(修正)、Exclusive(独占)、Shared(共享)和Invalid(无效)。
-
内存屏障通过Load和Store屏障实现可见性,确保每次读写操作都能从主内存获取最新数据。
-
以i++为例,展示了内存屏障如何确保线程安全和可见性。
延伸问答
可见性在多核环境中是如何产生的?
可见性问题在多核环境中产生,因为每个CPU有自己的缓存,线程对共享变量的修改可能只在本地缓存中进行,导致其他线程无法及时看到这些修改。
如何使用volatile来解决可见性问题?
使用volatile修饰共享变量后,所有对该变量的读写操作都在主内存中进行,从而确保不同线程之间对该变量修改的可见性。
MESI协议在缓存一致性中起什么作用?
MESI协议维护多处理器系统中的缓存一致性,通过标记缓存行的状态,确保当一个CPU修改共享变量时,其他CPU的缓存行被标记为无效,从而强制它们从主内存重新加载数据。
内存屏障是如何确保可见性的?
内存屏障通过在每个读操作前加Load屏障和在每个写操作后加Store屏障,强制从主内存读取最新数据和将数据写回主内存,从而确保可见性。
i++操作中如何避免线程安全问题?
在i++操作中,通过使用同步机制或锁来确保操作的原子性,避免多个线程同时读取和修改同一变量导致的线程安全问题。
volatile变量的写入过程是怎样的?
写入volatile变量时,会在指令前加lock前缀,强制将值写入主内存,并使其他处理器的缓存行标记为无效,以确保可见性。