如果从另一个线程调用另一个方法,则多个线程在阻塞时调用方法

时间:2014-04-22 18:32:58

标签: java multithreading concurrency

假设从不同的线程调用了两个方法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()

我能想到的任何其他解决方案要么需要在方法中进行同步,要么做其他不允许多个线程执行单个方法的情况,如果没有线程执行另一个。

2 个答案:

答案 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;一个想要资源的作家,即使有这么多的读者,当资源闲置时永远不会