硬件内存模型到 Java 内存模型,这些硬核知识你知多少?(2)
JMM 通过控制主内存与每个线程的本地内存之间的交互,来为 Java 程序员提供内存可见性保证。Java 内存模型除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。这套实现也就是我们常用的volatile、synchronized、final 等。 Happens-Before内存模型 Happens-Before 内存模型或许叫做 Happens-Before 原则更为合适,在 《JSR 133 :Java 内存模型与线程规范》中,Happens-Before 内存模型被定义成 Java 内存模型近似模型,Happens-Before 原则要说明的是关于可见性的一组偏序关系。 为了方便程序员开发,将底层的繁琐细节屏蔽掉,Java 内存模型 定义了 Happens-Before 原则。只要我们理解了 Happens-Before 原则,无需了解 JVM 底层的内存操作,就可以解决在并发编程中遇到的变量可见性问题。JVM 定义的 Happens-Before 原则是一组偏序关系:对于两个操作 A 和 B,这两个操作可以在不同的线程中执行。如果 A Happens-Before B,那么可以保证,当 A 操作执行完后,A 操作的执行结果对 B 操作是可见的。 Happens-Before 原则一共包括 8 条,下面我们一起简单的学习一下这 8 条规则。 1、程序顺序规则 这条规则是指在一个线程中,按照程序顺序,前面的操作 Happens-Before 于后续的任意操作。这一条规则还是非常好理解的,看下面这一段代码
第四行代码要 Happens-Before 于第五行代码,也就是按照代码的顺序来。 2、锁定规则 这条规则是指对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。例如下面的代码,在进入同步块之前,会自动加锁,而在代码块执行完会自动释放锁,加锁以及释放锁都是编译器帮我们实现的
对于锁定规则可以这样理解:假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁),线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12。 3、volatile 变量规则 这条规则是指对一个 volatile 变量的写操作及这个写操作之前的所有操作 Happens-Before 对这个变量的读操作及这个读操作之后的所有操作。 4、线程启动规则 这条规则是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。
子线程 t1 能够看见主线程对 count 变量的修改,所以在线程中打印出来的是 12 。这也就是线程启动规则 5、线程结束规则 这条是关于线程等待的。它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。
6、中断规则 (编辑:ASP站长网) |