zoukankan      html  css  js  c++  java
  • Java 程序中怎么保证多线程的运行安全?

    并发操作中的3大问题:原子性问题,可见性问题,有序性问题

    原子性:一个或者多个操作在 CPU 执行的过程中不被中断的特性
    可见性:一个线程对共享变量的修改,另外一个线程能够立刻看到
    有序性:程序执行的顺序按照代码的先后顺序执行

    问题产生的原因

    线程切换带来的原子性问题

    案列:
    假设为一个32位的变量赋值包括两个过程:为低16位赋值,为高16位赋值。可能发生一种情况:当将低16位数值写入之后,突然被中断,而此时又有一个线程去读取该变量的值,那么读取到的就是错误的数据。

    缓存导致的可见性问题

    案例:

    //线程1执行的代码
    int i = 0;
    i = 10;
     
    //线程2执行的代码
    j = i;
    

    假若执行线程1的是CPU1,执行线程2的是CPU2。由上面的分析可知,当线程1执行 i =10这句时,会先把i的初始值加载到CPU1的高速缓存中,然后赋值为10,那么在CPU1的高速缓存当中i的值变为10了,却没有立即写入到主存当中。此时线程2执行 j = i,它会先去主存读取i的值并加载到CPU2的缓存当中,注意此时内存当中i的值还是0,那么就会使得j的值为0,而不是10。这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。

    编译优化带来的有序性问题

    案列:

    //线程1:
    context = loadContext();   //语句1
    inited = true;             //语句2
     
    //线程2:
    while(!inited ){
      sleep()
    }
    doSomethingwithconfig(context);
    

    由于语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了指令重排序,在线程1执行过程中先执行语句2,而此是线程2会以为初始化工作已经完成,那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被初始化,就会导致程序出错。

    解决办法

    JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
    synchronized、volatile、LOCK,可以解决可见性问题(volatile不能解决原子性问题,可以解决有序性问题)
    synchronized、LOCK、volatile、Happens-Before 规则可以解决有序性问题

    参考文献

    https://www.cnblogs.com/dolphin0520/p/3920373.html

  • 相关阅读:
    JDK 动态代理分析
    java class 文件解析
    ARM体系结构和汇编指令
    待整理
    Nand Flash,Nor Flash,CFI Flash,SPI Flash 之间的关系
    CPU与内存的那些事
    关于DMA和它的仇家
    BSS段 data段 text段 堆heap 和 栈stack
    关于常用序号的几点说明(数字序号顺序)
    word表格自动编号,前面加章节号
  • 原文地址:https://www.cnblogs.com/little-mao2020/p/14804137.html
Copyright © 2011-2022 走看看