ExecutorService是線程池的一個(gè)服務(wù),可以隨時(shí)關(guān)閉線程池,是繼承Executor的。Executors是個(gè)工廠類(lèi),專(zhuān)門(mén)創(chuàng)建各種線程池。 Android常用的線程池有一下幾種,在Executors里面對(duì)應(yīng)的方法: 1. newFixedThreadPool 創(chuàng)建一個(gè)可重用固定線程數(shù)的線程池,以共享的無(wú)界隊(duì)列方式來(lái)運(yùn)行這些線程。在任意點(diǎn),在大多數(shù) nThreads 線程會(huì)處于處理任務(wù)的活動(dòng)狀態(tài)。如果在所有線程處于活動(dòng)狀態(tài)時(shí)提交附加任務(wù),則在有可用線程之前,附加任務(wù)將在隊(duì)列中等待。如果在關(guān)閉前的執(zhí)行期間由于失敗而導(dǎo)致任何線程終止,那么一個(gè)新線程將代替它執(zhí)行后續(xù)的任務(wù)(如果需要)。在某個(gè)線程被顯式地關(guān)閉之前,池中的線程將一直存在。 -newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時(shí)建新的線程 -其獨(dú)特之處:任意時(shí)間點(diǎn),最多只能有固定數(shù)目的活動(dòng)線程存在,此時(shí)如果有新的線程要建立,只能放在另外的隊(duì)列中等待,直到當(dāng)前的線程中某個(gè)線程終止直接被移出池子 -和cacheThreadPool不同,F(xiàn)ixedThreadPool沒(méi)有IDLE機(jī)制(可能也有,但既然文檔沒(méi)提,肯定非常長(zhǎng),類(lèi)似依賴(lài)上層的TCP或UDP IDLE機(jī)制之類(lèi)的),所以FixedThreadPool多數(shù)針對(duì)一些很穩(wěn)定很固定的正規(guī)并發(fā)線程,多用于服務(wù)器 -從方法的源代碼看,cache池和fixed 池調(diào)用的是同一個(gè)底層池,只不過(guò)參數(shù)不同: fixed池線程數(shù)固定,并且是0秒IDLE(無(wú)IDLE) cache池線程數(shù)支持0-Integer.MAX_VALUE(顯然完全沒(méi)考慮主機(jī)的資源承受能力),60秒IDLE ExecutorService pool = Executors.newFixedThreadPool(2); //創(chuàng)建實(shí)現(xiàn)了Runnable接口對(duì)象,Thread對(duì)象當(dāng)然也實(shí)現(xiàn)了Runnable接口 Thread t1 = new MyThread(); Thread t2 = new MyThread(); Thread t3 = new MyThread(); Thread t4 = new MyThread(); Thread t5 = new MyThread(); //將線程放入池中進(jìn)行執(zhí)行 pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.execute(t4); pool.execute(t5);
2. newCachedThreadPool 創(chuàng)建一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池,但是在以前構(gòu)造的線程可用時(shí)將重用它們。對(duì)于執(zhí)行很多短期異步任務(wù)的程序而言,這些線程池通常可提高程序性能。調(diào)用 execute 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒(méi)有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此,長(zhǎng)時(shí)間保持空閑的線程池不會(huì)使用任何資源。注意,可以使用 ThreadPoolExecutor 構(gòu)造方法創(chuàng)建具有類(lèi)似屬性但細(xì)節(jié)不同(例如超時(shí)參數(shù))的線程池。 -緩存型池子,先查看池中有沒(méi)有以前建立的線程,如果有,就reuse.如果沒(méi)有,就建一個(gè)新的線程加入池中 -緩存型池子通常用于執(zhí)行一些生存期很短的異步型任務(wù) 因此在一些面向連接的daemon型SERVER中用得不多。 -能reuse的線程,必須是timeout IDLE內(nèi)的池中線程,缺省timeout是60s,超過(guò)這個(gè)IDLE時(shí)長(zhǎng),線程實(shí)例將被終止及移出池。 注意,放入CachedThreadPool的線程不必?fù)?dān)心其結(jié)束,超過(guò)TIMEOUT不活動(dòng),其會(huì)自動(dòng)被終止。
3. newSingleThreadExecutor 創(chuàng)建一個(gè)使用單個(gè) worker 線程的 Executor,以無(wú)界隊(duì)列方式來(lái)運(yùn)行該線程。(注意,如果因?yàn)樵陉P(guān)閉前的執(zhí)行期間出現(xiàn)失敗而終止了此單個(gè)線程,那么如果需要,一個(gè)新線程將代替它執(zhí)行后續(xù)的任務(wù))。可保證順序地執(zhí)行各個(gè)任務(wù),并且在任意給定的時(shí)間不會(huì)有多個(gè)線程是活動(dòng)的。與其他等效的 newFixedThreadPool(1) 不同,可保證無(wú)需重新配置此方法所返回的執(zhí)行程序即可使用其他的線程。 -單例線程,任意時(shí)間池中只能有一個(gè)線程 -用的是和cache池和fixed池相同的底層池,但線程數(shù)目是1-1,0秒IDLE(無(wú)IDLE)
4.newScheduledThreadPool -調(diào)度型線程池 -這個(gè)池子里的線程可以按schedule依次delay執(zhí)行,或周期執(zhí)行
這三個(gè)方法都返回了一個(gè)ExecutorService類(lèi)型的對(duì)象。實(shí)際上,ExecutorService是一個(gè)接口,它的submit()方法負(fù)責(zé)接收任務(wù)并交與線程池中的線程去運(yùn)行。submit()方法能夠接受Callable和Runnable兩種類(lèi)型的對(duì)象。它們的用法和區(qū)別如下: Runnable接口:繼承Runnable接口的類(lèi)要實(shí)現(xiàn)它的run()方法,并將執(zhí)行任務(wù)的代碼放入其中,run()方法沒(méi)有返回值。適合于只做某種操作,不關(guān)心運(yùn)行結(jié)果的情況。 Callable接口:繼承Callable接口的類(lèi)要實(shí)現(xiàn)它的call()方法,并將執(zhí)行任務(wù)的代碼放入其中,call()將任務(wù)的執(zhí)行結(jié)果作為返回值。適合于執(zhí)行某種操作后,需要知道執(zhí)行結(jié)果的情況。
無(wú)論是接收Runnable型參數(shù),還是接收Callable型參數(shù)的submit()方法,都會(huì)返回一個(gè)Future(也是一個(gè)接口)類(lèi)型的對(duì)象。該對(duì)象中包含了任務(wù)的執(zhí)行情況以及結(jié)果。調(diào)用Future的boolean isDone()方法可以獲知任務(wù)是否執(zhí)行完畢;調(diào)用Object get()方法可以獲得任務(wù)執(zhí)行后的返回結(jié)果,如果此時(shí)任務(wù)還沒(méi)有執(zhí)行完,get()方法會(huì)保持等待,直到相應(yīng)的任務(wù)執(zhí)行完畢后,才會(huì)將結(jié)果返回。
我們用下面的一個(gè)例子來(lái)演示Java5.0中線程池的使用: [java] view plaincopy import java.util.concurrent.*; public class ExecutorTest { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService es = Executors.newSingleThreadExecutor(); Future fr = es.submit(new RunnableTest());// 提交任務(wù) Future fc = es.submit(new CallableTest());// 提交任務(wù) // 取得返回值并輸出 System.out.println((String) fc.get()); // 檢查任務(wù)是否執(zhí)行完畢 if (fr.isDone()) { System.out.println("執(zhí)行完畢-RunnableTest.run()"); } else { System.out.println("未執(zhí)行完-RunnableTest.run()"); } // 檢查任務(wù)是否執(zhí)行完畢 if (fc.isDone()) { System.out.println("執(zhí)行完畢-CallableTest.run()"); } else { System.out.println("未執(zhí)行完-CallableTest.run()"); } // 停止線程池服務(wù) es.shutdown(); } } class RunnableTest implements Runnable { public void run() { System.out.println("已經(jīng)執(zhí)行-RunnableTest.run()"); } } class CallableTest implements Callable { public Object call() { System.out.println("已經(jīng)執(zhí)行-CallableTest.call()"); return "返回值-CallableTest.call()"; } }
運(yùn)行結(jié)果: 已經(jīng)執(zhí)行-RunnableTest.run() 已經(jīng)執(zhí)行-CallableTest.call() 返回值-CallableTest.call() 執(zhí)行完畢-RunnableTest.run() 執(zhí)行完畢-CallableTest.run()
使用完線程池之后,需要調(diào)用它的shutdown()方法停止服務(wù),否則其中的所有線程都會(huì)保持運(yùn)行,程序不會(huì)退出。 |
|