我正在寻找以下问题的Java并发解决方案。
正在运行一些任务,还有一段代码C。
C必须等待所有任务完成。 (超时)
在C完成之前不能开始任何任务。
我浏览了java.concurrency包,发现了一些有趣的东西,但是似乎没有什么工作很正确:
我相信我可以使用移相器和锁来构造一些东西:
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()
);
}
现在,尽管我相当确定这是可行的,但我也意识到尝试构建自己的并发解决方案是一个坏主意。有更好的方法吗?
如果没有,我将如何使用phase
参数?
编辑:此问题在涉及Web客户端连接的项目中,因此任务无法预期地到达。但是,通过更仔细的设计可以避免这种情况。
答案 0 :(得分:0)
这是一个特殊的用例,我认为我们需要使用多个并发实用程序进行协调。下面的程序应该做到这一点。请随时发布任何不清楚的问题-
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);
}
}
答案 1 :(得分:0)
我在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));
}
具有StampedLock类的键是readLock()不是互斥的,而writeLock()是互斥的。它也支持超时,类似于常规的Lock。