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

标签 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(),则即使没有线程执行 methodB,其他线程也无法执行 methodA() ().

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

最佳答案

这种情况非常像十字路口的红绿灯。要么道路 A 通过,要么通过道路 B,但不能同时通过。

假设我们有一个 TrafficLight 类,它的作用有点像 Semaphore ,它监视两条道路“A”和“B”。想要传递“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 可能遇到的一个问题是,对“A”的请求数量如此之大,以至于对“B”的请求永远没有机会。因此,TrafficLight 对请求进行计数,在多次请求 (maxBeforeYield) 后,它也开始阻止“A”请求,然后很好地等待,直到返回所有权限,然后给另一个状态一个机会, ReentrantLock 需要公平,以确保“方向”切换,除非仅阻止同一方向的请求。

鉴于此 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();
}

关于java - 如果从另一个线程调用另一个方法,则多个线程调用一个方法,同时阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23227529/

相关文章:

java - 为什么在 Swing 中调整窗口大小后才显示 JFrame 的背景图像?

Java 链式/嵌套方法调用

java - 按顺序读取多个 PDF 文件

将任务作为操作的 C# 动态方法调用

java - 当读取和设置简单引用已经是原子操作时,为什么要使用 AtomicRefernce

java - 对并行线程组执行顺序操作

java - spring-security:CglibAopProxy 不拦截 GlobalMethodSecurityConfiguration 的方法调用

c++ - FFMPEG:多线程解码死锁?

javascript - 如何在 JavaScript 中实现原子操作(并发模型)?

dictionary - 如何从并发映射写入中恢复?