zoukankan      html  css  js  c++  java
  • JUC的本质

    在介绍可见性、原子性、有序性的时候,特意提到缓存导致的可见性问题,线程切换带来的原子性问题,编
    译优化带来的有序性问题,其实缓存、线程、编译优化的目的和我们写并发程序的目的是相同的,都是提高
    程序性能。但是技术在解决一个问题的同时,必然会带来另外一个问题,所以在采用一项技术的同时,一定
    要清楚它带来的问题是什么,以及如何规避。

    那synchronized里的加锁lock()和解锁unlock()锁定的对象在哪里呢?上面的代码我们看到只有修饰代码块的时候,锁定了一个obj对象,那修饰方法的时候锁定的是什么呢?这个也是Java的一条隐式规则:

    当修饰静态方法的时候,锁定的是当前类的Class对象,在上面的例子中就是Class X;
    当修饰非静态方法的时候,锁定的是当前实例对象this。

    编译优化带来的有序性问题
    那并发编程里还有没有其他有违直觉容易导致诡异Bug的技术呢?有的,就是有序性。顾名思义,有序性指
    的是程序按照代码的先后顺序执行。编译器为了优化性能,有时候会改变程序中语句的先后顺序,例如程序
    中:“a=6;b=7;”编译器优化后可能变成“b=7;a=6;”,在这个例子中,编译器调整了语句的顺序,
    但是不影响程序的最终结果。不过有时候编译器及解释器的优化可能导致意想不到的Bug。
    在Java领域一个经典的案例就是利用双重检查创建单例对象,例如下面的代码:在获取实例getInstance()的
    方法中,我们首先判断instance是否为空,如果为空,则锁定Singleton.class并再次检查instance是否为
    空,如果还为空则创建Singleton的一个实例。

    public class Singleton {
     static Singleton instance;
     static Singleton getInstance(){
     if (instance == null) {
      synchronized(Singleton.class) {
           if (instance == null)
                 instance = new Singleton();
    }
      }
       return instance;
     }
    }

    假设有两个线程A、B同时调用getInstance()方法,他们会同时发现 instance == null ,于是同时对
    Singleton.class加锁,此时JVM保证只有一个线程能够加锁成功(假设是线程A),另外一个线程则会处于等
    待状态(假设是线程B);线程A会创建一个Singleton实例,之后释放锁,锁释放后,线程B被唤醒,线程B
    再次尝试加锁,此时是可以加锁成功的,加锁成功后,线程B检查 instance == null 时会发现,已经创
    建过Singleton实例了,所以线程B不会再创建一个Singleton实例。
    这看上去一切都很完美,无懈可击,但实际上这个getInstance()方法并不完美。问题出在哪里呢?出在new
    操作上,我们以为的new操作应该是:
    1. 分配一块内存M;
    2. 在内存M上初始化Singleton对象;
    3. 然后M的地址赋值给instance变量。
    但是实际上优化后的执行路径却是这样的:

    1. 分配一块内存M;
    2. 将M的地址赋值给instance变量;
    3. 最后在内存M上初始化Singleton对象。

    优化后会导致什么问题呢?我们假设线程A先执行getInstance()方法,当执行完指令2时恰好发生了线程切
    换,切换到了线程B上;如果此时线程B也执行getInstance()方法,那么线程B在执行第一个判断时会发现
    instance != null ,所以直接返回instance,而此时的instance是没有初始化过的,如果我们这个时候
    访问 instance 的成员变量就可能触发空指针异常。

    Java方法里面的局部变量是否存在并发问题?

    一点问题都没有。因为每个线程都有自己的调用栈,局部变量保存在线程各自的调用栈里面,不会共
    享,所以自然也就没有并发问题。再次重申一遍:没有共享,就没有伤害。

  • 相关阅读:
    关于断电即关闭的电路设计
    Python-29_常用模块复习
    Python-28_组合_继承_多态_封装_反射
    Python-27_面向对象
    Python-26_模块-02_python内置模板
    Python-25_模块-01_调用基本操作、路径
    Python-24_综合练习-01_函数_文件处理_解耦--查询功能
    Python-23_装饰器-04_练习---无参装饰器、有参装饰器
    Python-22_装饰器-03_解压序列
    Python-21_装饰器-02_装饰器实现
  • 原文地址:https://www.cnblogs.com/leeego-123/p/13998260.html
Copyright © 2011-2022 走看看