zoukankan      html  css  js  c++  java
  • JAVA 多线程随笔 (一) 可见性和volatile关键字

     // 先上代码
    1
    public class NoVisibility { 2 private static boolean ready; 3 private static int number; 4
    5 private static class ReaderThread extends Thread { 6 public void run() { 7 while(!ready) { 8 Thread.yield(); 9 } 10 System.out.println(number); 11 } 12 } 13 14 public static void main(String[] args) { 15 new ReaderThread().start(); 16 number = 100; 17 ready = true; 18 } 19 }

    上边的代码,如果直接运行,main进程首先开始ReaderThread进程,再去设置ready为true。 

    直观感受应该是当main进程将ready设为true后,ReaderThread进程就会跳出while循环,从而输出number值100。 

    但实际上,程序可能一直无限循环,或是输出的值为0. 因为这里没有用到同步机制,main进程写的ready和number值,不能保证ReaderThread看到。

    为什么?

    这里在多线程的背景下,JVM可能会进行底层的字节代码的优化和重排序,所以developer如果没有设计合理的同步机制,就不能确保代码的执行顺序是按照你所写的那样。

    怎么做?

    最基本的方法,就是用Locking机制,分别在读取和设置变量的方法上设置同一个锁,这就能保证 变量在进程A释放锁前的改动, 进程B在获得锁(同一个锁)后也能读取到。

    另外一种常见的方法,就是将 可能被不同的进程读取的变量用volatile修饰,volatile可以近似看作一种轻量级的同步机制。 此外volatile用来告诉编译器和运行库这个变量会在多个进程间共享,

    不要将它缓存在寄存器或是其他进程看不到的cache里。

    需要注意的是volatile只能保证可见性,不能保证原子性(比如 volatile int a = 0; a++;  两个进程可能都同时读到0),所以它是轻量级的同步机制。

    volatile的实现原理

      如果大家有兴趣查看代码JIT生成后的汇编指令,会发现针对volatile的变量的写操作,会有一个Lock指令,这是用来实现内存屏障的,保证如果一个处理器修改了变量值,会直接将值写回到内存,其他的处理器对应的缓存也会失效,需要重新从内存中读取,这样就保证所有的处理器读到的值,都是最近的变量值。

  • 相关阅读:
    MyCat简介+Mybatis实现多租户(链接)
    mybatis的sql执行过程底层源码分析和缓存原理分析
    推荐算法数据集
    CentOS系统初始化
    NAT
    VRRP
    BGP协议的原理及应用
    ospf协议的重分发
    静态路由的原理与配置、动态路由
    OSPF (企业内部使用的动态路由协议)
  • 原文地址:https://www.cnblogs.com/liangwenbo/p/5333453.html
Copyright © 2011-2022 走看看