在之前的文章中,學習了通過實現java.lang.Runnable來定義類,以及像下面這樣創建一個線程來運行任務:
Runnable task = new TaskClass(task);
new Thread(task).start();該方法對單一任務是很方便,但是對於大量的任務而言是不夠高效的。為每一個任務開始一個新的線程可能會限制流量並且造成性能降低。
java提供Executor接口來執行線程池中的任務,提供ExecutorService 接口來管理和控制任務,ExecutorService 接口是Executor接口的子接口
newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads)
創建一個可重用固定線程數的線程池,以共享的無界隊列方式來運行這些線程。在任意點,在大多數 nThreads 線程會處於處理任務的活動狀態。如果在所有線程處於活動狀態時提交附加任務,則在有可用線程之前,附加任務將在隊列中等待。如果在關閉前的執行期間由於失敗而導致任何線程終止,那麼一個新線程將代替它執行後續的任務(如果需要)。在某個線程被顯式地關閉
之前,池中的線程將一直存在。
參數:nThreads
- 池中的線程數
返回:新創建的線程池
拋出:IllegalArgumentException
- 如果 nThreads <= 0
newCachedThreadPool
public static ExecutorService newCachedThreadPool()
創建一個可根據需要創建新線程的線程池,但是在以前構造的線程可用時將重用它們。對於執行很多短期異步任務的程序而言,這些線程池通常可提高程序性能。調用 execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長時間保持空閒的線程池不會使用任何資源。注意,可以使用 ThreadPoolExecutor
構造方法創建具有類似屬性但細節不同(例如超時參數)的線程池。
返回:新創建的線程池
看一個多線程的例子:
package ExecuterTest; public class TaskThreadDemo { public static void main(String[] args) { //新建任務與線程 Thread th1 = new Thread(new PrintChar('a', 100)); Thread th2 = new Thread(new PrintChar('b', 100)); Thread th3 = new Thread(new PrintNum(100)); //啟動線程 th1.start(); th2.start(); th3.start(); } } //任務為:打印指定字符的指定次數 class PrintNum implements Runnable { private int lastNum; public PrintNum(int n) { lastNum = n; } @Override public void run() { for (int i = 1; i <= lastNum; i++) { System.out.println(" " + i); } } } //任務為:打印從1-n的所有數 class PrintChar implements Runnable { private char charToPrint; //打印的字符 private int times; //打印的次數 public PrintChar(char c, int t) { charToPrint = c; times = t; } @Override public void run() { for (int i = 0; i < times; i++) { System.out.println(charToPrint); } } }
下面使用線程池來修改上面的程序:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TaskThreadDemo { public static void main(String[] args) { //創建了一個最大線程數為3的線程池 ExecutorService excutor=Executors.newFixedThreadPool(3); //提交runnable()任務到excutor excutor.execute(new PrintChar('a', 100)); excutor.execute(new PrintChar('b', 100)); excutor.execute(new PrintNum(100)); //關閉excutor excutor.shutdown(); } }
如果將第6行改為:
ExecutorService excutor=Executors.newFixedThreadPool(1);
那麼線程池中就只有一個線程,則三個線程將順序執行
如果將第6行改為:
ExecutorService excutor=Executors.newCachedThreadPool();
所有的線程將並發執行