使用String参数加锁时,加锁的对象是什么?
What object is the lock on when a String parameter is used for locking?
我在其中一个回购协议中遇到过这样的代码。我检查了一下,它有效。 (只有一个线程进入同步块。)
public Void hello(String s) {
synchronized (s) {
i++;
System.out.println(i);
}
return null;
}
我的问题是锁是在字符串 class 本身上获得的吗?如果是,是否意味着如果代码库中的其他地方存在这样的代码,它们都会等待获得对同一对象的锁定?从而增加不必要的延迟?
String 对象上的内部锁是获取的锁。但是锁定是否有效取决于字符串是否始终是同一实例。字符串池和实习会影响这一点。
很难确定是否会使用同一个实例只是不这样做的原因之一。
如果应用程序中的两个 类 使用相同的字符串实例,那么其中一个可以获得锁并将另一个关闭。所以你可以让概念上不相关的对象相互影响,争用同一个锁。
人们也会感到困惑,认为他们可以使用字符串值来表示某些东西,并让代码在同步块或方法中更改 s 的值。这将打破所有的锁定。锁在对象上,而不是在变量上。更改值意味着当前持有锁的线程现在拥有旧对象,但试图进入的线程正在尝试获取新对象的锁,线程可以获取新对象并在前一个线程完成之前开始执行同步代码.
它有时可能会偶然工作,但这是一个糟糕的主意。使用专用对象作为锁:
private final Object lock = new Object();
我在其中一个回购协议中遇到过这样的代码。我检查了一下,它有效。 (只有一个线程进入同步块。)
public Void hello(String s) {
synchronized (s) {
i++;
System.out.println(i);
}
return null;
}
我的问题是锁是在字符串 class 本身上获得的吗?如果是,是否意味着如果代码库中的其他地方存在这样的代码,它们都会等待获得对同一对象的锁定?从而增加不必要的延迟?
String 对象上的内部锁是获取的锁。但是锁定是否有效取决于字符串是否始终是同一实例。字符串池和实习会影响这一点。
很难确定是否会使用同一个实例只是不这样做的原因之一。
如果应用程序中的两个 类 使用相同的字符串实例,那么其中一个可以获得锁并将另一个关闭。所以你可以让概念上不相关的对象相互影响,争用同一个锁。
人们也会感到困惑,认为他们可以使用字符串值来表示某些东西,并让代码在同步块或方法中更改 s 的值。这将打破所有的锁定。锁在对象上,而不是在变量上。更改值意味着当前持有锁的线程现在拥有旧对象,但试图进入的线程正在尝试获取新对象的锁,线程可以获取新对象并在前一个线程完成之前开始执行同步代码.
它有时可能会偶然工作,但这是一个糟糕的主意。使用专用对象作为锁:
private final Object lock = new Object();