设为首页 - 加入收藏 ASP站长网(Aspzz.Cn)- 科技、建站、经验、云计算、5G、大数据,站长网!
热搜: 数据 创业者 手机
当前位置: 首页 > 运营中心 > 建站资源 > 优化 > 正文

硬件内存模型到 Java 内存模型,这些硬核知识你知多少?(2)

发布时间:2019-11-08 17:32 所属栏目:21 来源:平头哥
导读:JMM 通过控制主内存与每个线程的本地内存之间的交互,来为 Java 程序员提供内存可见性保证。Java 内存模型除了定义了一套规范,还提供了一系列原语,封装了底层实现后,供开发者直接使用。这套实现也就是我们常用的

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 于后续的任意操作。这一条规则还是非常好理解的,看下面这一段代码

  1. class Test{ 
  2. 1   int x ; 
  3. 2   int y ; 
  4. 3   public void run(){ 
  5. 4       y = 20; 
  6. 5       x = 12; 
  7.     } 

第四行代码要 Happens-Before 于第五行代码,也就是按照代码的顺序来。

2、锁定规则

这条规则是指对一个锁的解锁 Happens-Before 于后续对这个锁的加锁。例如下面的代码,在进入同步块之前,会自动加锁,而在代码块执行完会自动释放锁,加锁以及释放锁都是编译器帮我们实现的

  1. synchronized (this) { 
  2.     // 此处自动加锁 
  3.     // x 是共享变量, 初始值 =10 
  4.     if (this.x < 12) { 
  5.        this.x = 12; 
  6.     } 
  7. } // 此处自动解锁 

对于锁定规则可以这样理解:假设 x 的初始值是 10,线程 A 执行完代码块后 x 的值会变成 12(执行完自动释放锁),线程 B 进入代码块时,能够看到线程 A 对 x 的写操作,也就是线程 B 能够看到 x==12。

3、volatile 变量规则

这条规则是指对一个 volatile 变量的写操作及这个写操作之前的所有操作 Happens-Before 对这个变量的读操作及这个读操作之后的所有操作。

4、线程启动规则

这条规则是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。

  1. public class Demo { 
  2.     private static int count = 0; 
  3.     public static void main(String[] args) throws InterruptedException { 
  4.         Thread t1 = new Thread(() -> { 
  5.             System.out.println(count); 
  6.         }); 
  7.         count = 12; 
  8.         t1.start(); 
  9.     } 

子线程 t1 能够看见主线程对 count 变量的修改,所以在线程中打印出来的是 12 。这也就是线程启动规则

5、线程结束规则

这条是关于线程等待的。它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作。

  1. public class Demo { 
  2.     private static int count = 0; 
  3.     public static void main(String[] args) throws InterruptedException { 
  4.         Thread t1 = new Thread(() -> { 
  5.             // t1 线程修改了变量 
  6.             count = 12; 
  7.         }); 
  8.         t1.start(); 
  9.         t1.join(); 
  10.         // mian 线程可以看到 t1 线程改修后的变量 
  11.         System.out.println(count); 
  12.     } 

6、中断规则

(编辑:ASP站长网)

网友评论
推荐文章
    热点阅读