多线程编程核心技术(三)Java内存模型

2021-03-08 23:31

阅读:429

标签:get   释放   htm   直接   lan   就是   简单   app   als   

如果说造成线程不安全的情况是来源有时序性(代码优化),可见性(缓存一致性),原子性(线程切换)。

那么最简单的优化方式就是禁用缓存和编译优化。这样可以直接解决问题,就是代码的性能会相对的下降。合理的方案应该是按需禁用缓存以及编译优化。

这样的话就可以分治不同的代码,有并发的代码进行调整,没有并发的代码则可以继续之前的。

Java模型中规范的三个解决这类问题的关键字是 volatile,synchronized和final,以及Happens-Before规则。

volatile在C语言里面也有,本质是禁用高速缓存(强制刷新)。

class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;
    v = true;
  }
  public void reader() {
    if (v == true) {
      // 这里x会是多少呢?
    }
  }
}

这个代码在Java1.5之前可能为0,问题在于x可能被缓存了,导致另外一个线程虽然看到了v=true,但是x依然是0;

在java1.5成功解决了这个问题,Happens-Before规则的含义就是前面的操作对后面的操作是可见的,也就是做线程A进行了读写操作,那么B肯定能看到A读写之后的最新的变量的值。

Happens-Before的6大规则就是:

1.程序的顺序性规则:程序前面对某个变量的修改对后续的程序是可见的,例如volatile修改了v,v对后面的线程二是可见的

2.volatile变量规则:在新的内存模型中,volatile周围的普通字段不能随便重排;编译器生成字节码时,会在volatile写操作的前面和后面分别插入内存屏障(StoreStore屏障|volatile写|StoreLoad屏障),其中StoreStore屏障:禁止上面的普通写和下面的volatile写重排序;StoreLoad屏障:防止上面的volatile写与下面可能有的volatile读/写重排序。

3.传递性:这条规则是指如果 A Happens-Before B,且 B Happens-Before C,那么 A Happens-Before C。

花里胡哨的,其实就是如果你用了volatile,volatile会导致x的可见性需要保障,那么后面线程读的时候(线程读的时候需要对volatile进行判断),就会从主存中进行读取。边界就是只要给volatile赋值成功,那么这个赋值语句之前所有代码的执行结果都对其他线程可见 所以应该是将有volitile执行结果的cpu全部缓存强制刷新到内存,然后强制将其它cpu中的全部缓存和内存同步。

4.管程中锁的规则:管程(monitor)只是保证了同一时刻只有一个进程在管程内活动,即管程内定义的操作在同一时刻只被一个进程调用(由编译器实现).

管程(monitor)只是保证了同一时刻只有一个进程在管程内活动,即管程内定义的操作在同一时刻只被一个进程调用(由编译器实现).管程中的锁在 Java 里是隐式实现的,例如下面的代码,在进入同步块之前,会自动加锁,而在代码块执行完会自动释放锁,加锁以及释放锁都是编译器帮我们实现的。

5. 线程 start() 规则:指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作。

多线程编程核心技术(三)Java内存模型

标签:get   释放   htm   直接   lan   就是   简单   app   als   

原文地址:https://www.cnblogs.com/SmartCat994/p/14188022.html

上一篇:tomcat JAVA_OPTS

下一篇:js 单例模式


评论


亲,登录后才可以留言!