如何从主内存中获取变量并且赋值?
首先,内存只是用来存储数据的,它并不能进行赋值,赋值都是通过cpu进行赋值的,如何赋值呢,
cpu会从主内存中拷贝变量,然后通过缓存一致协议到当前线程的副本中进行赋值,一般主内存开始的变量值肯定是空的,
我们在当前线程的副本中将其赋值后会刷新到主内存中,如果是单线程的话一般是没有问题的,直接刷新就可以到竹内存中,
但是如果是多线程的话,就会出现顺序混乱的问题,我们就拿单例来举例,来看下面的代码:
private static TestApp testApp;
public static TestApp getInstance(){
//双重锁定
if (testApp == null){
//保证此方法一次只能进入一个线程
synchronized (TestApp.class){
if (testApp == null){
//给主内存拷贝来的变量赋值
testApp = new TestApp();
}
}
}
//刷新值到主内存中
return testApp;
从上面代码可以看到我对这个单例的处理,这样看大家会发现什么?看似是不是一点问题都没有,但是,它是有问题的,问题就在多线程并发上面,第一个线程进入这个方法给变量赋值,对这没问题,其他线程也进不来的,但是如果第一个线程执行完赋值的操作,synchroized就会释放,呢么第2个线程就会进来,这时候return testApp这个值并没有刷新到主内存,但是赋值操作又被执行了一次,这个变量又被new了一个新的对象,这时候return返回的值该属于谁呢?没错就是线程2,这就导致了对这个变量进行赋值并且刷新到主内存时候的顺序就混乱了。
如何处理多线程获取内存中变量赋值时顺序混乱的问题?
//此变量被volatile修饰
private static volatile TestApp testApp;
public static TestApp getInstance(){
//双重锁定
if (testApp == null){
//保证此方法一次只能进入一个线程
synchronized (TestApp.class){
if (testApp == null){
//给主内存拷贝来的变量赋值
testApp = new TestApp();
}
}
}
//刷新值到主内存中
return testApp;
在看这次代码,比上次是不是多了某个操作呢?对,没错,就是volatile,它的特性是什么呢?就是可见,有序,和内存屏障,
对,你没看错,注意那个“有序”,我们用其修饰这个变量,就会让这个变量赋值变的有序,不会导致重新被new一个新的对象,
当第一个线程进入sychroized时,如果没有处理完成,它是不会释放的,就会保证一次只能进入一个线程,也就根本不会导致
对象被重新赋值,这样是不是也就解决了因为多线程的并发从而导致的顺序混乱问题,线程1拿走主内存的变量然后赋值,通过
以上操作就可以刷新到主内存中,当第一个线程处理完成才轮得到第2个线程,以此类推这个问题就能完美解决了。