1

我有一个静态地图

private static Map<String, Car> cars = new HashMap<~>() //Map holding car objects

我在方法中使用变量,例如

private static String getCar(String name){
    return cars.get(name);
}

因此,如果我想锁定汽车,是否可以像下面那样进行线程安全。

private static void xyz() {
    synchronized(cars) {
        Car c = getCar("abc");
        c.setColor("Green");
    }
}

有什么建议么?

4

3 回答 3

4

Java 的synchronized关键字可以应用于任何对象以在继续之前对该对象“获取锁”(或“同步”该对象)。如果任何其他进程试图同时在同一对象上运行同步代码,它将阻塞,直到锁定该对象的进程退出同步块。

您同步的对象不必在synchronized块的任何部分实际使用;它可能是一个简单的互斥对象,其唯一目的是在同步块中锁定和解锁。但是,重要的是要注意,如果其他线程没有在该对象上进行同步,那么简单地在一个对象上同步并不会阻止它们修改它。它是程序员/约定强制执行的锁,而不是内置锁,所有使用共享对象的代码都必须“同意”在其上进行同步。

例如,使用您上面编写的代码,即使您的xyz()方法在 上同步cars,您也可以编写另一个方法,如下所示:

public void changeCar() {
    Car myCar = cars.get("abc");
    myCar.setColor("Blue");
}

cars 无需调用即可修改synchronized。此方法可能会在您的方法修改“abc”汽车的同时xyz()修改它(即违反线程安全),因为它不包含任何调用synchronizedon 的代码cars

如果您想确保您的cars地图是线程安全的(即从不同时被两种方法修改),您必须要么

  1. 确保任何修改cars首次调用的代码synchronized(cars)
  2. 使用ConcurrentHashMap,它可以保证对它的 put 和 get 操作是线程安全的。
于 2012-07-24T02:55:35.793 回答
1

很好,但请注意,使用您当前的代码,您并没有完全锁定汽车对象,您仍然可以通过其他方法访问汽车并设置属性,除非您再次在汽车对象上同步

public static void otherMethod() {
  synchronized(cars) {
     Car myCar = cars.get("abc");
     myCar.setColor("Red");
  }
}

但是如果方法 xyz() 是您设置属性的唯一位置,那么您的代码是线程安全的。

于 2012-07-24T03:05:27.727 回答
0

如果您只担心单个方法同步,请使用

Map<String, Car> synchronizedMap = Collections.synchronizedMap(map);

这将自动为映射中的所有方法添加同步,并使每个方法调用原子。这是您可能应该向您的线程公开的地图。

但是,如果您需要跨多个方法调用进行同步(如果某些内容为空,则 get 后跟 put),则需要上述方法。

请注意 Car 对象也需要是线程安全的,并且在没有看到该方法的情况下,我不能说它是否是。

于 2012-07-24T03:48:54.230 回答