簡體   English   中英

Java中的同步和代碼重新排序

[英]Synchronized and Code reorder in java

在某些鏈接中,可以認為在同步塊內可以對代碼進行重新排序,而在其他站點則無法實現。 您能舉一個例子來說明使用同步時代碼重新排序的實際情況嗎?

有兩種可能的重新排序:

  • 同步塊之前或之后的語句可以在同步塊內移動(前提是它們當然不在不同的同步塊中)-有時稱為“蟑螂汽車旅館”原則
  • 只要修改順序一致,就可以對同步塊內的語句進行重新排序(即,從與該塊共享事前關系的其他代碼中看不到效果)

但更重要的是: 如果代碼正確同步,則這些重新排序不會影響程序的執行 ,這是您應該關心的全部。

示例(所有變量本來都為0):

線程1:

a=1;
synchronized(lock) {
    b=1;
    c=1;
}
d=1;

線程2:

synchronized(lock) {
    if (a==1) print(b); // can print 0 or 1
    if (b==1) print(a)/print(c); // always prints 1
    if (b==1) print(d); // can print 0 or 1
    if (d==1) print(a)/print(b)/print(c); // always prints 1
}

特別是,允許​​將d=1移到c=1之前或將a=1移到b=1之后,因為這不是線程2能夠觀察到的,因為線程1執行的同步塊看起來像原子的從線程2操作。

另一方面,不使用相同鎖的線程將能夠觀察到這些重新排序。

只要遵守之前發生的情況,運行時就可以對操作進行重新排序。 規范寫道

應當指出的是,兩個動作之間存在先發生關系並不一定意味着在實現中它們必須按照該順序進行。 如果重新排序產生的結果與合法執行相符,則不合法。

更具體地說,如果兩個動作共享事前發生關系,則它們不一定必須按照順序與沒有事前發生關系的任何代碼發生過關系。 例如,在一個數據競爭中的一個線程中進行寫操作而在另一個線程中進行讀操作可能看起來與這些讀操作的發生順序不一致。

特別是,如果一個線程這樣做:

synchronized (lock) {
    x = 1;
    y = 1;
}

另一個則:

if (y == 1) System.out.println(x);

這些線程之間沒有“事前發生”的關系,另一個線程可能觀察到yx被分配之前就已經被分配了,並輸出0。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM