線程與單線程執行器服務
一**、概述**
線程和執行器框架是用於在 Java 中並行執行代碼的兩種機制。這提高了應用程序的性能。 Executor Framework 提供了不同種類的線程池。其中一個池僅包含一個工作線程。
在本教程中,我們將了解線程和具有單個工作線程的執行程序服務之間的區別。
2.線程
線程是具有獨立執行路徑的輕量級進程。它用於並行執行任務。因此,可以有多個線程同時運行而不會相互干擾。
Thread
對象執行Runnable
任務。
讓我們看看如何創建線程。我們可以通過**擴展Thread class
或實現Runnable
接口來創建線程。**
讓我們通過擴展Thread
類來創建一個線程:
public class CustomThread extends Thread {
// override the run() method to provide custom implementation
public static void main(String[] args) {
CustomThread t1 = new CustomThread();
t1.start();
}
}
在上面的示例中, CustomThread
類擴展了Thread
類。在main()
方法中,我們創建了CustomThread
類的對象 然後調用它的start()
方法。它開始執行線程.
下面我們來看一個實現Runnable
接口創建線程的例子:
public class TestClass implements Runnable {
// implement the run() method of Runnable interface
public static void main(String[] args) {
TestClass testClassRef = new TestClass();
Thread t1 = new Thread(testClassRef);
t1.start();
}
}
在上面的示例中, TestClass
實現了Runnable
接口。我們在Thread
類的構造函數中傳遞了TestClass
對象的引用。然後,我們調用start()
方法。這反過來又調用了TestClass
實現的run()
方法。
3. 執行器框架
現在我們將了解 Executor Framework。它是在 JDK 1.5 中引入的.
它是一個多線程框架,維護工作線程池並管理它們。任務在隊列中提交,然後由這些工作線程執行。
它消除了在代碼中顯式創建線程的開銷。相反,它重用池中的線程來異步執行任務。
現在讓我們看看執行器框架維護的不同種類的線程池。
3.1.固定線程池
該池包含固定數量的線程。我們在創建池期間指定線程數。如果發生異常並且線程終止,則會創建一個新線程。
讓我們看看如何創建一個固定的線程池:
ExecutorService executorService = Executors.newFixedThreadPool(5);
在上面的代碼片段中,我們創建了一個具有五個工作線程的固定線程池。
3.2.緩存線程池
該線程池在需要時創建新線程。如果沒有線程可用於執行提交的任務,則將創建一個新線程。
下面是我們創建緩存線程池的方法:
ExecutorService executorService = Executors.newCachedThreadPool();
在緩存線程池中,我們沒有提到池大小。這是因為它在沒有線程可用於執行提交的任務時創建新線程。它還會在可用時重用已創建的線程。
3.3.調度線程池
此線程池在給定延遲後或定期運行任務。
下面是我們如何創建一個調度線程池:
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
在上面的代碼片段中,整數參數是核心池大小。它表示保留在池中的線程數,即使它們處於空閒狀態。
3.4.單線程池
這個池只包含一個線程。它按順序執行提交的任務。如果發生異常並且線程終止,則會創建一個新線程。
下面的代碼片段顯示瞭如何創建單個線程池:
ExecutorService executorService = Executors.newSingleThreadExecutor();
在這裡, Executors
類的static
方法newSingleThreadExecutor()
創建了由單個工作線程組成的ExecutorService
。
4.線程與單線程執行器服務
我們可能想知道如果單個線程池ExecutorService
只包含一個線程,那麼它與顯式創建一個線程並使用它來執行任務有何不同。
現在讓我們探討線程和只有一個工作線程的執行程序服務之間的區別,以及何時使用哪個。
4.1.任務處理
線程只能處理Runnable
任務,而單線程執行器服務可以同時執行Runnable
和Callable
任務。因此,使用它,我們也可以運行可以返回一些值的任務。
ExecutorService
接口中的submit()
方法採用Callable
任務或Runnable
任務並返回Future o
對象。該對象表示異步任務的結果。
此外,一個線程可以只處理一個任務並退出。但是單線程執行器服務可以處理一系列任務並按順序執行它們。
4.2.線程創建開銷
創建線程會產生開銷。例如,JVM 需要分配內存。當在代碼中重複創建線程時,它會影響性能。但是在單線程執行器服務的情況下,會重用同一個工作線程。因此,它避免了創建多線程的開銷。
4.3.內存消耗
線程對象佔用大量內存。因此,如果我們為每個異步任務創建線程,就會導致OutOfMemoryError
。但是在單線程執行器服務中,重複使用同一個工作線程,從而減少內存消耗。
4.4.資源釋放
線程在執行完成後釋放資源。但是對於executor服務,我們需要關閉服務,否則JVM無法關閉。 shutdown()
和shutdownNow()
等方法關閉執行程序服務。
5.結論
在本文中,我們了解了線程、Executor Framework 和不同類型的線程池。我們還看到了線程和單線程執行器服務之間的差異。
我們了解到,如果有任何重複的作業或者有很多異步任務,那麼執行器服務是更好的選擇。
與往常一樣,示例的源代碼可在 GitHub 上獲得。