我正在学习Java多线程编程。我有以下逻辑:

假设我有A类

class A {
    ConcurrentMap<K, V> map;

    public void someMethod1 () {
        // operation 1 on map
        // operation 2 on map
    }

    public void someMethod2 () {
        // operation 3 on map
        // operation 4 on map
    }
}

现在,我不需要同步“someMethod1”或“someMethod2”中的操作。这意味着,如果有两个线程同时调用“someMethod1”,则无需序列化这些操作(因为ConcurrentMap将完成此工作)。

但是我希望“someMethod1”和“someMethod2”彼此互斥,这意味着当某个线程正在执行“someMethod1”时,另一个线程应等待输入“someMethod2”(但应允许另一个线程输入“someMethod1”)。

简而言之,有没有一种方法可以使“someMethod1”和“someMethod2”不是互斥体,而是互斥体?

我希望我已经清楚地阐明了我的问题...

谢谢!

最佳答案

我尝试了几次使用更高级别的构造的尝试,但没有想到。我认为这可能是一个降低底层API的机会:


private int someMethod1Invocations = 0;
private int someMethod2Invocations = 0;

public void someMethod1() {
    synchronized(this) {
        // Wait for there to be no someMethod2 invocations -- but
        // don't wait on any someMethod1 invocations.
        // Once all someMethod2s are done, increment someMethod1Invocations
        // to signify that we're running, and proceed
        while (someMethod2Invocations > 0)
            wait();
        someMethod1Invocations++;
    }

    // your code here

    synchronized (this) {
        // We're done with this method, so decrement someMethod1Invocations
        // and wake up any threads that were waiting for that to hit 0.
        someMethod1Invocations--;
        notifyAll();
    }
}

public void someMethod2() {
    // comments are all ditto the above
    synchronized(this) {
        while (someMethod1Invocations > 0)
            wait();
        someMethod2Invocations++;
    }

    // your code here
    synchronized(this) {
        someMethod2Invocations--;
        notifyAll();
    }
}

上面一个明显的问题是它可能导致thread starvation。例如,someMethod1()正在运行(并阻止someMethod2()),并且在即将完成时,另一个线程随之出现并调用someMethod1()。这样就可以了,就像它完成另一个线程一样,启动someMethod1(),依此类推。在这种情况下,someMethod2()将永远不会有运行的机会。实际上,这不是上面代码中的直接错误。这是您的设计需求中的一个问题,一个好的解决方案应该积极地解决这个问题。我认为,一个合理的AbstractQueuedSynchronizer可以解决问题,尽管这是留给读者的练习。 :)

最后,我忍不住要发表意见:鉴于ConcurrentHashMap操作非常快,您最好将两种方法都放在一个互斥体上并用它完成。因此,是的,线程将不得不排队等待调用someMethod1(),但是每个线程都将非常快地完成其轮换(从而让其他线程继续进行)。这不应该是一个问题。

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

10-09 04:41