Java 不同任务类型的闩锁

Java 不同任务类型的闩锁,java,concurrency,Java,Concurrency,我正在寻找以下问题的java并发解决方案 有一些任务正在运行,还有一段代码C C必须等待所有任务完成。(超时) 在C完成之前,不得开始任何任务 我查看了java.concurrency包,发现了一些有趣的东西,但似乎没有什么东西是正确的: 移相器允许单向阻塞,但不允许双向阻塞 信号量、ForkJoinTasks和其他一些都有计数器类型的特性,但它们似乎都不能满足我的要求 我相信我可以用一个相位器和一个锁来构造这样的东西: void C() { synchronized(lock)

我正在寻找以下问题的java并发解决方案

有一些任务正在运行,还有一段代码C


  • C必须等待所有任务完成。(超时)

  • 在C完成之前,不得开始任何任务

我查看了java.concurrency包,发现了一些有趣的东西,但似乎没有什么东西是正确的:

  • 移相器允许单向阻塞,但不允许双向阻塞
  • 信号量、ForkJoinTasks和其他一些都有计数器类型的特性,但它们似乎都不能满足我的要求
我相信我可以用一个相位器和一个锁来构造这样的东西:

void C() {
    synchronized(lock) {
        phaser.awaitAdvanceInterruptibly(phase, 1, TimeUnit.SECONDS);
        // Start work anyway if a task is taking too long.
        doWork();
    }
}

void someTask() {
    synchronized(lock) {
        phaser.register();
    }
    doTask().thenRun(
        () -> phaser.arriveAndDeregister()
    );
}
现在,虽然我相当肯定这会起作用,但我也意识到尝试构建自己的并发解决方案是个坏主意。有更好的方法吗

如果没有,我将使用什么作为
阶段
参数


编辑:此问题发生在涉及web客户端连接的项目中,因此任务的到达是不可预测的。但是,通过更仔细的设计可以避免这种情况。

这是一个专门的用例,我认为我们需要使用多个并发实用程序进行协调。下面的程序应该可以做到这一点。请随时张贴问题的任何部分都不清楚-

import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;

public class TestClass {

    private volatile int numOfActiveTasks = 0;
    private Semaphore cSemaphore = new Semaphore(1);
    private Semaphore taskSemaphore = new Semaphore(1);
    private Object tasksLock = new Object();

    //Test method
    public static void main(String[] args) throws IOException {
        TestClass testClass = new TestClass();

        //Launch some task threads
        ExecutorService taskES = Executors.newFixedThreadPool(2);
        IntStream.range(1, 11).forEach((i) -> taskES.submit(() -> {
            try {
                testClass.executeTask();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));

        //Launch some C threads
        ExecutorService cES = Executors.newFixedThreadPool(2);
        IntStream.range(1, 5).forEach((i) -> cES.submit(() -> {
            try {
                testClass.C();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));

        taskES.shutdown();
        cES.shutdown();
    }


    void C() throws InterruptedException {
        try {
            cSemaphore.acquire();

            //If tasks are running, wait at-least n seconds
            this.taskSemaphore.tryAcquire(1, TimeUnit.SECONDS);

            print("C started running");
            doCsWork();

        } finally {
            cSemaphore.release();
            print("C stopped running");
        }
    }

    void executeTask() throws InterruptedException {

        //Do not start while C is running
        cSemaphore.acquire();
        cSemaphore.release();

        synchronized (tasksLock) {
            ++numOfActiveTasks;
            taskSemaphore.tryAcquire();
            print("A task started running. Total " + numOfActiveTasks + " tasks running");
        }

        doTasksWork();

        synchronized (tasksLock) {
            --numOfActiveTasks;
            if (numOfActiveTasks == 0) {
                taskSemaphore.release();
            }
            print("A task stopped running. Total " + numOfActiveTasks + " tasks remaining");
        }
    }

    void doCsWork() throws InterruptedException {
        Thread.sleep(1000);
    }

    void doTasksWork() throws InterruptedException {
        Thread.sleep(2000);
    }

    void print(String message) {
        System.out.println(message);
    }

}

我在java.util.concurrent.locks中找到了这个问题的解决方案,它非常适合我的用例

StampedLock lock;

void C() {
    long stamp = lock.tryWriteLock(1, TimeUnit.SECONDS);
    doWork();
    lock.unlockWrite(stamp);
}

void someTask() {
    long stamp = lock.readLock();
    doTask().thenRun(() -> lock.unlockRead(stamp));
}

该类的关键在于readLock()不是独占的,而writeLock()是独占的。它还支持超时,类似于常规锁。

您可以使用两个
countdownlock
s。一个用1创建,在C部分完成时启动任务;另一个用N创建,仅在N个任务完成时启动C部分finished@Ivan这将起作用,但我不知道将运行多少任务,或何时运行。我已经为这个问题添加了相关的上下文。C必须等待所有任务完成,但同时,任务不能开始,直到C完成。我是唯一一个在这里看到矛盾的人吗?@AlexeiKaigorodov C不依赖于任何任务的完成,但它必须等待任何正在进行的任务。因此,在C之后到达的任务必须等待C完成。