線程Thread

目錄

概念

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

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

線程的創(chuàng)建

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

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

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

class MyRunnable implements Runnable {
        @Override
        public void run() {
            //執(zhí)行線程操作
        }
    }
開啟線程(一般采用這種方案,既能保證Thread 的擴(kuò)展,同時Runnable對象也可以作為任務(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;
    }
});
//這種方式針對需要獲取返回值的線程開啟
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)建后尚未啟動的線程處于這種狀態(tài)。
2,運行(Runable):Runable包括了操作系統(tǒng)線程狀態(tài)中的Running和Ready,也就是處于此狀態(tài)的線程有可能正在執(zhí)行,也有可能正在等待著CPU為它分配執(zhí)行時間。
3,無限期等待(Waiting):處于這種狀態(tài)的線程不會被分配CPU執(zhí)行時間,它們要等待被其他線程顯式地喚醒。

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

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

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

以下方法會讓線程進(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)”在等待著獲取到一個排他鎖,這個事件將在另外一個線程放棄這個鎖的時候發(fā)生;而“等待狀態(tài)”則是在等待一段時間,或者喚醒動作的發(fā)生。 在程序等待進(jìn)入同步區(qū)域的時候,線程將進(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()的線程不會釋放對象鎖;wait()會釋放對象鎖進(jìn)入等待狀態(tài),使得其他線程能使用同步代碼塊或同步方法

多線程

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

2,線程安全:當(dāng)多個線程訪問一個對象時,如果不用考慮這些線程在運行時環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,調(diào)用這個對象的行為都可以獲得正確的結(jié)果,那這個對象是線程安全的?;咎攸c如下:

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

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

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

ThreadLocal:線程內(nèi)部的數(shù)據(jù)存儲類,可以在指定的線程內(nèi)存儲數(shù)據(jù),通過泛型來聲明數(shù)據(jù)類型。變量的作用域為當(dāng)前的線程。最典型的使用是在線程中獲取Loop對象時,采用的就是ThreadLocal來進(jìn)行存取。提供三個方法:
set()用于存儲數(shù)據(jù),
get()用于獲取數(shù)據(jù),
remove()用于手動釋放存儲的變量,
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í)行時間由線程本身來控制,線程把自己的工作執(zhí)行完了之后,要主動通知系統(tǒng)切換到另外一個線程上。 好處:實現(xiàn)簡單,而且由于線程要把自己的事情干完后才會進(jìn)行線程切換,切換操作對線程自己是可知的,所以沒有什么線程同步的問題。壞處:線程執(zhí)行時間不可控制,甚至如果一個線程編寫有問題,一直不告知系統(tǒng)進(jìn)行線程切換,那么程序就會一直阻塞在那里。
2,搶占式調(diào)度:每個線程將由系統(tǒng)來分配執(zhí)行時間,線程的切換不由線程本身來決定(在Java中,Thread.yield()可以讓出執(zhí)行時間,但是要獲取執(zhí)行時間的話,線程本身是沒有什么辦法的)。 在這種實現(xiàn)線程調(diào)度的方式下,線程的執(zhí)行時間是系統(tǒng)可控的,也不會有一個線程導(dǎo)致整個進(jìn)程阻塞的問題。但線程優(yōu)先級并不是太靠譜。
Java使用的線程調(diào)度方式就是搶占式調(diào)度

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

1,自旋鎖:競爭鎖失敗的線程,并不會真實的在操作系統(tǒng)層面掛起等待,而是JVM會讓線程做幾個空循環(huán)(基于預(yù)測在不久的將來就能獲得),在經(jīng)過若干次循環(huán)后,如果可以獲得鎖,那么進(jìn)入臨界區(qū),如果還不能獲得鎖,才會真實的將線程在操作系統(tǒng)層面進(jìn)行掛起。
適用場景:自旋鎖可以減少線程的阻塞,這對于鎖競爭不激烈,且占用鎖時間非常短的代碼塊來說,有較大的性能提升,因為自旋的消耗會小于線程阻塞掛起操作的消耗。如果鎖的競爭激烈,或者持有鎖的線程需要長時間占用鎖執(zhí)行同步塊,就不適合使用自旋鎖了,因為自旋鎖在獲取鎖前一直都是占用cpu做無用功,線程自旋的消耗大于線程阻塞掛起操作的消耗,造成cpu的浪費。
2,鎖消除:虛擬機(jī)中編譯器在運行時,對一些代碼上要求同步,但是被檢測到不可能存在共享數(shù)據(jù)競爭的鎖進(jìn)行消除。鎖消除的主要判定依據(jù)來源于逃逸分析的數(shù)據(jù)支持,如果判斷在一段代碼中,堆上的所有數(shù)據(jù)都不會逃逸出去從而被其他線程訪問到,那就可以把它們當(dāng)做棧上數(shù)據(jù)對待,認(rèn)為它們是線程私有的,同步加鎖自然就無須進(jìn)行。
3,鎖粗化:一般情況下,推薦將同步塊的作用范圍限制到只在共享數(shù)據(jù)的實際作用域中才進(jìn)行同步,使得需要同步的操作數(shù)量盡可能變小,保證就算存在鎖競爭,等待鎖的線程也能盡快拿到鎖。但如果反復(fù)操作對同一個對象進(jìn)行加鎖和解鎖,即使沒有線程競爭,頻繁地進(jìn)行互斥同步操作也會導(dǎo)致不必要的性能損耗,此時,虛擬機(jī)將會把加鎖同步的范圍粗化到整個操作序列的外部,這樣只需加一次鎖。
4,輕量級鎖:并不是用來代替重量級鎖的,它的本意是在沒有多線程競爭的前提下,減少傳統(tǒng)的重量級鎖使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗。
5,偏向鎖:目的是消除數(shù)據(jù)在無競爭情況下的同步原語,進(jìn)一步提高程序的運行性能。 如果說輕量級鎖是在無競爭的情況下使用CAS操作去消除同步使用的互斥量,那偏向鎖就是在無競爭的情況下把整個同步都消除掉,連CAS操作都不做了。偏向鎖可以提高帶有同步但無競爭的程序性能。 它同樣是一個帶有效益權(quán)衡(TradeOff)性質(zhì)的優(yōu)化,也就是說,它并不一定總是對程序運行有利,如果程序中大多數(shù)的鎖總是被多個不同的線程訪問,那偏向模式就是多余的。

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

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

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

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

補充:鎖的是對象而不是方法,同時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í)行時插入了第三條線程的內(nèi)容,但包含相同鎖對象進(jìn)行互斥的代碼塊必須相互獨立的一次執(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,常見案例:

//模擬四個窗口賣票
public class SellTicket {

    private static final String TAG = "SellTicket";

    //用于統(tǒng)計四個窗口賣的票
    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)用情況:驗證了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都在等待獲取對方持有的鎖對象,造成互鎖)
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)點:

1,復(fù)用線程池中的線程,避免因為線程的創(chuàng)建于銷毀帶來性能的消耗。
2,能有效的控制線程池的最大并發(fā)數(shù),避免大量的線程之間因相互搶占系統(tǒng)資源而導(dǎo)致阻塞現(xiàn)象
3,能夠?qū)€程進(jìn)行簡單的管理,并提供定時執(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)情況下核心線程會一直存活,即使處于閑置狀態(tài)也不會受存keepAliveTime限制。除非將allowCoreThreadTimeOut設(shè)置為true。
2,maximumPoolSize:線程池所能容納的最大線程數(shù)。超過這個數(shù)的線程將被阻塞。當(dāng)任務(wù)隊列為沒有設(shè)置大小的LinkedBlockingDeque時,這個值無效。
3,keepAliveTime:非核心線程的閑置超時時間,超過這個時間就會被回收。
4,unit:指定keepAliveTime的單位,TimeUnit是一個時間單位的枚舉類。當(dāng)allowCoreThreadTimeOut設(shè)置為true時對corePoolSize生效。
5,workQueue:線程池中的任務(wù)隊列,通過execute()提交的Runnable任務(wù)會存儲在該隊列中,然后根據(jù)對應(yīng)的規(guī)則進(jìn)行執(zhí)行。
6,threadFactory:線程工廠,提供創(chuàng)建新線程的功能。ThreadFactory是一個接口,只有一個方法Thread newThread(Runnable r)(一般使用系統(tǒng)默認(rèn))
7,handler:當(dāng)線程池中的資源已經(jīng)全部使用,添加新線程被拒絕時,會調(diào)用RejectedExecutionHandler的rejectedExecution方法,拋出異常提示。(一般使用系統(tǒng)默認(rèn))

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

1,線程數(shù)量<核心線程數(shù)量,那么直接啟動一個核心線程來執(zhí)行任務(wù),不會放入隊列中。
2,線程數(shù)量>=核心線程數(shù),但<最大線程數(shù)。當(dāng)任務(wù)隊列是LinkedBlockingDeque,超過核心線程數(shù)量的任務(wù)會放在任務(wù)隊列中排隊(只會啟動核心數(shù)量的線程);當(dāng)任務(wù)隊列為SynchronousQueue,線程池會創(chuàng)建新線程執(zhí)行任務(wù),這些任務(wù)也不會被放在任務(wù)隊列中。這些線程屬于非核心線程,在任務(wù)完成后,閑置時間達(dá)到了超時時間就會被清除。
3,如果線程數(shù)量>核心線程數(shù),并且>最大線程數(shù)。當(dāng)任務(wù)隊列為LinkedBlockingDeque,會將超過核心線程的任務(wù)放在任務(wù)隊列中排隊。此時線程池的最大線程數(shù)設(shè)置是無效的,他的線程數(shù)最多不會超過核心線程數(shù)。當(dāng)任務(wù)隊列為SynchronousQueue的時候,會因為線程池拒絕添加任務(wù)而拋出異常。

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

1,FixedThreadPool :通過方法newFixedThreadPool()創(chuàng)建,是線程數(shù)量固定的線程池。只有核心線程數(shù)并且不會被回收。
2,CachedThreadPool:通過方法newCachedThreadPool()創(chuàng)建,沒有固定線程池,線程大小無限制,適合執(zhí)行大量的耗時少的任務(wù)。
3,ScheduledThreadPool:通過方法newScheduledThreadPool()創(chuàng)建,核心線程數(shù)固定,非核心線程數(shù)沒有限制。適合執(zhí)行定時任務(wù)和固定周期的重復(fù)任務(wù)。
4,SingleThreadExecutor:通過方法newSingleThreadExecutor()創(chuàng)建,內(nèi)部只有一個核心線程數(shù),適合執(zhí)行串行的任務(wù),可以不用考慮同步問題。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容