[英]Java happens-before relationship
雖然SO和其他地方有很多關於之前發生過的關系的帖子,但我很難找到對我的問題的確切答案。
考慮兩個Java線程:
最初, flag == false
和data == 0
T1
data = 42;
synchronized(m) {
flag = true;
}
T2
boolean f;
synchronized(m) {
f = flag;
}
if (f) {
int x = data;
}
根據上面的代碼,我相信f
可以被賦值為true
或false
,沒有guaruntee。 它是否正確?
現在,如果兩個synchronized
語句被更改為synchronized(flag)
,我認為指令flag = true
將始終發生在指令f = flag
,因此f
將始終被賦值為true
。 它是否正確?
不,同步不保證首先到達哪個Thread
。 僅保證多一個Thread
不能一次訪問同步塊。
將synchronized
塊視為門上有鎖的房間。 我們不知道誰會首先到達門口,但一旦他們這樣做,他們就會進門並鎖上門。
其他人必須等到房間里的人准備離開並解鎖門。 一旦發生這種情況,每個人都會再次參加比賽。
這一切都取決於您關閉Thread
的順序。 但即便如此,也沒有任何保證,因為JVM可能會隨機地暫停Thread
和Thread
的yield
。 在類比中 - 領先到門的人可能會在香蕉皮上絆倒。 不太可能,但總是可能的。
如果你想要保證,那么你需要wait
/ notify
- 以便讀取線程檢查flag
,如果它是false
,則在循環中掛起自己。
寫入線程然后設置flag
並通知鎖定監視器喚醒讀取線程。
下面是一個使用Java 5中的Lock
和Condition
api的示例。我並不是說你必須優先使用它來synchronized
和wait
/ notify
- 這只是我躺在我適應的一個例子。
Reader
獲取lock
,然后在循環中檢查ready
標志。 如果該標志為false
則await
該條件。 這會以原子方式釋放lock
並掛起Thread
。
Writer
同時獲取lock
並設置data
和ready
標志。 然后它調用signalAll
並釋放lock
。
這會喚醒Reader
,然后讀取ready
為true
並繼續執行print
語句。
輸出將始終為42
(從不為-1
)。
public class App {
static volatile boolean ready = false;
static volatile int data = -1;
private static class Reader implements Runnable {
private final Lock lock;
private final Condition condition;
public Reader(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
while (!ready) {
try {
condition.await();
} catch (InterruptedException ex) {
//oh well
}
}
System.out.println(data);
} finally {
lock.unlock();
}
}
}
private static class Writer implements Runnable {
private final Lock lock;
private final Condition condition;
public Writer(Lock lock, Condition condition) {
this.lock = lock;
this.condition = condition;
}
@Override
public void run() {
lock.lock();
try {
data = 42;
ready = true;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) throws InterruptedException {
final ExecutorService executorService = Executors.newFixedThreadPool(2);
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
executorService.execute(new Reader(lock, condition));
executorService.execute(new Writer(lock, condition));
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.