[英]Synchronize on two String objects
我只找到了一个字符串 object 同步的答案,而不是两个。
这不是一项真正的任务,而是一项任务。 我有 SomeLibrary 可以将钱从一个帐户转移到另一个帐户。 我无法访问帐户 object 来锁定它。 我只能使用 SomeLibrary.transfer(String from, String to),它不是线程安全的。 我有将帐户 ID 作为字符串的方法。 我需要在没有死锁的情况下锁定这两个字符串。
到目前为止我所做的是:
使用.intern 方法创建了新的字符串(String fr = from.intern())。 但这是不好的做法,我不允许使用这种方法。 但它奏效了。
从旧字符串创建新字符串(String fr = new String(from))。 这也有效(我没有死锁),但我怀疑这个解决方案。
还有其他方法可以锁定两个字符串吗?
我尝试使用 ConcurrentHashMap 并将字符串放在那里,但它没有用。
可能有一种方法可以将字符串放入某些对象中,但是应该在哪里创建这些对象? 我可以在 transfer() 中创建它们,但是在局部变量上同步也不是好习惯。
我的方法是:
public void transfer(String from, String to, int amount) {
String fr = new String(from);
String too = new String(to);
int fromHash = System.identityHashCode(fr);
int toHash = System.identityHashCode(too);
if (fromHash < toHash) {
synchronizedTransfer(from, to, amount, fr, too);
} else if (fromHash > toHash) {
synchronizedTransfer(to, from, amount, too, fr);
} else {
synchronized (tieLock) {
synchronizedTransfer(from, to, amount, fr, too);
}
}
}
private void synchronizedTransfer(String from, String to, int amount, String fr, String too) {
synchronized (fr) {
synchronized (too) {
SomeLibrary.transfer(from, to);
}
}
}
您可以使用嵌套的同步块在两个对象上同步。 为了防止任何死锁,我会按字典顺序比较两个字符串:
public void transfer(String from, String to, int amount) {
int comparingResult = from.compareTo(to);
if (comparingResult > 0) {
synchronized (from) {
synchronized (to) {
SomeLibrary.transfer(from, to);
}
}
} else if (comparingResult < 0) {
synchronized (to) {
synchronized (from) {
SomeLibrary.transfer(from, to);
}
}
} else {
if (from == to) { // Do not use equals() here
synchronized (from) {
SomeLibrary.transfer(from, to);
}
} else {
throw new UnsupportedOperationException();
}
}
}
else
部分是可选的,取决于您可以在同一个帐户之间转移资金这一事实,在我看来,这有点无用。
必须明确的是,对于传输(from, to),所有 (from, ), ( , from), (*, to), (to, *)传输可能需要被保护。
做到这一点的唯一方法是同步从和同步到。 当有传输(到,从)时,这可能会导致死锁。 为此,可以订购 from 和 to 以便同步 AAA 在同步 BBB 之前。
另一种方法是在可以回滚的事务中进行原子存款(from, -amount),存款(to, amount)并完成所有操作。
现在同步 object:这必须是唯一的 Object 实例。 您可以使用帐户 ID 字符串,如Map
( Set
)。 因此,您有一个独特的 object 作为 map 中的键。 当然 map 操作也受到并发的影响,使用: Collections.synchronizedMap
。 您需要更新它,添加/删除帐户 ID。
由于事务是一个单独的主题,因此按规范顺序嵌套两个同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.