java重排序问题

java指令重排序

用两个例子来讲明:java

1.双重锁单例模式

public class Singleton {
    
    private static Singleton uniqueSingleton;

    private Singleton() {}

    public static Singleton getInstance() {
        if (null == uniqueSingleton) {//先判断是否为空,没必要每次都加锁
            synchronized (Singleton.class) {//再获取锁
                if (null == uniqueSingleton) {//再次判断是否为空,由于第二个线程获取到锁后,继续执行,可是第一个线程已经初始化完成了
                    uniqueSingleton = new Singleton();//初始化对象
                }
            }
        }
        return uniqueSingleton;
    }
}

上述代码是一个双重锁的单例模式实现方式,但存在隐患
咱们须要了解初始化对象的过程,包含的指令大体以下:
1.分配内存空间
2.初始化对象
3.将对象指向分配的内存空间
有些编译器为了提高效率,会将2 3的顺序倒置(重排序,先将对象指向分配的内存空间再初始化),所以可能发生读取到未初始化完成的对象
如何解决?
使用volatile关键字,禁止重排序编程

private volatile static Singleton uniqueSingleton;

2.多线程下的状态判断

public class NoVisibility{
    private static boolean ready;
    private static int number;
    
    private static class ReaderThrad extends Thread{
        public void run(){
            while(!ready){
                Thread.yield();
            }
            System.out.println(number);
        }
    }
    
    public static void main(String [] args){
        new ReaderThread().start();
        number = 42;
        ready = true;
    }
}

上述代码源自<<Java并发编程实践>>书中
可能发生的现象:多线程

  1. 持续循环下去,ReaderThread可能永远看不到ready的值
    Thread.yield()的意思是将当前状态转换为就绪状态,ReaderThread立刻又获取到了执行机会,可能致使main线程永远获取不到执行的机会
  2. 可能会打印0
    ReaderThread可能看到了写入ready的值,但却没有看到写入number的值,由于发生了“重排序”现象,因为number=42 ready=true不知足Happens-Before原则,所以JVM能够对这两个操做任意的重排序,便可能先执行ready=true再执行number=42

结语:本篇幅较短,不能深刻的将多线程中有关重排序的问题的讲得透彻,若从发散思惟的角度来看来此问题,涉及到的相关知识点很是多,想深刻了解建议阅读<<Java并发编程实践>> <<深刻理解Java虚拟机>>并发

相关文章
相关标签/搜索