線程Thread

目錄

概念

線程:系統(tǒng)調(diào)度的最小單位洛退,CPU資源分配的基本單位。
進(jìn)程:一段執(zhí)行的程序女阀,可以包含多個(gè)進(jìn)程塌衰。

在Android中只有一個(gè)主線程main,也稱之為UI線程跛十,用于運(yùn)行四大組件以及與用戶的交互。
而子線程也稱之為工作線程,用于執(zhí)行耗時(shí)操作压怠,避免在UI線程中執(zhí)行造成卡頓從而出現(xiàn)ANR。

線程的創(chuàng)建

1飞苇,繼承Thread類創(chuàng)建線程

//創(chuàng)建線程(缺點(diǎn):由于java中是單繼承菌瘫,無法再通過繼承進(jìn)行功能擴(kuò)展)
class MyThread extends Thread {
        @Override
        public void run() {
            //執(zhí)行線程操作
        }
    }
//開啟線程
new MyThread().start();

2蜗顽,實(shí)現(xiàn)Runnable接口創(chuàng)建線程

class MyRunnable implements Runnable {
        @Override
        public void run() {
            //執(zhí)行線程操作
        }
    }
開啟線程(一般采用這種方案,既能保證Thread 的擴(kuò)展雨让,同時(shí)Runnable對(duì)象也可以作為任務(wù)單元在其它地方使用)
new Thread(new MyRunnable()).start();

3雇盖,使用Callable和Future創(chuàng)建線程

FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
    @Override
    public Integer call() throws Exception {
        Log.d(TAG, "call: AAA = " + Thread.currentThread().getName());
        return 10;
    }
});
//這種方式針對(duì)需要獲取返回值的線程開啟
new Thread(task,"有返回值的線程").start();
try {
    Integer integer = task.get();
    Log.d(TAG, "onCreate: AAA = " + integer);
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}
//打印結(jié)果
10-20 21:26:53.838 28300-28329/com.learn.study D/MainActivity: call: AAA = 有返回值的線程
10-20 21:26:53.838 28300-28300/com.learn.study D/MainActivity: onCreate: AAA = 10

線程的生命周期

線程狀態(tài)轉(zhuǎn)換關(guān)系(來源于書籍:java虛擬機(jī))

1,新建(New):創(chuàng)建后尚未啟動(dòng)的線程處于這種狀態(tài)栖忠。
2崔挖,運(yùn)行(Runable):Runable包括了操作系統(tǒng)線程狀態(tài)中的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行庵寞,也有可能正在等待著CPU為它分配執(zhí)行時(shí)間狸相。
3,無限期等待(Waiting):處于這種狀態(tài)的線程不會(huì)被分配CPU執(zhí)行時(shí)間皇帮,它們要等待被其他線程顯式地喚醒卷哩。

以下方法會(huì)讓線程陷入無限期的等待狀態(tài):

  • 沒有設(shè)置Timeout參數(shù)的Object.wait()
  • 沒有設(shè)置Timeout參數(shù)的Thread.join()
  • LockSupport.park()

4,限期等待(Timed Waiting):處于這種狀態(tài)的線程也不會(huì)被分配CPU執(zhí)行時(shí)間属拾,不過無須等待被其他線程顯式地喚醒将谊,在一定時(shí)間之后它們會(huì)由系統(tǒng)自動(dòng)喚醒。

以下方法會(huì)讓線程進(jìn)入限期等待狀態(tài):

  • Thread.sleep()方法渐白。
  • 設(shè)置了Timeout參數(shù)的Object.wait()方法尊浓。
  • 設(shè)置了Timeout參數(shù)的Thread.join()方法。
  • LockSupport.parkNanos()方法纯衍。
  • LockSupport.parkUntil()方法

5栋齿,阻塞(Blocked):線程被阻塞了,“阻塞狀態(tài)”與“等待狀態(tài)”的區(qū)別是:“阻塞狀態(tài)”在等待著獲取到一個(gè)排他鎖襟诸,這個(gè)事件將在另外一個(gè)線程放棄這個(gè)鎖的時(shí)候發(fā)生瓦堵;而“等待狀態(tài)”則是在等待一段時(shí)間,或者喚醒動(dòng)作的發(fā)生歌亲。 在程序等待進(jìn)入同步區(qū)域的時(shí)候菇用,線程將進(jìn)入這種狀態(tài)。
6陷揪,結(jié)束(Terminated):已終止線程的線程狀態(tài)惋鸥,線程已經(jīng)結(jié)束執(zhí)行。

sleep()和wait()的區(qū)別

  • sleep()來自Thread類悍缠;wait()來自O(shè)bject類
  • sleep()用于線程控制自身流程卦绣;而wait()用于線程間通信,配合notify()/notifyAll()在同步代碼塊或同步方法里使用
  • sleep()的線程不會(huì)釋放對(duì)象鎖飞蚓;wait()會(huì)釋放對(duì)象鎖進(jìn)入等待狀態(tài)滤港,使得其他線程能使用同步代碼塊或同步方法

多線程

1,優(yōu)點(diǎn):為了充分利用計(jì)算機(jī)處理器的能力玷坠,避免處理器在磁盤I/O蜗搔、網(wǎng)絡(luò)通信或數(shù)據(jù)庫訪問時(shí)總是處于等待其他資源的狀態(tài)劲藐。將單線程的串行處理改為多線程的并行處理八堡,可以大大提高處理效率樟凄。

2,線程安全:當(dāng)多個(gè)線程訪問一個(gè)對(duì)象時(shí)兄渺,如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行缝龄,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作挂谍,調(diào)用這個(gè)對(duì)象的行為都可以獲得正確的結(jié)果叔壤,那這個(gè)對(duì)象是線程安全的】谛穑基本特點(diǎn)如下:

1炼绘,原子性:簡單說就是相關(guān)操作不會(huì)中途被其他線程干擾,一般通過同步機(jī)制保障妄田。如使用:synchronized或ReentrantLock(對(duì)接口Lock的實(shí)現(xiàn))
2俺亮,可見性:是一個(gè)線程修改了某個(gè)共享變量,其狀態(tài)能夠立即被其它線程知曉疟呐。使用volatile關(guān)鍵字修飾變量
3脚曾,有序性:保證線程內(nèi)串行語義,避免指令重排等启具。

volatile: 本身就包含了禁止指令重排序的語義
synchronized:保證一個(gè)變量在同一個(gè)時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作本讥,使得持有同一個(gè)鎖的兩個(gè)同步塊只能串行地進(jìn)入

ReentrantLock和synchronized的區(qū)別
1,ReentrantLock作為Lock的實(shí)現(xiàn)類鲁冯,使用時(shí)更加靈活拷沸,可以進(jìn)行中斷操作,執(zhí)行完需要調(diào)用unLock()進(jìn)行釋放(在finally中釋放鎖)薯演。
2撞芍,ReentrantLock默認(rèn)也是不公平鎖,但可以在創(chuàng)建時(shí)的構(gòu)造方法傳入true實(shí)現(xiàn)公平鎖涣仿。但是會(huì)增加額外的開銷
3勤庐,鎖綁定多個(gè)條件:一個(gè)ReentrantLock對(duì)象可以通過多次調(diào)用newCondition()同時(shí)綁定多個(gè)Condition對(duì)象。而在synchronized中好港,鎖對(duì)象wait()和notify()或notifyAl()只能實(shí)現(xiàn)一個(gè)隱含的條件愉镰,若要和多于一個(gè)的條件關(guān)聯(lián)不得不額外地添加一個(gè)鎖。
4钧汹,synchronized內(nèi)部鎖使用非公平策略丈探,是非公平鎖,不會(huì)增加上下文切換開銷拔莱,使用監(jiān)視器Monitor來實(shí)現(xiàn)碗降。

ThreadLocal:線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類隘竭,可以在指定的線程內(nèi)存儲(chǔ)數(shù)據(jù),通過泛型來聲明數(shù)據(jù)類型讼渊。變量的作用域?yàn)楫?dāng)前的線程动看。最典型的使用是在線程中獲取Loop對(duì)象時(shí),采用的就是ThreadLocal來進(jìn)行存取爪幻。提供三個(gè)方法:
set()用于存儲(chǔ)數(shù)據(jù)菱皆,
get()用于獲取數(shù)據(jù),
remove()用于手動(dòng)釋放存儲(chǔ)的變量,
initialValue():用于重寫該方法設(shè)定默認(rèn)值

3,線程調(diào)度:指系統(tǒng)為線程分配處理器使用權(quán)的過程挨稿。主要調(diào)度方式有兩種仇轻,分別是協(xié)同式線程調(diào)度(Cooperative Threads-Scheduling)和搶占式線程調(diào)度(Preemptive ThreadsScheduling)。

1奶甘,協(xié)同式調(diào)度:線程的執(zhí)行時(shí)間由線程本身來控制篷店,線程把自己的工作執(zhí)行完了之后,要主動(dòng)通知系統(tǒng)切換到另外一個(gè)線程上臭家。 好處:實(shí)現(xiàn)簡單疲陕,而且由于線程要把自己的事情干完后才會(huì)進(jìn)行線程切換,切換操作對(duì)線程自己是可知的侣监,所以沒有什么線程同步的問題鸭轮。壞處:線程執(zhí)行時(shí)間不可控制,甚至如果一個(gè)線程編寫有問題橄霉,一直不告知系統(tǒng)進(jìn)行線程切換窃爷,那么程序就會(huì)一直阻塞在那里。
2姓蜂,搶占式調(diào)度:每個(gè)線程將由系統(tǒng)來分配執(zhí)行時(shí)間按厘,線程的切換不由線程本身來決定(在Java中,Thread.yield()可以讓出執(zhí)行時(shí)間钱慢,但是要獲取執(zhí)行時(shí)間的話逮京,線程本身是沒有什么辦法的)。 在這種實(shí)現(xiàn)線程調(diào)度的方式下束莫,線程的執(zhí)行時(shí)間是系統(tǒng)可控的懒棉,也不會(huì)有一個(gè)線程導(dǎo)致整個(gè)進(jìn)程阻塞的問題。但線程優(yōu)先級(jí)并不是太靠譜览绿。
Java使用的線程調(diào)度方式就是搶占式調(diào)度

4策严,鎖優(yōu)化:為了在線程之間更高效地共享數(shù)據(jù),以及解決競爭問題饿敲,從而提高程序的執(zhí)行效率妻导。

1,自旋鎖:競爭鎖失敗的線程,并不會(huì)真實(shí)的在操作系統(tǒng)層面掛起等待倔韭,而是JVM會(huì)讓線程做幾個(gè)空循環(huán)(基于預(yù)測在不久的將來就能獲得)术浪,在經(jīng)過若干次循環(huán)后,如果可以獲得鎖寿酌,那么進(jìn)入臨界區(qū)胰苏,如果還不能獲得鎖,才會(huì)真實(shí)的將線程在操作系統(tǒng)層面進(jìn)行掛起份名。
適用場景:自旋鎖可以減少線程的阻塞碟联,這對(duì)于鎖競爭不激烈妓美,且占用鎖時(shí)間非常短的代碼塊來說僵腺,有較大的性能提升,因?yàn)樽孕南臅?huì)小于線程阻塞掛起操作的消耗壶栋。如果鎖的競爭激烈辰如,或者持有鎖的線程需要長時(shí)間占用鎖執(zhí)行同步塊,就不適合使用自旋鎖了贵试,因?yàn)樽孕i在獲取鎖前一直都是占用cpu做無用功琉兜,線程自旋的消耗大于線程阻塞掛起操作的消耗,造成cpu的浪費(fèi)毙玻。
2豌蟋,鎖消除:虛擬機(jī)中編譯器在運(yùn)行時(shí),對(duì)一些代碼上要求同步桑滩,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進(jìn)行消除梧疲。鎖消除的主要判定依據(jù)來源于逃逸分析的數(shù)據(jù)支持,如果判斷在一段代碼中运准,堆上的所有數(shù)據(jù)都不會(huì)逃逸出去從而被其他線程訪問到幌氮,那就可以把它們當(dāng)做棧上數(shù)據(jù)對(duì)待,認(rèn)為它們是線程私有的胁澳,同步加鎖自然就無須進(jìn)行该互。
3,鎖粗化:一般情況下韭畸,推薦將同步塊的作用范圍限制到只在共享數(shù)據(jù)的實(shí)際作用域中才進(jìn)行同步宇智,使得需要同步的操作數(shù)量盡可能變小,保證就算存在鎖競爭胰丁,等待鎖的線程也能盡快拿到鎖随橘。但如果反復(fù)操作對(duì)同一個(gè)對(duì)象進(jìn)行加鎖和解鎖,即使沒有線程競爭隘马,頻繁地進(jìn)行互斥同步操作也會(huì)導(dǎo)致不必要的性能損耗太防,此時(shí),虛擬機(jī)將會(huì)把加鎖同步的范圍粗化到整個(gè)操作序列的外部,這樣只需加一次鎖蜒车。
4讳嘱,輕量級(jí)鎖:并不是用來代替重量級(jí)鎖的,它的本意是在沒有多線程競爭的前提下酿愧,減少傳統(tǒng)的重量級(jí)鎖使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗沥潭。
5,偏向鎖:目的是消除數(shù)據(jù)在無競爭情況下的同步原語嬉挡,進(jìn)一步提高程序的運(yùn)行性能钝鸽。 如果說輕量級(jí)鎖是在無競爭的情況下使用CAS操作去消除同步使用的互斥量,那偏向鎖就是在無競爭的情況下把整個(gè)同步都消除掉庞钢,連CAS操作都不做了拔恰。偏向鎖可以提高帶有同步但無競爭的程序性能。 它同樣是一個(gè)帶有效益權(quán)衡(TradeOff)性質(zhì)的優(yōu)化基括,也就是說颜懊,它并不一定總是對(duì)程序運(yùn)行有利,如果程序中大多數(shù)的鎖總是被多個(gè)不同的線程訪問风皿,那偏向模式就是多余的河爹。

5,java中信號(hào)量Semaphore:用于控制臨界區(qū)域訪問的個(gè)數(shù)桐款,即可以設(shè)置多個(gè)線程或單個(gè)線程對(duì)同一個(gè)資源的使用咸这。內(nèi)部使用計(jì)數(shù)的方式對(duì)線程進(jìn)行阻塞控制。

  • 初始化時(shí)定義同時(shí)控制訪問的個(gè)數(shù)
  • 調(diào)用acquire()方法獲取當(dāng)前線程是否可以執(zhí)行魔眨。當(dāng)計(jì)數(shù)大于0媳维,臨界區(qū)域可以被訪問,統(tǒng)計(jì)計(jì)數(shù)減少1冰沙。否則當(dāng)前線程對(duì)臨界區(qū)域的訪問被阻塞侨艾。
  • 調(diào)用release()方法,計(jì)數(shù)加1拓挥,然后喚醒等待隊(duì)列中的線程唠梨。內(nèi)部使用鏈表進(jìn)行存儲(chǔ)。

6侥啤,Monitor:同一個(gè)時(shí)刻当叭,只有一個(gè)線程能夠進(jìn)行monitor定義的臨界區(qū),可以達(dá)到互斥的效果盖灸。

  • java中通過synchronized的修飾限定了臨界區(qū)域的范圍蚁鳖。
  • java中的關(guān)聯(lián)對(duì)象:monitor object,也就是java中的object對(duì)象赁炎。object在存儲(chǔ)時(shí)分為:對(duì)象頭醉箕,實(shí)例數(shù)據(jù),對(duì)齊填充,在對(duì)象頭中保留了鎖標(biāo)識(shí)讥裤。當(dāng)前線程執(zhí)行時(shí)不滿足monitor條件時(shí)會(huì)加入到waitSet中放棒,當(dāng)添加滿足時(shí)被喚醒后轉(zhuǎn)移到EntrySet中(對(duì)應(yīng)c語言實(shí)現(xiàn)的objectMonitor中)。
  • monitor提供wait()己英,signal()间螟,signalAll()能夠?qū)崿F(xiàn)等待與喚醒功能。

補(bǔ)充:鎖的是對(duì)象而不是方法损肛,同時(shí)synchronized()代碼塊不能保證一次執(zhí)行完厢破。

new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized ("aa") {
                    Log.d(TAG, "run: 11");
                    try {
                        Thread.sleep(100);
                        Log.d(TAG, "run: 22");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized ("aa") {
                    Log.d(TAG, "run: 33");
                    try {
                        Thread.sleep(100);
                        Log.d(TAG, "run: 44");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "run: 55");
                try {
                    Thread.sleep(100);
                    Log.d(TAG, "run: 66");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
//打印結(jié)果:(第一條線程執(zhí)行時(shí)插入了第三條線程的內(nèi)容,但包含相同鎖對(duì)象進(jìn)行互斥的代碼塊必須相互獨(dú)立的一次執(zhí)行完)
10-20 23:47:43.445 7141-7171/com.learn.study D/MainActivity: run: 11
10-20 23:47:43.446 7141-7173/com.learn.study D/MainActivity: run: 55
10-20 23:47:43.545 7141-7171/com.learn.study D/MainActivity: run: 22
10-20 23:47:43.546 7141-7173/com.learn.study D/MainActivity: run: 66
10-20 23:47:43.552 7141-7172/com.learn.study D/MainActivity: run: 33
10-20 23:47:43.652 7141-7172/com.learn.study D/MainActivity: run: 44

5治拿,常見案例:

//模擬四個(gè)窗口賣票
public class SellTicket {

    private static final String TAG = "SellTicket";

    //用于統(tǒng)計(jì)四個(gè)窗口賣的票
    private static List<Integer> sWindow1 = new ArrayList<>();
    private static List<Integer> sWindow2 = new ArrayList<>();
    private static List<Integer> sWindow3 = new ArrayList<>();
    private static List<Integer> sWindow4 = new ArrayList<>();

    private static int sTicketNumber;

    /**
     * 模擬賣票
     * @param tickets:票的總數(shù)
     */
    public static void sell(int tickets) {
        sTicketNumber = tickets;
        sWindow1.clear();
        sWindow2.clear();
        sWindow3.clear();
        sWindow4.clear();
        new MyThread("窗口1").start();
        new MyThread("窗口2").start();
        new MyThread("窗口3").start();
        new MyThread("窗口4").start();
    }

    static class MyThread extends Thread {

        public MyThread(String name) {
            super(name);
        }

        @Override
        public void run() {
            while (true) {
                synchronized ("aaa") {
                    if (sTicketNumber > 0) {
                        String name = Thread.currentThread().getName();
                        if ("窗口1".equals(name)) {
                            sWindow1.add(sTicketNumber);
                        } else if ("窗口2".equals(name)) {
                            sWindow2.add(sTicketNumber);
                        } else if ("窗口3".equals(name)) {
                            sWindow3.add(sTicketNumber);
                        } else if ("窗口4".equals(name)) {
                            sWindow4.add(sTicketNumber);
                        }
                        sTicketNumber--;
                        if (sTicketNumber <= 0) {
                            Log.d(TAG, "run: 窗口1賣票數(shù)量 = " + sWindow1.size());
                            Log.d(TAG, "run: 窗口2賣票數(shù)量 = " + sWindow2.size());
                            Log.d(TAG, "run: 窗口3賣票數(shù)量 = " + sWindow3.size());
                            Log.d(TAG, "run: 窗口4賣票數(shù)量 = " + sWindow4.size());
                        }
                    } else {
                        break;
                    }
                }
            }
        }
    }
}
//調(diào)用情況:驗(yàn)證了synchronized 鎖的不平衡性摩泪。
SellTicket.sell(10);
10-21 00:34:00.677 13740-13766/com.learn.study D/SellTicket: run: 窗口1賣票數(shù)量 = 10
    run: 窗口2賣票數(shù)量 = 0
    run: 窗口3賣票數(shù)量 = 0
    run: 窗口4賣票數(shù)量 = 0
SellTicket.sell(100);
10-21 00:41:39.549 16601-16638/com.learn.study D/SellTicket: run: 窗口1賣票數(shù)量 = 11
    run: 窗口2賣票數(shù)量 = 80
    run: 窗口3賣票數(shù)量 = 9
10-21 00:41:39.550 16601-16638/com.learn.study D/SellTicket: run: 窗口4賣票數(shù)量 = 0
SellTicket.sell(1000);
10-21 00:42:23.104 16851-16878/? D/SellTicket: run: 窗口1賣票數(shù)量 = 312
    run: 窗口2賣票數(shù)量 = 255
    run: 窗口3賣票數(shù)量 = 0
    run: 窗口4賣票數(shù)量 = 433
SellTicket.sell(10000);
10-21 00:43:06.227 17176-17219/com.learn.study D/SellTicket: run: 窗口1賣票數(shù)量 = 1777
    run: 窗口2賣票數(shù)量 = 2774
    run: 窗口3賣票數(shù)量 = 1851
    run: 窗口4賣票數(shù)量 = 3598
//模擬死鎖
public class DeadLock {

    private static final String TAG = "DeadLock";

    public static void deadLock() {
        new MyThread("線程1","aa","bb").start();
        new MyThread("線程2","bb","aa").start();
    }

    static class MyThread extends Thread {

        private String mLock1;
        private String mLock2;
        private int total = 100;

        public MyThread(String name, String lock1, String lock2) {
            super(name);
            mLock1 = lock1;
            mLock2 = lock2;
        }

        @Override
        public void run() {
            while (total > 0) {
                synchronized (mLock1) {
                    Log.d(TAG, "run: " + Thread.currentThread().getName() + " ;; 等待獲取 : " + mLock2 + " ;; total = " + total);
                    synchronized (mLock2) {
                        Log.d(TAG, "run: " + Thread.currentThread().getName() + " ;; 等待獲取 : " + mLock1 + " ;; total = " + total);
                        total--;
                    }
                }
            }
        }
    }
}
DeadLock.deadLock();
//打印結(jié)果(發(fā)現(xiàn)線程1與線程2都在等待獲取對(duì)方持有的鎖對(duì)象,造成互鎖)
10-21 00:58:04.536 19486-19589/com.learn.study D/DeadLock: run: 線程1 ;; 等待獲取 : bb ;; total = 100
    run: 線程1 ;; 等待獲取 : aa ;; total = 100
    run: 線程1 ;; 等待獲取 : bb ;; total = 99
10-21 00:58:04.536 19486-19593/com.learn.study D/DeadLock: run: 線程2 ;; 等待獲取 : aa ;; total = 100

線程池

1忍啤,優(yōu)點(diǎn):

1加勤,復(fù)用線程池中的線程,避免因?yàn)榫€程的創(chuàng)建于銷毀帶來性能的消耗同波。
2,能有效的控制線程池的最大并發(fā)數(shù)叠国,避免大量的線程之間因相互搶占系統(tǒng)資源而導(dǎo)致阻塞現(xiàn)象
3未檩,能夠?qū)€程進(jìn)行簡單的管理,并提供定時(shí)執(zhí)行以及指定間隔循環(huán)執(zhí)行的任務(wù)粟焊。

2冤狡,創(chuàng)建:利用ThreadPoolExecutor的構(gòu)造方法創(chuàng)建線程池

new ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
參數(shù)說明如下:
1,corePoolSize:核心線程數(shù)项棠,默認(rèn)情況下核心線程會(huì)一直存活悲雳,即使處于閑置狀態(tài)也不會(huì)受存keepAliveTime限制。除非將allowCoreThreadTimeOut設(shè)置為true香追。
2合瓢,maximumPoolSize:線程池所能容納的最大線程數(shù)。超過這個(gè)數(shù)的線程將被阻塞透典。當(dāng)任務(wù)隊(duì)列為沒有設(shè)置大小的LinkedBlockingDeque時(shí)晴楔,這個(gè)值無效。
3峭咒,keepAliveTime:非核心線程的閑置超時(shí)時(shí)間税弃,超過這個(gè)時(shí)間就會(huì)被回收。
4凑队,unit:指定keepAliveTime的單位则果,TimeUnit是一個(gè)時(shí)間單位的枚舉類。當(dāng)allowCoreThreadTimeOut設(shè)置為true時(shí)對(duì)corePoolSize生效。
5西壮,workQueue:線程池中的任務(wù)隊(duì)列导匣,通過execute()提交的Runnable任務(wù)會(huì)存儲(chǔ)在該隊(duì)列中,然后根據(jù)對(duì)應(yīng)的規(guī)則進(jìn)行執(zhí)行茸时。
6贡定,threadFactory:線程工廠,提供創(chuàng)建新線程的功能可都。ThreadFactory是一個(gè)接口缓待,只有一個(gè)方法Thread newThread(Runnable r)(一般使用系統(tǒng)默認(rèn))
7,handler:當(dāng)線程池中的資源已經(jīng)全部使用渠牲,添加新線程被拒絕時(shí)旋炒,會(huì)調(diào)用RejectedExecutionHandler的rejectedExecution方法,拋出異常提示签杈。(一般使用系統(tǒng)默認(rèn))

3瘫镇,任務(wù)執(zhí)行的規(guī)則:

1,線程數(shù)量<核心線程數(shù)量答姥,那么直接啟動(dòng)一個(gè)核心線程來執(zhí)行任務(wù)铣除,不會(huì)放入隊(duì)列中。
2鹦付,線程數(shù)量>=核心線程數(shù)尚粘,但<最大線程數(shù)。當(dāng)任務(wù)隊(duì)列是LinkedBlockingDeque敲长,超過核心線程數(shù)量的任務(wù)會(huì)放在任務(wù)隊(duì)列中排隊(duì)(只會(huì)啟動(dòng)核心數(shù)量的線程)郎嫁;當(dāng)任務(wù)隊(duì)列為SynchronousQueue,線程池會(huì)創(chuàng)建新線程執(zhí)行任務(wù)祈噪,這些任務(wù)也不會(huì)被放在任務(wù)隊(duì)列中泽铛。這些線程屬于非核心線程,在任務(wù)完成后辑鲤,閑置時(shí)間達(dá)到了超時(shí)時(shí)間就會(huì)被清除盔腔。
3,如果線程數(shù)量>核心線程數(shù)遂填,并且>最大線程數(shù)铲觉。當(dāng)任務(wù)隊(duì)列為LinkedBlockingDeque,會(huì)將超過核心線程的任務(wù)放在任務(wù)隊(duì)列中排隊(duì)吓坚。此時(shí)線程池的最大線程數(shù)設(shè)置是無效的撵幽,他的線程數(shù)最多不會(huì)超過核心線程數(shù)。當(dāng)任務(wù)隊(duì)列為SynchronousQueue的時(shí)候礁击,會(huì)因?yàn)榫€程池拒絕添加任務(wù)而拋出異常盐杂。

4逗载,四種常見的線程池:利用Executors的工廠模式創(chuàng)建

1,FixedThreadPool :通過方法newFixedThreadPool()創(chuàng)建链烈,是線程數(shù)量固定的線程池厉斟。只有核心線程數(shù)并且不會(huì)被回收。
2强衡,CachedThreadPool:通過方法newCachedThreadPool()創(chuàng)建擦秽,沒有固定線程池,線程大小無限制漩勤,適合執(zhí)行大量的耗時(shí)少的任務(wù)感挥。
3,ScheduledThreadPool:通過方法newScheduledThreadPool()創(chuàng)建越败,核心線程數(shù)固定触幼,非核心線程數(shù)沒有限制。適合執(zhí)行定時(shí)任務(wù)和固定周期的重復(fù)任務(wù)究飞。
4置谦,SingleThreadExecutor:通過方法newSingleThreadExecutor()創(chuàng)建,內(nèi)部只有一個(gè)核心線程數(shù)亿傅,適合執(zhí)行串行的任務(wù)媒峡,可以不用考慮同步問題。

實(shí)際開發(fā)中建議使用ThreadPoolExecutor創(chuàng)建線程池,而不是采用Executors默認(rèn)的四種袱蜡。其中FixedThreadPool與SingleThreadExecutor丝蹭,在任務(wù)過度時(shí)會(huì)出現(xiàn)OOM,CachedThreadPool坪蚁,ScheduledThreadPool在任務(wù)過多時(shí)會(huì)大量創(chuàng)建線程,造成OOM

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镜沽,一起剝皮案震驚了整個(gè)濱河市敏晤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缅茉,老刑警劉巖嘴脾,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蔬墩,居然都是意外死亡译打,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門拇颅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奏司,“玉大人,你說我怎么就攤上這事樟插≡涎螅” “怎么了竿刁?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長搪缨。 經(jīng)常有香客問我食拜,道長,這世上最難降的妖魔是什么副编? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任负甸,我火速辦了婚禮,結(jié)果婚禮上痹届,老公的妹妹穿的比我還像新娘呻待。我一直安慰自己,他們只是感情好短纵,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布带污。 她就那樣靜靜地躺著,像睡著了一般香到。 火紅的嫁衣襯著肌膚如雪鱼冀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天悠就,我揣著相機(jī)與錄音千绪,去河邊找鬼。 笑死梗脾,一個(gè)胖子當(dāng)著我的面吹牛荸型,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播炸茧,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瑞妇,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了梭冠?” 一聲冷哼從身側(cè)響起辕狰,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎控漠,沒想到半個(gè)月后蔓倍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡盐捷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年偶翅,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片碉渡。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡聚谁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爆价,到底是詐尸還是另有隱情垦巴,我是刑警寧澤媳搪,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站骤宣,受9級(jí)特大地震影響秦爆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜憔披,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一等限、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧芬膝,春花似錦望门、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至癣缅,卻和暖如春厨剪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背友存。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工祷膳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屡立。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓直晨,卻偏偏與公主長得像,于是被迫代替她去往敵國和親膨俐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子勇皇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

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

  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書筆記,整理的知識(shí)點(diǎn)焚刺,也是為了防止忘記儒士,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦檩坚!如果你也喜歡,那...
    波波波先森閱讀 11,263評(píng)論 4 56
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 29,386評(píng)論 8 265
  • 從哪說起呢诅福? 單純講多線程編程真的不知道從哪下嘴匾委。。 不如我直接引用一個(gè)最簡單的問題氓润,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,757評(píng)論 1 17
  • 今天早上體重又回來了赂乐,昨天晚飯吃半條魚,有點(diǎn)撐咖气,快走40分鐘挨措,又跳操40分鐘挖滤,還好,下來了浅役,有點(diǎn)沾沾自喜斩松。 早上去...
    影子3623253閱讀 100評(píng)論 0 1
  • 午后的空氣很干凈。晨起的雷雨粉墨登場之后觉既,濕氣方興未艾惧盹。陽光散進(jìn)一片闊葉林,掛在葉尖上的雨滴折射出小小的一道彩虹瞪讼。...
    陟卓閱讀 300評(píng)論 0 0