不同类方法的同步

时间:2018-04-10 16:34:17

标签: java multithreading java-threads

我有两个类,每个类都有一个方法。

class A {
    private void insert(String usedId){
        // ...
    }
}

class B {
    private void refresh(String userId){
        // ...
    }
}

从不同的Thread调用每个方法。对于不同的Thread s,它们会从不同的userId调用。

我需要在调用第二个方法时锁定第一个方法,而对于同一个userId则反之亦然。

是保留List个ID并设置锁定的最佳选择吗?

1 个答案:

答案 0 :(得分:1)

我们介绍一个LockDispenser。您将此对象传递给您希望拥有thread safe的所有AB。它将提供LockcreateLock(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);
}

fooAfooB互为线程安全,因此barAbarB