当String作为锁的对象时,String.intern()和Striped哪个更好?
想象一下这样一个场景,我们需要根据设备 id 进行锁定,设备 id 是一个字符串。很多人推荐使用String.intern()
作为锁对象,但也有人推荐使用Striped
进行并发控制,比如下面的代码:
import com.google.common.util.concurrent.Striped;
import java.util.concurrent.locks.Lock;
public class Test {
private Striped<Lock> striped = Striped.lock(8);
public void businessLogicByStringIntern(String deviceId) {
// use deviceId.intern() as lock
synchronized (deviceId.intern()) {
// execute code thread-safely
}
}
public void businessLogicByStriped(String deviceId) {
// use striped lock
synchronized (striped.get(deviceId)) {
// execute code thread-safely
}
}
}
更推荐哪种实现, businessLogicByStringIntern
还是 businessLogicByStriped
?
Imagine a scenario where we need to lock based on the device id, which is a string. Many people recommend using String.intern()
as the lock object, but some people recommend using Striped
for concurrency control, such as the following code:
import com.google.common.util.concurrent.Striped;
import java.util.concurrent.locks.Lock;
public class Test {
private Striped<Lock> striped = Striped.lock(8);
public void businessLogicByStringIntern(String deviceId) {
// use deviceId.intern() as lock
synchronized (deviceId.intern()) {
// execute code thread-safely
}
}
public void businessLogicByStriped(String deviceId) {
// use striped lock
synchronized (striped.get(deviceId)) {
// execute code thread-safely
}
}
}
Which implementation is more recommended, businessLogicByStringIntern
or businessLogicByStriped
?
Reference:
Striped (Guava: Google Core Libraries for Java 19.0 API)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在第一个版本中,您将获得每个设备的唯一锁定,通过
deviceId
字符串进行区分。在这种情况下,实习生
是必要的。在第二个版本中,您只有(比如说)8 个锁,并且它们在所有设备上呈条带状。
有什么区别?
第一个版本创建了更原始的锁。但原始锁很便宜,除非存在锁争用。在此版本中,只有当两个或多个线程确实尝试使用同一设备执行某些操作时,才会发生锁争用。
第二个版本永远不会创建超过 8 个锁,并且它们是
Lock
对象。Lock
API 提供了比原始锁更多的功能……如果这对您有用的话。但是在这个版本中你会遇到更多的争论。例如,如果两个不同的设备使用相同的条带锁,那么这两个设备就会互斥……这可能是您不希望看到的。
使用内部字符串作为锁标识符还存在一个理论上的问题。驻留字符串的空间是 JVM 范围内的,因此如果应用程序的不同部分独立以这种方式锁定事物(例如使用驻留设备 ID 字符串),它们可能会产生干扰。应用程序的两个部分可能最终会意外共享锁。 (这个问题在 https://stackoverflow.com/a/134154/5973816. 中有更深入的讨论。
)如果这是一个真正的问题,可以采取一些方法来避免这种情况。例如,应用程序的两个部分可以在实习之前向字符串添加(不同的)前缀等。
哪个更好?
这取决于 1) 您要优化的内容以及 2) 锁可以持有多长时间;即由条带化引起的不必要的争用的成本。
在大多数情况下,第一个版本(每个设备都有一个不同的锁)会更好。但是,如果您拥有大量设备,则大量驻留字符串的成本可能会很高。在这种情况下,如果锁持有的时间很短,那么分条锁可能会更好。
In the first version, you get a unique lock per device as distinguished by the
deviceId
string. Theintern
is necessary in this case.In the second version, you have only (say) 8 locks and they are striped across all of the devices.
What is the difference?
The first version creates more primitive locks. But primitive locks are cheap unless there is contention on a lock. With this version you only get lock contention if two or more threads are really trying to do something with the same device.
The second version never creates more than 8 locks, and they are
Lock
objects. TheLock
API provides more functionality than a primitive lock ... if that is useful to you.But with this version you get more contention. For example, if two different devices use the same striped lock, you get mutual exclusion for those two devices ... which you probably don't want.
There is also a theoretical issue with using interned strings as lock identifiers. The space of interned strings is JVM wide, so if you have different parts of your application independently locking things this way (e.g. using the interned device id strings), they can potentially interfere. The two parts of the application might end up accidentally sharing locks. (This issue is discussed in more depth in https://stackoverflow.com/a/134154/5973816.)
There are ways to avoid this if it is a real issue. For example, the two parts of the application could add (different) prefixes to the strings before interning, etc.
Which is better?
Well it depends on 1) what you are optimizing for and 2) how long the locks are liable to be held; i.e. the cost of unwanted contention caused by striping.
Under most circumstances, the first version (a distinct lock per device) will be better. But, if you have a huge number of devices, the cost of a huge number of interned strings might be significant. In that case, AND if the locks are held for a very short time, then lock striping might be better.