提问人:zotov_l88 提问时间:11/13/2023 最后编辑:zotov_l88 更新时间:11/13/2023 访问量:39
如何让 main 等待线程执行,但这些线程必须同时启动
How to make main wait for threads to execute, but these threads must be started at the same time
问:
我有一个程序,在其中创建一个数组,克隆到所需数量的相同数组中,然后以不同的方式排序。
https://github.com/zotov88/algorithms
public class SortingRunner {
final static int CAPACITY = 10_000;
final static int FROM = -100;
final static int TO = 100;
final static int COUNT_ARRAYS = 4;
public static void main(String[] args) throws InterruptedException {
int[][] arrays = Utils.generateTheSameRandomArrays(CAPACITY, FROM, TO, COUNT_ARRAYS);
List<Sorting> sortingList = List.of(
new BubbleSort(arrays[0]),
new SelectionSort(arrays[1]),
new MergeSort(arrays[2]),
new QuickSort(arrays[3])
);
for (Sorting sorting : sortingList) {
Thread t = new Thread(() -> Utils.speedTest(sorting));
t.start();
t.join();
}
Utils.printArrays(arrays);
}
}
在这段代码中,首先对线程进行逐个处理,然后在主线程中开始数组的打印。
for (Sorting sorting : sortingList) {
Thread t = new Thread(() -> Utils.speedTest(sorting));
t.start();
t.join();
}
Utils.printArrays(arrays);
我希望数组在每个线程中同时排序,并且 main 等待它们完成,然后打印。
答:
tl;博士
使用执行程序服务。
try (
ExecutorService executorService = Executors. … ;
)
{
futures = executorService.invokeAll ( tasks );
}
执行器框架
Java 5 中添加了 Executors 框架来支持此类工作。从那时起,我们很少需要直接互动。Thread
将任务定义为 Runnable
或 Callable
对象。将它们提交到具有所需行为的执行程序服务对象。
通常最好使用 Executors
实用程序类来实例化执行器服务。在这里,我们使用一个执行器服务,为每个任务创建一个新的虚拟线程。
提交任务时,将获得一个 Future
对象。使用该对象检查任务的进度。在 的情况下,使用该对象访问任务的结果。Callable
Future
您可以一次提交一个任务。或者,您可以使用来提交任务集合。没有真正的区别,只是为了方便您的编码情况。invokeAll
如何让 main 等待线程执行
您可以等待执行程序服务完成其所有任务,在此之前原始线程将被阻止。要管理此等待完成的块,您有两条路由,一条是手动路由,另一条是更方便的自动路由:
- 要手动管理,请参阅
Javadoc for ExecutorService
接口上提供给您的样板代码。 - 从 Java 19 开始,对象是
AutoCloseable
。因此,我们可以使用 try-with-resources 语法来更方便地等待完成。(您可能需要检查 OpenJDK 中的源代码,以查看该行为是否符合您的需求。ExecutorService
我们在下面的代码中使用更方便的 try-with-resources 方法。
但这些线程必须同时启动
这是不可能的。Java 中的线程由主机操作系统管理的本机线程提供支持。这些操作系统线程的调度超出了您的控制范围,也超出了 JVM 的控制范围。
执行程序服务将尝试立即开始执行任务(除非您使用 ScheduledExecutorService
指定了延迟)。因此,由多核机器上的多个线程支持的执行器服务可能会几乎在同一时刻开始执行多个任务。但也许不是。例如,如果计算机负担过重,则某些任务可能需要等待。或者,主机操作系统可能会优先处理其他线程,然后再处理您的线程。您通常可以预期您的任务很快就会开始,但不是确定性的。
示例代码
package work.basil.example.threading;
import java.time.Instant;
import java.util.List;
import java.util.concurrent.*;
public class BunchOfTasks
{
public static void main ( String[] args )
{
// Define your tasks to be performed.
List < Callable < Instant > > tasks =
List.of (
( ) -> {
System.out.println ( "x" );
return Instant.now ( );
} ,
( ) -> {
System.out.println ( "y" );
return Instant.now ( );
} ,
( ) -> {
System.out.println ( "z" );
return Instant.now ( );
}
);
// Submit your tasks. Capture `Future` objects.
List < Future < Instant > > futures = List.of ( );
try (
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor ( ) ;
)
{
futures = executorService.invokeAll ( tasks );
} catch ( InterruptedException e ) { throw new RuntimeException ( e ); }
// Report results by inspecting `Future` objects.
for ( Future < Instant > instantFuture : futures )
{
try { System.out.println ( instantFuture.get ( ).toString ( ) ); } catch ( InterruptedException | ExecutionException e ) { throw new RuntimeException ( e ); }
}
}
}
输出示例:
x
y
z
2023-11-12T20:51:42.098634Z
2023-11-12T20:51:42.098742Z
2023-11-12T20:51:42.098795Z
评论
Executor