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

Java 如果从另一个线程调用另一个方法,则多个线程在阻塞时调用该方法,java,multithreading,concurrency,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 s

假设有两个方法
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()


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

这种情况非常类似于十字路口的交通灯。A路或B路都可以通过,但决不能同时通过

假设我们有一个
TrafficLight
类,它的行为有点像一个
信号灯,它监视两条道路“a”和“B”。想要通过“A”的线程可以请求对“A”的许可,并应被授予该许可,如果“B”许可未被释放,则阻止,反之亦然

在过去,我做过这样一个
TrafficLight
课程作为练习(实际上可以监控两个以上的状态):


听起来您需要读写器锁(例如java.util.concurrent.locks.ReentrantReadWriteLock)。它允许任意数量的“读卡器”同时使用资源,或者只允许一个“写卡器”使用资源,但不能同时使用两者


一个好的实现,如Java版本,由于需要提供“公平性”,会稍微复杂一些。例如,它不能“饥饿”一个想要资源的编写器,即使有如此多的读卡器,资源从来没有空闲的时候。

您是否正试图特别避免同步?
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();
        }
    }
}
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();
}