繁体   English   中英

在静态变量中使用同步

[英]Using synchronized in static variable

我有一张静态地图

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

有什么建议么?

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

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

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

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

修改cars 而没有调用synchronized 这将有可能此方法修改的“ABC”的车在同一时间,作为方法xyz()正在修改它(即违反线程安全的),因为它不包含调用任何代码synchronizedcars

如果要确保您的cars地图是线程安全的(即,决不能同时用两种方法修改),则必须

  1. 确保任何修改cars代码都首先synchronized(cars)调用synchronized(cars)
  2. 使用ConcurrentHashMap ,以确保对其进行放置和获取操作是线程安全的。

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

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

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

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

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

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

但是,如果您需要在多个方法调用之间进行同步(如果为空,则在获取后跟上put进行同步),则需要上述方法。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM