您的位置:

Java Executors详解

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 > 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多线程编程中的一个重要组成部分,并且提供了许多有用的实用程序,使线程编程变得更加容易和高效。