1.禁止指令重排序
``
public class VoliatlieTest3 {
private volatile VoliatlieTest3 singleInstace;
private VoliatlieTest3() {
}
public VoliatlieTest3 getSingleInstace() {
if (singleInstace == null) {
synchronized (VoliatlieTest3.class) {
if (singleInstace == null) {
singleInstace = new VoliatlieTest3();
}
}
}
return singleInstace;
}
}
``
singleInstace = new VoliatlieTest3()
这个代码分3个指令:
1.分配内存空间
2.初始化对象
3.将singleTon指向分配的内存
第二步和第三步可能会次序不一样
那么多线程这里会出问题
现在有线程A,B
如果A线程运行到singleInstace = new VoliatlieTest3(),并且这里指令被重新排序了,现在执行执行了
1.分配内存空间
2.将singleInstace指向分配的内存
执行到这里的时候singleInstace就!= null了,但实际还是空的
这个时候线程B正好过来了,判断singleInstace 不为空,然后返回了,此时B线程返回的就是空的对象
2.保证对象(基本数据类型)可见性,
``
public class VoliatlieTest2 extends Thread {
//这里 volatile 会使线程内存中的变量从主内存中获取flat,如果没有这个关键字,则下面的进程不会退出,每次打印的i都是不一样的;
volatile boolean flat = false;
int i = 0;
@Override
public void run() {
while (!flat) { i++; }
}
public static void main(String[] args) {
VoliatlieTest2 voliatlieTest2 = new VoliatlieTest2();
voliatlieTest2.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
voliatlieTest2.flat = true;
System.out.println(voliatlieTest2.i);
System.out.println(voliatlieTest2.i);
}
}
``
主线程里面,flat 初始值是false, i初始值是0
子线程voliatelieTest2启动起来后,如果flat是false对i进行++,主线程休眠1秒主线程将flat改为true
打印2次i的变量
这里虽然将flat改为true了,但是子线程还会对执行i++,可以理解为子线程操作的是自己内存中的那个flat, 没有和主线程中的flat进行同步,主线程的flat被改为true了 但是子线程读取的flat还是flase,如果flat用volatile修饰,主线程将flat改为true后,子线程读取的flat就会是true 也就是i++就不会再执行了,打印的值就是相同的数
网友评论