2012-04-30 125 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