我尝试了几次使用高级构造的尝试,但没有想到任何东西。我认为这可能是一个使用低级 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();
}
}
上面的一个明显问题是它可能导致线程饥饿。例如,someMethod1()
正在运行(并阻塞someMethod2()
s),就在它即将完成时,另一个线程出现并调用someMethod1()
. 这进行得很好,就像它完成另一个线程启动一样someMethod1()
,依此类推。在这种情况下,someMethod2()
将永远没有机会运行。这实际上不是上述代码中的直接错误;这是您的设计需求的问题,一个好的解决方案应该积极解决。我认为一个公平的AbstractQueuedSynchronizer可以做到这一点,尽管这是留给读者的练习。:)
最后,我忍不住要插入一个意见:鉴于ConcurrentHashMap
操作非常快,最好只在这两种方法周围放置一个互斥锁并完成它。所以是的,线程必须排队才能调用someMethod1()
,但是每个线程都会非常快地完成它的轮次(从而让其他线程继续进行)。这不应该是一个问题。