我有一个基于ExecutorService Thread流程规则的问题: 我想.submit()执行多个线程,我想要一些线程等到特定的前一个线程完成执行。
到目前为止,我通过使用CountDownLatch()知道了一种这样的方法。以下示例说明了需要在第三个线程开始之前完成的2个线程:
public class Example{
public static void main(String[] args) throws InterruptedException {
CountDownLatch cdl = new CountDownLatch(2); //count of 2
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new Runnable() {
public void run() {
method1(); //simulation of a useful method 1
cdl.countDown(); //reduces the count by one
}
});
executor.submit(new Runnable() {
public void run() {
method2(); //simulation of a useful method 2
cdl.countDown();
}
});
cdl.await(); //will wait until both methods are complete
executor.submit(new Runnable() {
public void run() {
result(); //simulation of a method that needs previous threads to execute }
});
}
}
很明显,这样的方法对于这样的工作来说不是最佳的,因为一方面,不能在.await()之后添加不依赖于CDL本身的额外线程。
因此,使用ExecutorService来管理Thread流程的更好的替代方法是什么,与CDL相比,它允许更好地操作Thread执行。
答案 0 :(得分:3)
在第3 CountDownLatch
Runnable
executor.submit(new Runnable() {
public void run() {
cdl.await(); //will wait until both methods are complete
result(); //simulation of a method that needs previous threads to execute }
});
}
您可能需要将cdl
声明为final,以便在匿名Runnable
实例中引用它:
final CountDownLatch cdl = new CountDownLatch(2); //count of 2
替代方法
有一个方法可以创建第三个任务:
void createThirdTask() {
executor.submit(new Runnable() {
public void run() {
result(); //simulation of a method that needs previous threads to execute }
});
}
}
在前两个任务和计数器之间有一个共享锁。
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private int count = 2;
CDL内部method1()
和method2()
递减值,如果达到零,则触发第三项任务。
void method1() {
//your actual code goes here
try {
lock.writeLock().lock();
if(count-- == 0) {
createThirdTask();
}
} finally {
lock.writeLock().unlock()
}
}
ReentrantReadWriteLock可以防止竞争条件。
答案 1 :(得分:3)
我建议将CompletableFuture用于此类线程任务。它可能看起来像这样:
public class RunAfterNThreads {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture.supplyAsync(RunAfterNThreads::runFirstBatchOfThreads)
.thenAcceptAsync((t) -> runSecondBatchOfThreads(null)).get();
}
private static Object runSecondBatchOfThreads(Object something) {
return something;
}
private static <U> U runFirstBatchOfThreads() {
return null;
}
}
如果你想使用一些库,我会建议探索类似Akka(事件驱动)的东西。
答案 2 :(得分:2)
我不确定Java是否真的有适当的标准机制来帮助您实现这一目标。 Eclipse的内部代码有很多额外的类来处理任务及其依赖项。
但是,我认为你或许可以使用&#34; CompletableFuture
这样做:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
Runnable r1 = () -> System.out.println("runnable 1");
Runnable r2 = () -> System.out.println("runnable 2");
Runnable r3 = () -> System.out.println("runnable 3");
CompletableFuture<Void> cf1 = CompletableFuture.runAsync(r1, executor);
CompletableFuture<Void> cf2 = CompletableFuture.runAsync(r2, executor);
cf1.runAfterBoth(cf2, r3);
}
}
如果您的情况更复杂,那么最好搜索“定向非循环图”&#39;任务库。