Java的多线程编程一直被广泛使用和研究。它提供了许多方式来管理和控制线程的行为。但是这些功能并不足以方便地进行线程管理。在这种情况下,Java的并发库提供了一种解决办法,即使用java.util.concurrent.Executors类来管理线程。它使线程管理变得更加简单、易于理解和实现。本文将从多个方面对Java Executors进行详细的介绍。
一、线程池
线程池是一种执行多个任务的方式,使用线程池可以避免创建线程的开销,以及将任务排队等待的时间,从而提高程序的响应速度和性能。Java的线程池管理器类是java.util.concurrent.ExecutorService接口。下面是一个实现线程池的示例:
“`java
ExecutorService executor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Runnable worker = new MyRunnable(i);
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished all threads");
“`
这里使用newFixedThreadPool方法创建一个固定大小的线程池。该线程池有5个线程。然后,循环运行10个任务。这些任务由MyRunnable类实现,实现了Runnable接口。execute()方法将每个任务提交给线程池,线程池会从线程池中的空闲线程中选择一个线程来执行它们。最后,关闭线程池,并等待所有任务完成。注意,这里的线程池最大可用线程数是5个。如果提交10个任务,则前5个将立即开始,而剩余5个任务将排队等待线程可用。
二、ScheduledExecutorService
Java的ScheduledExecutorService接口提供了一种调度执行任务的机制。下面是一个使用ScheduledExecutorService的示例:
“`java
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);
ScheduledFuture scheduledFuture =
executor.scheduleAtFixedRate(new MyRunnable(), 1, 5, TimeUnit.SECONDS);
“`
这里创建了一个大小为2的ScheduledExecutorService。然后使用scheduleAtFixedRate方法将任务提交给它。任务由MyRunnable实现。scheduleAtFixedRate表示每隔5秒钟执行一次任务。这里,需要注意的是,它初始延迟时间为1秒,因此,任务将在1秒后就开始执行。返回值是ScheduledFuture,它表示定期调度任务的结果和控制。可以使用以下代码取消执行:
“`java
scheduledFuture.cancel(true);
“`
三、Callable和Future
Callable是一个带有类型参数的接口,可以使用它来执行一个返回类型的异步任务。上面的代码已经使用了Runnable测试任务的执行。Callable并行计算的执行可以使用Future类。Future是一个带有类型参数的接口,用于获取并处理异步任务的结果。
下面是一个使用Callable和Future的示例:
“`java
ExecutorService executor = Executors.newSingleThreadExecutor();
Future future = executor.submit(new Callable() {
@Override
public Integer call() throws Exception {
int count = 0;
for (int i = 0; i < 100; i++) {
count += i;
}
return count;
}
});
try {
System.out.println("result : " + future.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
executor.shutdown();
“`
这里,使用newSingleThreadExecutor方法创建一个只有单个线程的线程池。这个线程池将执行一个返回类型为Integer的异步任务,这个任务是一个Callable实现。submit()方法提交任务,并返回一个Future对象。然后,通过调用get()方法等待异步任务完成并获取结果。最后,关闭线程池。
四、CompletionService
CompletionService是一种在完成任务时返回结果的一种更高级的机制。CompletionService表示处理线程执行结果的一组队列。它提供了一个带有队列的ExecutorService的实现,可以使用它来获取已完成任务的结果。CompletionService和Future都可以用于获取任务的结果,但CompletionService可以更多地控制任务的执行和获取它们的结果。
下面是一个使用CompletionService的示例:
“`java
ExecutorService executor = Executors.newFixedThreadPool(5);
CompletionService completionService = new ExecutorCompletionService(executor);
for (int i = 0; i < 10; i++) {
final int taskId = i;
completionService.submit(new Callable() {
@Override
public Integer call() throws Exception {
Thread.sleep(2000);
return taskId;
}
});
}
for (int i = 0; i < 10; i++) {
try {
System.out.println(completionService.take().get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
“`
这里创建一个固定大小为5的线程池。然后,使用ExecutorCompletionService代替CompletionService,以将任务提交给它。这个示例将提交执行10个任务,每个任务执行2秒钟。当任务完成时,take()方法将返回一个Future对象。使用get()方法等待异步任务完成并获取它的结果。最后,关闭线程池。
五、ForkJoinPool
Java的ForkJoinPool类是一个特殊的线程池,它可以重用线程,以便更好地利用CPU和内存资源。ForkJoinPool的主要设计目标是支持分治任务,例如在QuickSort或合并排序中使用。下面是一个使用ForkJoinPool的示例:
“`java
class ForkJoinMergeSort<T extends Comparable> extends RecursiveAction {
private T[] array;
private int start;
private int end;
public ForkJoinMergeSort(T[] array, int start, int end) {
super();
this.array = array;
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if (end – start < 2) {
return;
}
int middle = (start + end) / 2;
invokeAll(new ForkJoinMergeSort(array, start, middle),
new ForkJoinMergeSort(array, middle, end));
merge(array, start, middle, end);
}
private void merge(T[] array, int start, int middle, int end) {
T[] tempArray = (T[]) new Comparable[end – start];
int i = start;
int j = middle;
int k = 0;
while (i < middle && j < end) {
tempArray[k++] = array[i].compareTo(array[j]) < 0 ? array[i++] : array[j++];
}
while (i < middle) {
tempArray[k++] = array[i++];
}
while (j < end) {
tempArray[k++] = array[j++];
}
System.arraycopy(tempArray, 0, array, start, tempArray.length);
}
}
public class ForkJoinPoolDemo {
public static void main(String[] args) {
Integer[] array = { 3, 56, 23, 1, 5, 34, 78, 2, 45, 99 };
ForkJoinPool pool = new ForkJoinPool();
ForkJoinMergeSort task = new ForkJoinMergeSort(array, 0, array.length);
pool.invoke(task);
pool.shutdown();
System.out.println(Arrays.toString(array));
}
}
“`
这里实现一个单核心的归并排序算法,并使用ForkJoinPool类执行算法。ForkJoinPool从内部维护线程池,递归地拆分任务,将它们分配给可用的线程,当线程完成任务时将结果汇总。在这里,元素列表被递归地划分为子列表,直到列表元素数量为1,然后逐步合并这些子列表,直到完成排序。
以上就是Java Executors的详细介绍。它是Java多线程编程中的一个重要组成部分,并且提供了许多有用的实用程序,使线程编程变得更加容易和高效。
原创文章,作者:SMPB,如若转载,请注明出处:https://www.506064.com/n/143624.html