[英]How can two threads be “in” a “synchronized” method
我真的是Java兼容的新手,我正在嘗試實現以下規范:
這不是確切的規范,但我唯一的問題是:
我無法讓汽車在轉彎時跳過。 如果兩輛車選擇相同的位置,則一輛車停放,另一輛車等待直到公園空閑。 這不是我想要的行為。 我的第一個想法是簡單地將read和write同步到一個占用的變量:
class Car implements Runnable {
private CarState state = CarState.driving
run {
while(true) {
switch(state) {
case driving:
System.out.println(this + " driving.");
state = parking;
break;
case parking: Spot s = CarPark.getRandomSpot();
if(s.willingToPark(this)) {
System.out.println(s + " occupied. " + this
+ " skip park turn.");
} else {
s.park(this);
}
state = driving;
}
}
}
}
class Spot {
private boolean occupied = false;
private Car owner = new Car(...);
synchronized boolean willingToPark(Car c) {
if(occupied) {
return true;
} else {
occupied = true;
return false;
}
synchronized void park(Car c) {
System.out.println(c + " parking at " + this);
//don't care how this is implemented, just keep in mind
//that it will enter in a loop until the owner came back.
occupied = false;
}
}
如果我用三輛車運行這個,那么我最終會讓car0停在spot1,car1停在spot0,car2正在spot0上等待,因為car1正在執行同步的停車場(Car c)。 如果願意同步,兩輛車可以在同一地點停車怎么辦?
謝謝
如果願意同步,兩輛車可以在同一地點停車怎么辦?
它實際上很簡單。 Car1捕獲spot0並開始在park()
方法內的循環中等待所有者(您沒有提供代碼)。 在等待時,它擁有監視器並且不允許任何人在spot0上調用同步方法。
這就是為什么car2掛起了willingToPark()
方法的原因。
問題在於park
的循環。 想象一下:
s
。 s
上s
監視器鎖; 只有一個會成功。 park
旋轉, 同時仍然持有鎖 。 什么都沒有(沒有殺死JVM)會告訴線程無法停放,停止等待s
。 它會等到它可以獲得鎖定 - 這只會在第一個線程完成park
循環后才會發生。
解決方案不是在park
循環。 相反, 汽車應通過新方法unpark(Car)
取消設置被occupied
標志。 為了跨線程的內存可見性,還必須同步此方法。
現在數據流如下:
s
。 s
上s
監視器鎖; 只有一個會成功。 occupied = true
,並立即返回然后釋放s
上s
鎖 s
,並看到該地點被占用。 順便說一句,您甚至不需要synchronized
方法。 您可以使用AtomicBoolean的compareAndSet方法,它允許您以原子方式檢查AtomicBoolean的值,並僅在其當前值與您預期的值相同時進行設置。 因此, return occupied.compareAndSet(false, true)
表示“以原子方式檢查當前值;如果為false,則將其設置為true並返回true;如果為true,則保持原樣,然后返回false”。 這種行為很有用,但更先進一些。
使用AtomicBoolean標記停車位:
class Spot{
public final AtomicBoolean flag = new AtomicBoolean(false);
}
在代碼中的其他地方,汽車線程中有一場比賽搶奪點:
if(spot.flag.compareAndSet(false,true)){
// spot owned by current thread !!
// for other threads, `compareAndSet` will fail because they expect it to be `false`.
// visit store and buy stuff while car is parked.
// time to go, release the spot
spot.flag.set(false);
}else{
// find another spot
}
完整示例: http : //ideone.com/dw3LnV
這種方法是免費等待和鎖定免費的,您可以將點競賽邏輯放入while循環中,線程將繼續爭奪該標志。
進一步閱讀: http : //www.ibm.com/developerworks/library/j-jtp11234/
盧卡,我認為你沒有全面了解同步。 等待循環是問題所在。 至於同步本身,它只能在對象上完成:
synchronized
使得它在同步this
synchronized(someObject) {...}
使它在someObject
同步 調用synchronized方法時,它不允許任何其他同步方法使用它同步的對象。 因此,通過使用該循環,您可以鎖定其他所有內容。 正如其他人所說,您應該盡可能以最短的時間使用同步來完成任務。
例如,您可以僅在park方法中同步取消停放部分:
void park(Car c) {
System.out.println(c + " parking at " + this);
//don't care how this is implemented, just keep in mind
//that it will enter in a loop until the owner came back.
synchronized (this) {
occupied = false;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.