互斥方法

sho*_*301 7 java multithreading

我正在学习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
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

那么,简而言之,有没有一种方法可以让"someMethod1"和"someMethod2"不是互相的互斥体而是互相的互斥体?

我希望我说的问题足够明确......

谢谢!

ysh*_*vit 4

我尝试了几次更高级别的构造,但什么也没想到。我认为这可能是一个深入了解低级 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

上述一个明显的问题是它可能导致线程饥饿。例如,someMethod1()正在运行(并阻塞someMethod2()),就在它即将完成时,另一个线程出现并调用someMethod1()。一切进展顺利,就在它完成时另一个线程启动someMethod1(),依此类推。在这种情况下,someMethod2()永远不会有机会逃跑。这实际上并不是上面代码中的直接错误;而是错误。这是一个与您的设计需求相关的问题,一个好的解决方案应该积极努力解决这个问题。我认为一个公平的AbstractQueuedSynchronizer可以做到这一点,尽管这是留给读者的练习。:)

最后,我忍不住要插入一个观点:鉴于ConcurrentHashMap操作非常快,您最好只在这两个方法周围放置一个互斥体并完成它。所以,是的,线程必须排队才能调用someMethod1(),但每个线程都会非常快地完成其轮次(从而让其他线程继续进行)。这应该不是问题。