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/zh-tw/n/143624.html