2012-04-30 167 views
0

對於下面的例子的對象:爪哇等待在另一個線程

public Car getCar(int id){ 
    Car result= findCarInCache(id); 
    if (result==null){ 
     // POINT A 
     return createCarWithId(id); 
    } else { 
     return result; 
    } 
} 

public Car findCarInCache(int id){ 
    // Do something for find a car with this id in the cache 
} 

public void addToCache(Car car){ 
    // Add the car to the cache 
} 

public Car createCarWithId(int id){ 
    Thread.sleep(10000); 
    Car result= new Car(id); 
    addToCache(Car); 
    return result; 
} 

問題是當兩個線程調用同時getCar(2)例如。然後兩個線程都到達POINT A,並且生成Car#2的兩個實例。我如何讓第二個線程在POINT A處等待,直到第一個線程完成創建,然後在兩個調用中返回相同的對象? (我在Android中這樣做)

感謝

+0

http://docs.oracle.com/javase/tutorial/essential/concurrency/。或者類似的,一本關於java的初學者書。如果你使用線程,你需要了解併發性 –

回答

6

正確的方法是添加一個​​段某處這可以確保只有一個線程可以在同一時間進入該塊。

您問具體有關POINT A,所以你可以使createCarWithId同步。

public synchronized Car createCarWithId(int id){ 

這將鎖定具有該方法的對象的this。這裏有一些關於synchronized methods的文檔。

但是,您需要保護將Car添加到高速緩存,以便在高速緩存中找到它,因爲多個線程將同時使用高速緩存。出於這個原因,您還需要製作findCarInCache​​。此外,由於你不想在getCar鎖定兩次,應該也可能是​​:

public synchronized Car getCar(int id){ 
... 
public synchronized Car findCarInCache(int id){ 
... 
public synchronized Car createCarWithId(int id){ 

如果你想降低您鎖定的範圍,作爲替代,你可以創建一個鎖定對象,你可以synchronize上:

private final Object lockObject = new Object(); 
... 

public Car getCar(int id){ 
    synchronized (lock) { 
     ... 
    } 
} 
public Car findCarInCache(int id){ 
    synchronized (lock) { 
     ... 
    } 
} 
public Car createCarWithId(int id){ 
    synchronized (lock) { 
     ... 
    } 
} 

這裏有lock objects更多的文檔。

+0

感謝您的回答,這是非常有用的。所以,如果我想要createCarWithId()方法是同步的,但只有具有相同id的汽車之間,我應該實現某種單身檢索與該id相關聯的lockObject,對吧?還是有更簡單的形式? – Addev

+0

不,我不認爲你需要那個有限範圍@Addev的鎖。我只需要在添加和緩存放置周圍有一個同步塊,並將其留在那裏。即使你關心比賽的唯一時間是如果id是相同的,在每個id基礎上創建某種鎖的映射也需要同步,所以它不值得。 – Gray

+0

也@Addev,你的緩存也需要同步,所以你可能想要真正鎖定'getCar'和'createCarWithId'。任何你在多線程(緩存)中改變的東西都需要保護。我要編輯我的回覆。 – Gray