線程、多線程與線程池總結(jié)

先看幾個(gè)概念:
線程:進(jìn)程中負(fù)責(zé)程序執(zhí)行的執(zhí)行單元拐纱。一個(gè)進(jìn)程中至少有一個(gè)線程铜异。

多線程:解決多任務(wù)同時(shí)執(zhí)行的需求,合理使用CPU資源秸架。多線程的運(yùn)行是根據(jù)CPU切換完成揍庄,如何切換由CPU決定,因此多線程運(yùn)行具有不確定性东抹。

線程池:基本思想還是一種對象池的思想蚂子,開辟一塊內(nèi)存空間,里面存放了眾多(未死亡)的線程缭黔,池中線程執(zhí)行調(diào)度由池管理器來處理食茎。當(dāng)有線程任務(wù)時(shí),從池中取一個(gè)馏谨,執(zhí)行完成后線程對象歸池别渔,這樣可以避免反復(fù)創(chuàng)建線程對象所帶來的性能開銷,節(jié)省了系統(tǒng)的資源田巴。

如果對線程概念不清晰的話钠糊,不妨先看看我是一個(gè)線程這篇文章,擬人化的故事闡述線程的工作原理壹哺。

● 線程

創(chuàng)建線程的兩種方式:

一抄伍、繼承Thread類,擴(kuò)展線程管宵。

class DemoThread extends Thread {

    @Override
    public void run() {
        super.run();
        // Perform time-consuming operation...
    }
}

DemoThread t = new DemoThread();
t.start();
  • 繼承Thread類截珍,覆蓋run()方法。
  • 創(chuàng)建線程對象并用start()方法啟動(dòng)線程箩朴。

面試題

  • 1)線程和進(jìn)程有什么區(qū)別岗喉?

一個(gè)進(jìn)程是一個(gè)獨(dú)立(self contained)的運(yùn)行環(huán)境,它可以被看作一個(gè)程序或者一個(gè)應(yīng)用炸庞。而線程是在進(jìn)程中執(zhí)行的一個(gè)任務(wù)钱床。線程是進(jìn)程的子集,一個(gè)進(jìn)程可以有很多線程埠居,每條線程并行執(zhí)行不同的任務(wù)查牌。不同的進(jìn)程使用不同的內(nèi)存空間,而所有的線程共享一片相同的內(nèi)存空間滥壕。別把它和棧內(nèi)存搞混纸颜,每個(gè)線程都擁有單獨(dú)的棧內(nèi)存用來存儲本地?cái)?shù)據(jù)。

  • 2)如何在Java中實(shí)現(xiàn)線程绎橘?

創(chuàng)建線程有兩種方式:
一胁孙、繼承 Thread 類,擴(kuò)展線程。
二涮较、實(shí)現(xiàn) Runnable 接口稠鼻。

  • 3)Thread 類中的 start() 和 run() 方法有什么區(qū)別?

調(diào)用 start() 方法才會(huì)啟動(dòng)新線程狂票;如果直接調(diào)用 Thread 的 run() 方法枷餐,它的行為就會(huì)和普通的方法一樣;為了在新的線程中執(zhí)行我們的代碼苫亦,必須使用 Thread.start() 方法。

擴(kuò)展

Android 系統(tǒng)接口 HandlerThread 繼承了 Thread怨咪,它是一個(gè)可以使用 Handler 的 Thread屋剑,一個(gè)具有消息循環(huán)的線程。run()方法中通過 Looper.prepare() 來創(chuàng)建消息隊(duì)列诗眨,通過 Looper.loop() 來開啟消息循環(huán)唉匾。可以在 run() 方法中執(zhí)行耗時(shí)的任務(wù)匠楚,而 HandlerThread 內(nèi)部創(chuàng)建了消息隊(duì)列外界需要通過 Handler 的方式來通知 HandlerThread 執(zhí)行一個(gè)具體任務(wù)巍膘;HandlerThread 的 run() 方法是一個(gè)無限的循環(huán),可以通過它的 quite() 或 quitSafely() 方法來終止線程的執(zhí)行芋簿;

二峡懈、實(shí)現(xiàn)Runnable接口。

public class DemoActivity extends BaseActivity implements Runnable {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Thread t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {

    }
}

面試題

  • 1)用 Runnable 還是 Thread 与斤?

我們都知道可以通過繼承 Thread 類或者調(diào)用 Runnable 接口來實(shí)現(xiàn)線程肪康,問題是,創(chuàng)建線程哪種方式更好呢撩穿?什么情況下使用它磷支?這個(gè)問題很容易回答,如果你知道Java不支持類的多重繼承食寡,但允許你調(diào)用多個(gè)接口雾狈。所以如果你要繼承其他類,當(dāng)然是調(diào)用Runnable接口更好了抵皱。

  • 2)Runnable 和 Callable 有什么不同善榛?

Runnable 和 Callable 都代表那些要在不同的線程中執(zhí)行的任務(wù)。Runnable 從 JDK1.0 開始就有了叨叙,Callable 是在 JDK1.5 增加的锭弊。它們的主要區(qū)別是 Callable 的 call() 方法可以返回值和拋出異常,而 Runnable 的 run() 方法沒有這些功能擂错。Callable 可以返回裝載有計(jì)算結(jié)果的 Future 對象味滞。

?注意:這面第二個(gè)面試題主要是為了引出下面的擴(kuò)展,原諒我這樣為難人的出場。

擴(kuò)展

先看一下 Runnable 和 Callable 的源碼

public interface Runnable {
    public void run();
}

public interface Callable<V> {
    V call() throws Exception;
}

可以得出:

1)Callable 接口下的方法是 call()剑鞍,Runnable 接口的方法是 run()昨凡。
2)Callable 的任務(wù)執(zhí)行后可返回值,而 Runnable 的任務(wù)是不能返回值的蚁署。
3)call() 方法可以拋出異常便脊,run()方法不可以的。
4)運(yùn)行 Callable 任務(wù)可以拿到一個(gè) Future 對象光戈,表示異步計(jì)算的結(jié)果哪痰。它提供了檢查計(jì)算是否完成的方法,以等待計(jì)算的完成久妆,并檢索計(jì)算的結(jié)果晌杰。通過 Future 對象可以了解任務(wù)執(zhí)行情況,可取消任務(wù)的執(zhí)行筷弦,還可獲取執(zhí)行結(jié)果肋演。

但是,但是烂琴,凡事都有但是嘛...

單獨(dú)使用 Callable爹殊,無法在新線程中(new Thread(Runnable r))使用,Thread 類只支持 Runnable奸绷。不過 Callable 可以使用 ExecutorService (又拋出一個(gè)概念梗夸,這個(gè)概念將在下面的線程池中說明)。

上面又提到了 Future健盒,看一下 Future 接口:

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Future 定義了5個(gè)方法:

1)boolean cancel(boolean mayInterruptIfRunning):試圖取消對此任務(wù)的執(zhí)行绒瘦。如果任務(wù)已完成、或已取消扣癣,或者由于某些其他原因而無法取消惰帽,則此嘗試將失敗。當(dāng)調(diào)用 cancel() 時(shí)父虑,如果調(diào)用成功该酗,而此任務(wù)尚未啟動(dòng),則此任務(wù)將永不運(yùn)行士嚎。如果任務(wù)已經(jīng)啟動(dòng)呜魄,則 mayInterruptIfRunning 參數(shù)確定是否應(yīng)該以試圖停止任務(wù)的方式來中斷執(zhí)行此任務(wù)的線程。此方法返回后莱衩,對 isDone() 的后續(xù)調(diào)用將始終返回 true爵嗅。如果此方法返回 true,則對 isCancelled() 的后續(xù)調(diào)用將始終返回 true笨蚁。
2)boolean isCancelled():如果在任務(wù)正常完成前將其取消睹晒,則返回 true趟庄。
3)boolean isDone():如果任務(wù)已完成,則返回 true伪很。 可能由于正常終止戚啥、異常或取消而完成锉试,在所有這些情況中猫十,此方法都將返回 true。
4)V get()throws InterruptedException,ExecutionException:如有必要呆盖,等待計(jì)算完成拖云,然后獲取其結(jié)果。
5)V get(long timeout,TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException: 如有必要应又,最多等待為使計(jì)算完成所給定的時(shí)間之后江兢,獲取其結(jié)果(如果結(jié)果可用)。

看來 Future 接口也不能用在線程中丁频,那怎么用,誰實(shí)現(xiàn)了 Future 接口呢邑贴?答:FutureTask席里。

public class FutureTask<V> implements RunnableFuture<V> {
    ...
}

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

FutureTask 實(shí)現(xiàn)了 Runnable 和 Future,所以兼顧兩者優(yōu)點(diǎn)拢驾,既可以在 Thread 中使用奖磁,又可以在 ExecutorService 中使用。

看完上面啰哩啰嗦的介紹后繁疤,下面我們具體看一下具體使用的示例:

Callable<String> callable = new Callable<String>() {
    @Override
    public String call() throws Exception {
        return "個(gè)人博客:sunfusheng.com";
    }
};

FutureTask<String> task = new FutureTask<String>(callable);

Thread t = new Thread(task);
t.start(); // 啟動(dòng)線程
task.cancel(true); // 取消線程

使用 FutureTask 的好處是 FutureTask 是為了彌補(bǔ) Thread 的不足而設(shè)計(jì)的咖为,它可以讓程序員準(zhǔn)確地知道線程什么時(shí)候執(zhí)行完成并獲得到線程執(zhí)行完成后返回的結(jié)果。FutureTask 是一種可以取消的異步的計(jì)算任務(wù)稠腊,它的計(jì)算是通過 Callable 實(shí)現(xiàn)的躁染,它等價(jià)于可以攜帶結(jié)果的 Runnable,并且有三個(gè)狀態(tài):等待架忌、運(yùn)行和完成吞彤。完成包括所有計(jì)算以任意的方式結(jié)束,包括正常結(jié)束叹放、取消和異常饰恕。

查看具體操作代碼請參考 《個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy》,感謝您的關(guān)注井仰。

● 多線程

多線程的概念很好理解就是多條線程同時(shí)存在埋嵌,但要用好多線程確不容易,涉及到多線程間通信俱恶,多線程共用一個(gè)資源等諸多問題雹嗦。

使用多線程的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
1)適當(dāng)?shù)奶岣叱绦虻膱?zhí)行效率(多個(gè)線程同時(shí)執(zhí)行)范舀。
2)適當(dāng)?shù)奶岣吡速Y源利用率(CPU、內(nèi)存等)俐银。
缺點(diǎn):
1)占用一定的內(nèi)存空間尿背。
2)線程越多CPU的調(diào)度開銷越大。
3)程序的復(fù)雜度會(huì)上升捶惜。

對于多線程的示例代碼感興趣的可以自己寫Demo啦田藐,去運(yùn)行體會(huì),下面我主要列出一些多線程的技術(shù)點(diǎn)吱七。

synchronized

同步塊大家都比較熟悉汽久,通過 synchronized 關(guān)鍵字來實(shí)現(xiàn);所有加上 synchronized 的方法和塊語句踊餐,在多線程訪問的時(shí)候景醇,同一時(shí)刻只能有一個(gè)線程能夠訪問。

wait()吝岭、notify()三痰、notifyAll()

這三個(gè)方法是 java.lang.Object 的 final native 方法,任何繼承 java.lang.Object 的類都有這三個(gè)方法窜管。它們是Java語言提供的實(shí)現(xiàn)線程間阻塞和控制進(jìn)程內(nèi)調(diào)度的底層機(jī)制散劫,平時(shí)我們會(huì)很少用到的。

wait():
導(dǎo)致線程進(jìn)入等待狀態(tài)幕帆,直到它被其他線程通過notify()或者notifyAll喚醒获搏,該方法只能在同步方法中調(diào)用。

notify():
隨機(jī)選擇一個(gè)在該對象上調(diào)用wait方法的線程失乾,解除其阻塞狀態(tài)常熙,該方法只能在同步方法或同步塊內(nèi)部調(diào)用。

notifyAll():
解除所有那些在該對象上調(diào)用wait方法的線程的阻塞狀態(tài)碱茁,同樣該方法只能在同步方法或同步塊內(nèi)部調(diào)用裸卫。

調(diào)用這三個(gè)方法中任意一個(gè),當(dāng)前線程必須是鎖的持有者纽竣,如果不是會(huì)拋出一個(gè) IllegalMonitorStateException 異常彼城。

wait() 與 Thread.sleep(long time) 的區(qū)別

sleep():在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),該線程不丟失任何監(jiān)視器的所屬權(quán)退个,sleep() 是 Thread 類專屬的靜態(tài)方法募壕,針對一個(gè)特定的線程。
wait() 方法使實(shí)體所處線程暫停執(zhí)行语盈,從而使對象進(jìn)入等待狀態(tài)舱馅,直到被 notify() 方法通知或者 wait() 的等待的時(shí)間到。sleep() 方法使持有的線程暫停運(yùn)行刀荒,從而使線程進(jìn)入休眠狀態(tài)代嗤,直到用 interrupt 方法來打斷他的休眠或者 sleep 的休眠的時(shí)間到棘钞。
wait() 方法進(jìn)入等待狀態(tài)時(shí)會(huì)釋放同步鎖,而 sleep() 方法不會(huì)釋放同步鎖干毅。所以宜猜,當(dāng)一個(gè)線程無限 sleep 時(shí)又沒有任何人去 interrupt 它的時(shí)候,程序就產(chǎn)生大麻煩了硝逢,notify() 是用來通知線程姨拥,但在 notify() 之前線程是需要獲得 lock 的。另個(gè)意思就是必須寫在 synchronized(lockobj) {...} 之中渠鸽。wait() 也是這個(gè)樣子叫乌,一個(gè)線程需要釋放某個(gè) lock,也是在其獲得 lock 情況下才能夠釋放徽缚,所以 wait() 也需要放在 synchronized(lockobj) {...} 之中憨奸。

volatile 關(guān)鍵字

volatile 是一個(gè)特殊的修飾符,只有成員變量才能使用它凿试。在Java并發(fā)程序缺少同步類的情況下排宰,多線程對成員變量的操作對其它線程是透明的。volatile 變量可以保證下一個(gè)讀取操作會(huì)在前一個(gè)寫操作之后發(fā)生那婉。線程都會(huì)直接從內(nèi)存中讀取該變量并且不緩存它额各。這就確保了線程讀取到的變量是同內(nèi)存中是一致的。

ThreadLocal 變量

ThreadLocal 是Java里一種特殊的變量吧恃。每個(gè)線程都有一個(gè) ThreadLocal 就是每個(gè)線程都擁有了自己獨(dú)立的一個(gè)變量,競爭條件被徹底消除了麻诀。如果為每個(gè)線程提供一個(gè)自己獨(dú)有的變量拷貝痕寓,將大大提高效率。首先蝇闭,通過復(fù)用減少了代價(jià)高昂的對象的創(chuàng)建個(gè)數(shù)呻率。其次,你在沒有使用高代價(jià)的同步或者不變性的情況下獲得了線程安全呻引。

join() 方法

join() 方法定義在 Thread 類中礼仗,所以調(diào)用者必須是一個(gè)線程,join() 方法主要是讓調(diào)用該方法的 Thread 完成 run() 方法里面的東西后逻悠,再執(zhí)行 join() 方法后面的代碼元践,看下下面的"意思"代碼:

Thread t1 = new Thread(計(jì)數(shù)線程一);  
Thread t2 = new Thread(計(jì)數(shù)線程二);  
t1.start();  
t1.join(); // 等待計(jì)數(shù)線程一執(zhí)行完成,再執(zhí)行計(jì)數(shù)線程二
t2.start();  

啟動(dòng) t1 后童谒,調(diào)用了 join() 方法单旁,直到 t1 的計(jì)數(shù)任務(wù)結(jié)束,才輪到 t2 啟動(dòng)饥伊,然后 t2 才開始計(jì)數(shù)任務(wù)象浑,兩個(gè)線程是按著嚴(yán)格的順序來執(zhí)行的蔫饰。如果 t2 的執(zhí)行需要依賴于 t1 中的完整數(shù)據(jù)的時(shí)候,這種方法就可以很好的確保兩個(gè)線程的同步性愉豺。

Thread.yield() 方法

Thread.sleep(long time):線程暫時(shí)終止執(zhí)行(睡眠)一定的時(shí)間篓吁。
Thread.yield():線程放棄運(yùn)行,將CPU的控制權(quán)讓出蚪拦。

這兩個(gè)方法都會(huì)將當(dāng)前運(yùn)行線程的CPU控制權(quán)讓出來杖剪,但 sleep() 方法在指定的睡眠時(shí)間內(nèi)一定不會(huì)再得到運(yùn)行機(jī)會(huì),直到它的睡眠時(shí)間完成外盯;而 yield() 方法讓出控制權(quán)后摘盆,還有可能馬上被系統(tǒng)的調(diào)度機(jī)制選中來運(yùn)行,比如饱苟,執(zhí)行yield()方法的線程優(yōu)先級高于其他的線程孩擂,那么這個(gè)線程即使執(zhí)行了 yield() 方法也可能不能起到讓出CPU控制權(quán)的效果,因?yàn)樗尦隹刂茩?quán)后箱熬,進(jìn)入排隊(duì)隊(duì)列类垦,調(diào)度機(jī)制將從等待運(yùn)行的線程隊(duì)列中選出一個(gè)等級最高的線程來運(yùn)行,那么它又(很可能)被選中來運(yùn)行城须。

擴(kuò)展

線程調(diào)度策略

(1) 搶占式調(diào)度策略

Java運(yùn)行時(shí)系統(tǒng)的線程調(diào)度算法是搶占式的蚤认。Java運(yùn)行時(shí)系統(tǒng)支持一種簡單的固定優(yōu)先級的調(diào)度算法。如果一個(gè)優(yōu)先級比其他任何處于可運(yùn)行狀態(tài)的線程都高的線程進(jìn)入就緒狀態(tài)糕伐,那么運(yùn)行時(shí)系統(tǒng)就會(huì)選擇該線程運(yùn)行砰琢。新的優(yōu)先級較高的線程搶占了其他線程。但是Java運(yùn)行時(shí)系統(tǒng)并不搶占同優(yōu)先級的線程良瞧。換句話說陪汽,Java運(yùn)行時(shí)系統(tǒng)不是分時(shí)的。然而褥蚯,基于Java Thread類的實(shí)現(xiàn)系統(tǒng)可能是支持分時(shí)的挚冤,因此編寫代碼時(shí)不要依賴分時(shí)。當(dāng)系統(tǒng)中的處于就緒狀態(tài)的線程都具有相同優(yōu)先級時(shí)赞庶,線程調(diào)度程序采用一種簡單的训挡、非搶占式的輪轉(zhuǎn)的調(diào)度順序。

(2) 時(shí)間片輪轉(zhuǎn)調(diào)度策略

有些系統(tǒng)的線程調(diào)度采用時(shí)間片輪轉(zhuǎn)調(diào)度策略歧强。這種調(diào)度策略是從所有處于就緒狀態(tài)的線程中選擇優(yōu)先級最高的線程分配一定的CPU時(shí)間運(yùn)行澜薄。該時(shí)間過后再選擇其他線程運(yùn)行。只有當(dāng)線程運(yùn)行結(jié)束摊册、放棄(yield)CPU或由于某種原因進(jìn)入阻塞狀態(tài)表悬,低優(yōu)先級的線程才有機(jī)會(huì)執(zhí)行。如果有兩個(gè)優(yōu)先級相同的線程都在等待CPU丧靡,則調(diào)度程序以輪轉(zhuǎn)的方式選擇運(yùn)行的線程蟆沫。

以上把這些技術(shù)點(diǎn)總結(jié)出來籽暇,后面我會(huì)把多線程這塊的示例代碼更新到 《個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy》,感謝您的關(guān)注饭庞。

● 線程池

創(chuàng)建多個(gè)線程不光麻煩而且相對影響系統(tǒng)性能戒悠,接下來讓我看看使用線程池來操作多線程。我把自己的 《個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy》 中線程池轉(zhuǎn)成一個(gè) gif 效果圖舟山,大家可以實(shí)際把玩下去感受線程池的原理绸狐,有興趣的同學(xué)也可以先 star 下,我會(huì)在接下來的幾個(gè)月把這個(gè)學(xué)習(xí)的Demo工程完善好累盗。

線程池.gif

線程池的優(yōu)點(diǎn)

1)避免線程的創(chuàng)建和銷毀帶來的性能開銷寒矿。
2)避免大量的線程間因互相搶占系統(tǒng)資源導(dǎo)致的阻塞現(xiàn)象。
3}能夠?qū)€程進(jìn)行簡單的管理并提供定時(shí)執(zhí)行若债、間隔執(zhí)行等功能符相。

再擼一擼概念

Java里面線程池的頂級接口是 Executor,不過真正的線程池接口是 ExecutorService蠢琳, ExecutorService 的默認(rèn)實(shí)現(xiàn)是 ThreadPoolExecutor啊终;普通類 Executors 里面調(diào)用的就是 ThreadPoolExecutor。

照例看一下各個(gè)接口的源碼:

public interface Executor {
    void execute(Runnable command);
}

public interface ExecutorService extends Executor {
    void shutdown();
    List<Runnable> shutdownNow();
    
    boolean isShutdown();
    boolean isTerminated();
    
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);
    ...
}

public class Executors {
    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, 
                            new SynchronousQueue<Runnable>());
    }
    ...
}

下面我創(chuàng)建的一個(gè)線程池:

ExecutorService pool = Executors.newCachedThreadPool();

Executors 提供四種線程池:

  • 1)newCachedThreadPool 是一個(gè)可根據(jù)需要?jiǎng)?chuàng)建新線程的線程池傲须,但是在以前構(gòu)造的線程可用時(shí)將重用它們蓝牲。對于執(zhí)行很多短期異步任務(wù)的程序而言,這些線程池通程┓恚可提高程序性能例衍。調(diào)用 execute() 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的已卸,則創(chuàng)建一個(gè)新線程并添加到池中佛玄。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。因此咬最,長時(shí)間保持空閑的線程池不會(huì)使用任何資源。注意欠动,可以使用 ThreadPoolExecutor 構(gòu)造方法創(chuàng)建具有類似屬性但細(xì)節(jié)不同(例如超時(shí)參數(shù))的線程池永乌。

  • 2)newSingleThreadExecutor 創(chuàng)建是一個(gè)單線程池,也就是該線程池只有一個(gè)線程在工作具伍,所有的任務(wù)是串行執(zhí)行的翅雏,如果這個(gè)唯一的線程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線程來替代它人芽,此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行望几。

  • 3)newFixedThreadPool 創(chuàng)建固定大小的線程池,每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線程萤厅,直到線程達(dá)到線程池的最大大小橄抹,線程池的大小一旦達(dá)到最大值就會(huì)保持不變靴迫,如果某個(gè)線程因?yàn)閳?zhí)行異常而結(jié)束,那么線程池會(huì)補(bǔ)充一個(gè)新線程楼誓。

  • 4)newScheduledThreadPool 創(chuàng)建一個(gè)大小無限的線程池玉锌,此線程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

通過 ThreadPoolExecutor 的構(gòu)造函數(shù)疟羹,擼一擼線程池相關(guān)參數(shù)的概念:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 
        threadFactory, defaultHandler);
}
  • 1)corePoolSize:線程池的核心線程數(shù)主守,一般情況下不管有沒有任務(wù)都會(huì)一直在線程池中一直存活,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 設(shè)置為 true 時(shí)榄融,閑置的核心線程會(huì)存在超時(shí)機(jī)制参淫,如果在指定時(shí)間沒有新任務(wù)來時(shí),核心線程也會(huì)被終止愧杯,而這個(gè)時(shí)間間隔由第3個(gè)屬性 keepAliveTime 指定涎才。

  • 2)maximumPoolSize:線程池所能容納的最大線程數(shù),當(dāng)活動(dòng)的線程數(shù)達(dá)到這個(gè)值后民效,后續(xù)的新任務(wù)將會(huì)被阻塞憔维。

  • 3)keepAliveTime:控制線程閑置時(shí)的超時(shí)時(shí)長,超過則終止該線程畏邢。一般情況下用于非核心線程业扒,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 設(shè)置為 true時(shí),也作用于核心線程舒萎。

  • 4)unit:用于指定 keepAliveTime 參數(shù)的時(shí)間單位程储,TimeUnit 是個(gè) enum 枚舉類型,常用的有:TimeUnit.HOURS(小時(shí))臂寝、TimeUnit.MINUTES(分鐘)章鲤、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒)等。

  • 5)workQueue:線程池的任務(wù)隊(duì)列咆贬,通過線程池的 execute(Runnable command) 方法會(huì)將任務(wù) Runnable 存儲在隊(duì)列中败徊。

  • 6)threadFactory:線程工廠,它是一個(gè)接口掏缎,用來為線程池創(chuàng)建新線程的皱蹦。

線程池的關(guān)閉

ThreadPoolExecutor 提供了兩個(gè)方法,用于線程池的關(guān)閉眷蜈,分別是 shutdown() 和 shutdownNow()沪哺。

shutdown():不會(huì)立即的終止線程池,而是要等所有任務(wù)緩存隊(duì)列中的任務(wù)都執(zhí)行完后才終止酌儒,但再也不會(huì)接受新的任務(wù)辜妓。
shutdownNow():立即終止線程池,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊(duì)列籍滴,返回尚未執(zhí)行的任務(wù)酪夷。

面試題

1)什么是 Executor 框架?

Executor框架在Java 5中被引入异逐,Executor 框架是一個(gè)根據(jù)一組執(zhí)行策略調(diào)用捶索、調(diào)度、執(zhí)行和控制的異步任務(wù)的框架灰瞻。

無限制的創(chuàng)建線程會(huì)引起應(yīng)用程序內(nèi)存溢出腥例,所以創(chuàng)建一個(gè)線程池是個(gè)更好的的解決方案,因?yàn)榭梢韵拗凭€程的數(shù)量并且可以回收再利用這些線程酝润。利用 Executor 框架可以非常方便的創(chuàng)建一個(gè)線程池燎竖。

2)Executors 類是什么?

Executors為Executor要销、ExecutorService构回、ScheduledExecutorService、ThreadFactory 和 Callable 類提供了一些工具方法疏咐。Executors 可以用于方便的創(chuàng)建線程池纤掸。

查看具體操作代碼請參考 《個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy》,感謝您的關(guān)注浑塞。

關(guān)于我

個(gè)人郵箱:sfsheng0322@126.com
GitHub主頁
簡書主頁
個(gè)人博客
新浪微博

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末借跪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子酌壕,更是在濱河造成了極大的恐慌掏愁,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,273評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卵牍,死亡現(xiàn)場離奇詭異果港,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)糊昙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,349評論 3 398
  • 文/潘曉璐 我一進(jìn)店門辛掠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人释牺,你說我怎么就攤上這事汹桦≌锔耍” “怎么了奴愉?”我有些...
    開封第一講書人閱讀 167,709評論 0 360
  • 文/不壞的土叔 我叫張陵职辨,是天一觀的道長厅各。 經(jīng)常有香客問我镜撩,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,520評論 1 296
  • 正文 為了忘掉前任袁梗,我火速辦了婚禮宜鸯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘遮怜。我一直安慰自己淋袖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,515評論 6 397
  • 文/花漫 我一把揭開白布锯梁。 她就那樣靜靜地躺著即碗,像睡著了一般。 火紅的嫁衣襯著肌膚如雪陌凳。 梳的紋絲不亂的頭發(fā)上剥懒,一...
    開封第一講書人閱讀 52,158評論 1 308
  • 那天,我揣著相機(jī)與錄音合敦,去河邊找鬼初橘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛充岛,可吹牛的內(nèi)容都是我干的保檐。 我是一名探鬼主播,決...
    沈念sama閱讀 40,755評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼崔梗,長吁一口氣:“原來是場噩夢啊……” “哼夜只!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炒俱,我...
    開封第一講書人閱讀 39,660評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盐肃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后权悟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砸王,經(jīng)...
    沈念sama閱讀 46,203評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,287評論 3 340
  • 正文 我和宋清朗相戀三年峦阁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谦铃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,427評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榔昔,死狀恐怖驹闰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撒会,我是刑警寧澤嘹朗,帶...
    沈念sama閱讀 36,122評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站诵肛,受9級特大地震影響屹培,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,801評論 3 333
  • 文/蒙蒙 一褪秀、第九天 我趴在偏房一處隱蔽的房頂上張望蓄诽。 院中可真熱鬧,春花似錦媒吗、人聲如沸仑氛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,272評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锯岖。三九已至,卻和暖如春甫何,著一層夾襖步出監(jiān)牢的瞬間嚎莉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工沛豌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留趋箩,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,808評論 3 376
  • 正文 我出身青樓加派,卻偏偏與公主長得像叫确,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子芍锦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,440評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 先看幾個(gè)概念:線程:進(jìn)程中負(fù)責(zé)程序執(zhí)行的執(zhí)行單元娄琉。一個(gè)進(jìn)程中至少有一個(gè)線程次乓。多線程:解決多任務(wù)同時(shí)執(zhí)行的需求,合理...
    yeying12321閱讀 544評論 0 0
  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍(lán)閱讀 7,355評論 3 87
  • 線程概述 線程與進(jìn)程 進(jìn)程 ?每個(gè)運(yùn)行中的任務(wù)(通常是程序)就是一個(gè)進(jìn)程孽水。當(dāng)一個(gè)程序進(jìn)入內(nèi)存運(yùn)行時(shí)票腰,即變成了一個(gè)進(jìn)...
    閩越布衣閱讀 1,010評論 1 7
  • 下面是我自己收集整理的Java線程相關(guān)的面試題,可以用它來好好準(zhǔn)備面試女气。 參考文檔:-《Java核心技術(shù) 卷一》-...
    阿呆變Geek閱讀 14,857評論 14 507
  • 1把東西歸類杏慰,歸類完盡量把東西放到盒里。 2把盒子放到抽屜里炼鞠,柜子里缘滥。 3東西的放置應(yīng)該遵循在哪里使用就放在那附近...
    甜菜1991閱讀 170評論 0 0