在静态变量中使用synchronized

时间:2012-07-24 02:35:16

标签: java multithreading static-variables

我有一张静态地图

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");
    }
}

任何建议?

3 个答案:

答案 0 :(得分:4)

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

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

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

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

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

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

  1. 确保修改cars的所有代码首先调用synchronized(cars)
  2. 使用ConcurrentHashMap,保证对它的put和get操作是线程安全的。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:0)

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

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

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

但是,如果需要在多个方法调用之间进行同步(如果某些内容为null,则get之后是put),将需要您的上述方法。

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