假设从不同的线程调用了两个方法methodA()
和methodB()
。我想要的是当调用methodA()
时,调用methodB()
的线程将被阻塞,直到methodA()
完成,反过来。这可以通过信号量轻松实现:
private Semaphore semaphore = new Semaphore(1, true);
public void methodA() {//ignored try catch finally
semaphore.acquire();
//do stuff
semaphore.release();
}
public void methodB() {
semaphore.acquire();
//do stuff
semaphore.release();
}
但问题是我希望多个线程同时执行methodA()
或methodB()
。 多个线程应该能够同时执行methodA()
这么长时间没有人执行methodB()
;上面的解决方案在这种情况下不起作用,因为如果线程执行methodA()
,即使没有执行methodA()
的线程,其他线程也不能执行methodB()
。
我能想到的任何其他解决方案要么需要在方法中进行同步,要么做其他不允许多个线程执行单个方法的情况,如果没有线程执行另一个。
答案 0 :(得分:1)
这种情况非常像十字路口的交通灯。无论是A路还是B路,都不会同时进行。
所以,让我们说我们有一个TrafficLight
课程,有点像监视两条道路的Semaphore
" A"和" B"。希望通过" A"可以要求获得A" A"并且如果" B"许可尚未发布,反之亦然。
在过去,我做了一个TrafficLight
课程作为练习(实际上可以监控超过2个州):
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class TrafficLight<T> {
private ReentrantLock lock = new ReentrantLock(true);
private Condition switched = lock.newCondition();
private int registered;
private int maxBeforeYield = 20;
private T state;
public void acquire(T t) throws InterruptedException {
lock.lock();
try {
while ((state != null && !state.equals(t)) || maxBeforeYield == 0) {
switched.await();
}
if (state == null) {
state = t;
}
registered++;
maxBeforeYield--;
} finally {
lock.unlock();
}
}
public void release() {
lock.lock();
try {
registered--;
if (registered == 0) {
state = null;
maxBeforeYield = 20;
switched.signalAll();
}
} finally {
lock.unlock();
}
}
}
请注意maxBeforeYield
:TrafficLight可能遇到的一个问题是,大量请求&#34; A&#34;太棒了,要求&#34; B&#34;永远不会有机会。因此,TrafficLight对请求进行计数,并在一些请求(maxBeforeYield
)之后开始阻止&#34; A&#34;请求,然后很好地等待,直到所有权限都被返回,然后给另一个州一个机会,ReentrantLock
需要公平,以确保方向&#39;除非只阻止同一方向的请求,否则会切换。
鉴于此TrafficLight
课程,您可以将代码更改为:
private TrafficLight<String> trafficLight = new TrafficLight<>();
public void methodA() {//ignored try catch finally
trafficLight.acquire("A");
//do stuff
trafficLight.release();
}
public void methodB() {
trafficLight.acquire("B");
//do stuff
trafficLight.release();
}
答案 1 :(得分:0)
听起来像是想要一个读/写锁(例如,java.util.concurrent.locks.ReentrantReadWriteLock)。它允许任意数量的读者&#39;同时使用资源 - 或 - 它只允许一个作家&#39;使用它,但不是两者都使用。
一个好的实现,比如Java版本,由于需要提供公平性,因此会稍微复杂一些。&#39;例如,它绝不能饿死&#39;一个想要资源的作家,即使有这么多的读者,当资源闲置时永远不会。