測試用volatile修飾一個對象,該對象里的成員變量是否能受到volatile影響超全。
按照之前的理論推測: volatile修飾一個對象咆霜,其應(yīng)該只能保證引用地址的可見性。 對象的具體內(nèi)容的修改嘶朱,應(yīng)該無法保證其可見性蛾坯。
先說結(jié)論:以上的推測是錯的, volatile修飾一個對象時疏遏,也可以保證該對象的成員變量(未用volatile修飾)的可見性脉课。但是,不建議使用改览,這種寫法在sonar代碼掃描中也會報警告:Non-primitive fields should not be "volatile"下翎。意思就是非基本字段不應(yīng)該用volatile修飾。
測試代碼如下:
一宝当、控制單一變量來測試视事, 首先,對象跟對象的成員變量都不加volatile修飾
@Data
public class VolatileObj {
private int flag = 0;
}
public class TestVolatile {
private VolatileObj volatileObj = new VolatileObj();
private volatile boolean stop = false;
@Test
public void test() throws InterruptedException {
System.out.println("程序開始");
Thread thread1 = new Thread(
() -> {
int flag ;
while ((flag = volatileObj.getFlag()) < 10000 && !stop){
volatileObj.setFlag( ++ flag);
System.out.println("flag增加為:"+ flag + "此時stop="+ stop);
}
}
);
thread1.start();
Thread thread2 = new Thread(
() -> {
while (true){
if (volatileObj.getFlag() >= 5000){
System.out.println("修改stop值");
stop = true;
break;
}
}
System.out.println("修改后的stop值:" + stop);
}
);
thread2.start();
thread2.join();
}
}
運(yùn)行結(jié)果如下:程序阻塞住庆揩,因為thread2 線程沒有獲取到最新的flag值俐东,導(dǎo)致其死循環(huán)
...
flag增加為:9997此時stop=false
flag增加為:9998此時stop=false
flag增加為:9999此時stop=false
flag增加為:10000此時stop=false
二、對象不加volatile修飾订晌,對象的成員變量添加volatile修飾
@Data
public class VolatileObj {
private volatile int flag = 0;
}
運(yùn)行結(jié)果:程序正常結(jié)束虏辫。 thread2 線程發(fā)現(xiàn)flag的變化, 進(jìn)而修改stop標(biāo)識
...
flag增加為:8292此時stop=false
flag增加為:8293此時stop=false
flag增加為:8294此時stop=false
修改stop值
flag增加為:8295此時stop=false
修改后的stop值:true
三锈拨、 對象加volatile修飾砌庄,對象的成員變量不加volatile修飾
public class TestVolatile {
private volatile VolatileObj volatileObj = new VolatileObj();
private volatile boolean stop = false;
@Test
public void test() throws InterruptedException {
System.out.println("程序開始");
Thread thread1 = new Thread(
() -> {
int flag ;
while ((flag = volatileObj.getFlag()) < 10000 && !stop){
volatileObj.setFlag( ++ flag);
System.out.println("flag增加為:"+ flag + "此時stop="+ stop);
}
}
);
thread1.start();
Thread thread2 = new Thread(
() -> {
while (true){
if (volatileObj.getFlag() >= 5000){
System.out.println("修改stop值");
stop = true;
break;
}
}
System.out.println("修改后的stop值:" + stop);
}
);
thread2.start();
thread2.join();
}
}
運(yùn)行結(jié)果: 程序正常結(jié)束, thread2 線程發(fā)現(xiàn)flag的變化奕枢,進(jìn)而修改stop標(biāo)識
...
flag增加為:5226此時stop=false
flag增加為:5227此時stop=false
flag增加為:5228此時stop=false
flag增加為:5229此時stop=false
修改stop值
修改后的stop值:true
flag增加為:5230此時stop=false