java - 不同类方法的同步

标签 java multithreading java-threads

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

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

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

每个方法都是从不同的线程调用的。它们是从不同的 Thread 为不同的 userId 调用的。

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

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

最佳答案

我们引入了一个LockDispenser。您将此对象传递给您想要拥有的所有 AB thread safe 。它将通过 createLock(String forId) 提供 Lock 对象,使用后需要通过调用 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 block 。

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 来做到这一点 block 。

并像这样创建它们:

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 也是如此。

关于java - 不同类方法的同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49758748/

相关文章:

Java 更新 : On LInux Mint the openjdk package doesn't update to the latest stable version

java - H2 with MODE=Oracle 导致 'Schema "information_schema"not found'

java - WAIT 和 BLOCKED 线程状态的区别

c++ - 线程安全 std::vector push_back 和 reserve

java - 访问远程应用程序服务器上的线程

JavaFX - 如何在退出应用程序之前关闭所有正在运行的线程?

java - Hibernate 4 - 可以向 @ManyToMany Hibernate 额外表添加额外字段吗?

Java ClassLoader - 强制重新加载已经加载的类

.net - 如何在单独的线程上设置全局键盘 Hook ?

java - 使用Java在循环内并行执行方法