Java Synchronized如何比较锁定的对象?

时间:2013-05-21 16:31:39

标签: java multithreading synchronization

我想在多个API请求上锁定一个对象,这样每个用户只能有一个请求输入一段代码。

synchronized(obj)根据对象的引用或其hashCode()函数锁定吗?

即。我可以这样做:

synchronized("asdf") {
    doSomethingNifty();
}

这里“asdf”有一个唯一的哈希,但没有唯一的引用。

3 个答案:

答案 0 :(得分:12)

  

synchronized(obj)是否根据对象的内存位置或其toHash()函数进行锁定?

都不是。它锁定在与对象关联的监视器上。就JVM而言,我们不讨论对象的内存地址,因为它是可重定位的,而不是哈希代码(即使是Object.hashcode()),因为它不是唯一的。

应该锁定的内容而言,它应该是相同的final对象。类似的东西:

private final Object lockObject = new Object();
...
synchronized (lockObject) {
   // do stuff that needed to be protected
}

您希望它为final,以便可以保证多个线程锁定在不更改的同一对象引用上。 private很好,所以外部类不能搞砸类内部的锁定。

  

这里“asdf”有一个唯一的哈希值,但没有唯一的内存地址。

"asdf" 具有唯一的哈希值,因为其他字符串可能具有相同的哈希值,实际上可能在所有用法中都有唯一的“内存地址”如果编译器将其存储在Java string pool中,则应用程序中的“asdf”。这意味着一些完全不同的类也可能具有相同的错误模式代码块,并且会影响类的同步,因为它将锁定在同一个String对象实例上。这就是private锁定对象如此重要的原因。

当我们讨论这个主题时,你也必须永远不要像可能的BooleanInteger这样的非最终对象同步。经常使用以下模式,这是非常错误的:

Boolean value = false;
...
// really bad idea
synchronized (value) {
   if (value) {
      value = false;
   } else {
      value = true;
   }
}

非常错误,因为value引用正在发生变化。因此,一个线程可能会锁定它,然后更改它的引用值,以便另一个线程锁定另一个对象,并且两个线程同时位于synchronized内。更糟糕的是因为Boolean只有truefalse的两个值是常量,因此多个类将锁定在相同的引用上。

答案 1 :(得分:2)

您正在通过对象进行同步,内存地址问题纯粹是一个实现问题,与您无关。只要它是相同的对象(意味着完全相同的实例),就完成了同步。

如果使用其他实例,则同步将不起作用。你可以做的是将一个公共静态常量定义为锁:

public final static Object LOCK = new Object();

并使用它

synchronized(SomeClass.LOCK) {

答案 2 :(得分:0)

锁定在对象本身的实例上,如果您想这样想,可以将其视为内存位置。所以你所建议的不会起作用。

相反,听起来你只需要一个对应于你想要保护的代码块的对象。因此,在程序的设置过程中,您需要类似

的内容
static Object lockObject = new Object();

然后你可以做

synchronized(lockObject) {
    doSomethingNifty();
}

但是,如果doSomethingNifty()与特定对象相关,那么使用该对象而不是lockObject会很有意义。还要确保doSomethingNifty()执行起来很快,否则会有很多用户等待。