我有两个类,每个类都有一个方法。
class A {
private void insert(String usedId){
// ...
}
}
class B {
private void refresh(String userId){
// ...
}
}
从不同的Thread
调用每个方法。对于不同的Thread
s,它们会从不同的userId
调用。
我需要在调用第二个方法时锁定第一个方法,而对于同一个userId
则反之亦然。
是保留List
个ID并设置锁定的最佳选择吗?
答案 0 :(得分:1)
我们介绍一个LockDispenser
。您将此对象传递给您希望拥有thread safe的所有A
和B
。它将提供Lock
个createLock(String forId)
个对象,需要在使用后通过调用releaseLock(String forId)
来释放。
public class LockDispenser {
private final Map<String, Lock> dispenser = new LinkedHashMap<>();
public Object createLock(String forId) {
synchronized (dispenser) {
if (!dispenser.containsKey(forId)) {
dispenser.put(forId, new Lock());
}
Lock lock = dispenser.get(forId);
lock.referenceCounter++;
return lock;
}
}
public void releaseLock(String forId) {
synchronized (dispenser) {
Lock lock = dispenser.get(forId);
lock.referenceCounter--;
if (lock.referenceCounter == 0) {
dispenser.remove(forId);
}
}
}
public static class Lock {
private int referenceCounter = 0;
}
}
现在,实际的线程安全性来自于使用synchronized
块中的Lock
。
public class A {
private LockDispenser dispenser;
public A(LockDispenser dispenser) {
this.dispenser = dispenser;
}
private void insert(String userId) {
synchronized (dispenser.createLock(userId)) {
// code
}
dispenser.releaseLock(userId); // consider putting this in a finally block
}
}
public class B {
private LockDispenser dispenser;
public B(LockDispenser dispenser) {
this.dispenser = dispenser;
}
private void refresh(String userId) {
synchronized (dispenser.createLock(userId)) {
// code
}
dispenser.releaseLock(userId); // consider putting this in a finally block
}
}
即使抛出异常,也要确保调用releaseLock(String forId)
。您可以将其放入finally
块中来完成此操作。
并像这样创建它们:
public static void main(String... args) {
LockDispenser fooLock = new LockDispenser();
A fooA = new A(fooLock);
B fooB = new B(fooLock);
LockDispenser barLock = new LockDispenser();
A barA = new A(barLock);
B barB = new B(barLock);
}
fooA
和fooB
互为线程安全,因此barA
和barB
。