[英]How to use volatile correctly in Java
我正在研究Java Thread,當我分析從例8.3.1.4修改的以下代碼時,關鍵字volatile
會讓我感到困惑
public class Volatile {
public static void main(String[] args){
MyRunnable1 myRunnable1 = new MyRunnable1();
MyRunnable2 myRunnable2 = new MyRunnable2();
Thread t1 = new Thread(myRunnable1);
Thread t2 = new Thread(myRunnable2);
t1.start();
t2.start();
}
}
class MyRunnable1 implements Runnable{
public void run(){
while(true){
Test1.one();
}
}
}
class MyRunnable2 implements Runnable{
public void run(){
while(true){
Test1.two();
}
}
}
class Test1{
static volatile int i = 0;
static volatile int j = 0;
static void one(){
i ++;
j ++;
}
static void two(){
System.out.println("i = " + i + " j = " + j);
}
}
輸出段:
i = 60778110 j = 60778116
i = 60778402 j = 60778407
i = 60778630 j = 60778636
i = 60779062 j = 60779079
i = 60779492 j = 60779497
i = 60779784 j = 60779789
i = 60780161 j = 60780169
i = 60780625 j = 60780632
i = 60780936 j = 60780942
我的想法是,由於volatile
, i ++
發生在j ++
之前,它們的初始值為零,修改后的值將立即刷新到主存儲器,因此i
線程t2
看到的任何時候都應該大於j
。 但是輸出顯示i
總是低於j
。
然后我修改這two
函數如下:
static void two(){
System.out.println("j = " + j + " i = " + i);
}
的變化是, j
輸出之前i
,然后輸出段如下:
j = 47324409 i = 47324412
j = 47324587 i = 47324593
j = 47324808 i = 47324813
j = 47324991 i = 47324996
j = 47325193 i = 47325196
j = 47325347 i = 47325353
令我驚訝的是, j
總是低於i
。
我的想法是j
是較低的,因為它首先被連接,並且在i
連接一段時間之后,在時間間隔期間, one
函數執行導致i
增加。
所以第一個連接值將低於第二個連接值,是不是? 提前致謝!
你猜對了。 不同之處在於println
調用的參數分為3個步驟:
在Runnable2執行此操作時,特別是在step1之后和最終打印之前,Runnable2正忙於遞增值。 這會導致你看到的行為。
這不是揮發性的問題。 如果希望i和j同步,則必須同步Test1類的方法。
實際上, volatile
只是阻止線程緩存一個值,而是強制“直寫”和“讀取”:如果一個線程緩存一個變量並由另一個線程更新,那么第一個線程的值可能永遠不會改變,因為Java的緩存策略,不需要刷新其緩存。
因此,每當您有多個線程訪問和更改原始資源(如int,boolean或引用類型引用值本身)時,您應該使用volatile。
這本身並不意味着volatile實際上使變量訪問線程安全!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.