Java 内存模型 (JMM) 是 Java 虚拟机 (JVM) 的一项规范,它定义了 Java 多线程编程中变量的可见性和原子性规则。JMM 规定了不同线程之间共享变量的访问方式,确保了多线程程序的正确执行。
- 可见性:
可见性是指一个线程对共享变量的修改能够被其他线程立即看到。在 JMM 中,可见性通过内存屏障 (memory barrier) 来实现。内存屏障是一种特殊的指令,它可以强制 JVM 在执行内存操作之前或之后刷新缓存。
public class VisibilityDemo {
private int sharedVar = 0;
public void writerThread() {
sharedVar = 42;
}
public void readerThread() {
int localVar = sharedVar; // 可能读取到旧值
System.out.println("Reader thread: " + localVar);
}
public static void main(String[] args) {
VisibilityDemo demo = new VisibilityDemo();
Thread writer = new Thread(demo::writerThread);
Thread reader = new Thread(demo::readerThread);
writer.start();
reader.start();
writer.join();
reader.join();
}
}
在上面的例子中,writerThread
和 readerThread
同时访问共享变量 sharedVar
。如果没有内存屏障,readerThread
可能会读取到旧的 sharedVar
值,导致程序输出错误的结果。为了解决这个问题,可以在 writerThread
和 readerThread
之间插入内存屏障。
public class VisibilityDemoWithMemoryBarrier {
private int sharedVar = 0;
public void writerThread() {
// 插入内存屏障
synchronized (this) {}
sharedVar = 42;
}
public void readerThread() {
// 插入内存屏障
synchronized (this) {}
int localVar = sharedVar;
System.out.println("Reader thread: " + localVar);
}
public static void main(String[] args) {
VisibilityDemoWithMemoryBarrier demo = new VisibilityDemoWithMemoryBarrier();
Thread writer = new Thread(demo::writerThread);
Thread reader = new Thread(demo::readerThread);
writer.start();
reader.start();
writer.join();
reader.join();
}
}
在上面的例子中,我们在 writerThread
和 readerThread
之间插入了内存屏障(通过调用 synchronized
方法)。这样,readerThread
就能够立即看到 writerThread
对 sharedVar
的修改,并且不会出现错误的结果。
- 原子性:
原子性是指一个操作要么完全执行,要么根本不执行。在 JMM 中,原子性通过原子变量 (atomic variable) 和原子操作 (atomic operation) 来实现。
原子变量是一种特殊的变量,它只能被一个线程同时访问。原子操作是一种特殊的操作,它可以在不发生中断的情况下执行。
import java.util.concurrent.atomic.AtomicInteger;
public class AtomicityDemo {
private AtomicInteger sharedVar = new AtomicInteger(0);
public void incrementSharedVar() {
sharedVar.incrementAndGet();
}
public static void main(String[] args) {
AtomicityDemo demo = new AtomicityDemo();
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(demo::incrementSharedVar);
}
for (Thread thread : threads) {
thread.start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println("Final value of sharedVar: " + demo.sharedVar.get());
}
}
在上面的例子中,我们使用原子变量 sharedVar
来确保多个线程对 sharedVar
的修改是原子的。即使有多个线程同时修改 sharedVar
,最终结果也是正确的。
- JMM 的应用:
JMM 在多线程编程中有着广泛的应用,例如:
- 线程安全类设计: JMM 可以帮助我们设计线程安全的类,确保类中的共享变量在多线程环境下能够正确地访问。
- 并发数据结构实现: JMM 可以帮助我们实现并发数据结构,例如并发队列、并发栈等,这些数据结构可以在多线程环境下安全地使用。
- 高性能并发算法设计: JMM 可以帮助我们设计高性能的并发算法,例如无锁算法等,这些算法可以充分利用多核 CPU 的优势,实现更高的性能。
总之,JMM 是 Java 多线程编程的基础,了解 JMM 的原理和应用,对于编写正确和高效的多线程程序非常重要。