在Java多线程中,"private final Object"锁的用途是什么?

8
在Java多线程中,“private final Object”锁有何用途?
据我所知,为了使一个类具备线程安全性,我们应该使用内置锁,其中我们将所有方法标记为同步,并使用“this”在对象的监视器上锁定它们。或者,我们可以将类中标记为“this”的同步方法替换为在方法内部使用的私有最终对象锁来锁定通用对象锁,以使其具备线程安全性。
以下是使用内置锁的示例代码:
public class Counter{

 // Locks on the object's monitor
 public synchronized void changeValue() { 
   // ...
 }

我们可以使用以下外部锁替换上述代码:

}

public class Counter{
 private final Object lock = new Object(); // private final lock object

  public void changeValue() {
   synchronized (lock) { // Locks on the private Object
  // ...
       }
  }
}

使用上述的外部锁使类成为线程安全的是否可取,而不是使用内部锁定?如果我的理解有误,请纠正我。

这仅仅是使得对类的访问同步 - 这并不等同于线程安全。(除非每个公共方法都实现了单一逻辑“事务”。) - millimoose
3个回答

9
Oracle安全编码标准 包含了您所需的所有信息。
基本上,它是为了防止这种情况发生:声明为 synchronized 的方法和在 this 引用上同步的块都使用对象的监视器(即其固有锁)。攻击者可以操纵系统以触发争用和死锁,通过获得并无限期地持有可访问类的固有锁,从而导致拒绝服务(DoS)。

1
它还可以避免意外的拒绝服务或过于粗略的锁定,当两个不同的级别无意中为不同的事情使用相同的锁时。 - Stephen C
嗨,亨利克,我看了这篇文章,感谢提供的链接。有一件事仍然不清楚,如果不使用上述方法创建线程安全类,是否应该使用客户端锁定。 - rookie_ron
有没有这样的DoS攻击的示例? - kamaci

0

这条规则解决了在同步块中使用什么类型的监视器对象的问题。 总结文章,建议使用外部锁(也称为 私有锁对象惯用语法)。

  1. 将锁定放在无法更改的对象实例上使同步更加一致。当同步对象无法更改时,很难破坏同步。
  2. 由于锁定在特定对象上,即使线程正在同步块上工作,其他类资源也可用。这使代码更加健壮,不易受死锁影响。

0
以下示例清楚说明了何时使用:
public class Foo {
    // Locks on the object's monitor
    public synchronized void changeValue() {
        // ...
    }
    public static Foo changeState(String name) {
        // Manipulate on Foo 
        return obj;
    }
    public static void main(String[] args) throws InterruptedException {
        // Untrusted code
        String name = "test" ;
        Foo foo = Foo.changeState(name);
        if (foo == null) {
            throw new IllegalStateException();
        }
        synchronized (foo) {
            while (true) {
                // Indefinitely lock someObject
                Thread.sleep(Integer.MAX_VALUE);
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接