Java线程安全,数据竞争和良好的实现

时间:2011-12-05 10:34:15

标签: java spring-mvc thread-safety

我正在编写一个Spring控制器,声明一些私有hashmap并在某些方法中更新它们。当然,我知道并发访问的问题,所以我用最简单的方法来避免这些问题:“同步”java线程安全功能。但我想知道我是否应该同步我的方法或只需要线程映射我需要线程安全更新:

@Controller
public class myController{

private HashMap<String, String> myHashMap = new HashMap<String, String>();

...

//That way ?
public synchronized updateMyHashmap(){
myHashMap.add(value);
}

//or this way ?
public static void updateMyHashMap(){
synchronized(myHashMap){
myHashMap.add(value)
}
}

}

这些方法是等价的吗?我是否会有相同的申请行为?

4 个答案:

答案 0 :(得分:3)

这些方法不相同。

方法上的

synchronizedthis上进行同步,因此:

public synchronized updateMyHashmap(){
    myHashMap.add(value);
}

相当于:

public updateMyHashmap(){
    synchronized(this) {
        myHashMap.add(value);
    }
}

此处,thismyController的实例。 (旁注:通常建议用大写字母在Java中启动类名)。

第二种方法不正确,不应编译,因为您从静态方法访问非静态成员(myHashMap)。

假设它不是静态的,它将在hashmap而不是myController实例上同步。

您要同步的内容几乎肯定取决于您在此同步块中要执行的其他操作(例如,此value来自何处,是否必须从其他位置获取,以及是否需要使用myController实例来同步整个操作。

我建议您阅读Java Concurrency in Practice以了解有关同步问题的更多信息。

答案 1 :(得分:2)

如果myHashMap变量是私有的并且只能通过myController方法访问,那么您只需要同步这些方法。换句话说,如果您同步方法,它们将是线程安全的,但如果您在不使用同步块/方法的情况下直接访问myHashMap变量,则可以破坏锁定。

更简单地说。如果你的房间有一扇门,允许一个人一次进入,那么你一次只能在房间里有一个人......但是如果你在房间里放一个窗户,那么你仍然可以跳进通过窗户的房间。 :)

编辑:详细说明。通过将方法上的synchronized作为关键字放置,您将为整个方法创建关键部分,这意味着从方法调用到结束时,其他任何东西都无法在该对象中运行。通过使用关闭块,您可以根据需要跳入和跳出关键部分。假设您有一个100行的方法,对于使用共享资源需要10行,如果您在方法上放置同步,则对象将被锁定为整行100行代码,但是如果您只将锁定放在10行你需要的行,你只有10行的关键部分。

所有关于你所处的情况。对于你给出的例子,绝对没有区别。

答案 2 :(得分:0)

我会使用ConcurrentHashMap而不用手动同步访问。

使方法静止不会对你有所帮助;特别是因为你需要一个对象来同步,这通常就是这个。

答案 3 :(得分:0)

这两个是不同的东西,但可以用来实现同样的目的。

见这里,

//Here you are locking your method
public synchronized updateMyHashmap(){

   System.out.println("Inside method");

   //some code

   myHashMap.add(value); 
}

现在用这个方法

public updateMyHashmap(){

  //Some code here

  System.out.println("Inside method")

  synchronized(this) {
      myHashMap.add(value);      
  }
}  

所以我认为你现在可以很容易地看到这两种策略之间的区别。这取决于你想做什么,并根据你可以选择其中任何一个。

建议您同步要锁定的对象。