亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

每日六道java新手入門面試題,通往自由的道路--線程池

 更新時間:2021年07月01日 09:44:49   作者:太子爺哪吒  
這篇文章主要為大家分享了最有價值的6道線程池面試題,涵蓋內(nèi)容全面,包括數(shù)據(jù)結(jié)構(gòu)和算法相關(guān)的題目、經(jīng)典面試編程題等,對hashCode方法的設(shè)計、垃圾收集的堆和代進行剖析,感興趣的小伙伴們可以參考一下

1. 你知道線程池嗎?為什么需要使用線程池?

在面向?qū)ο缶幊讨?,?chuàng)建和銷毀對象是很費時間的,因為創(chuàng)建一個對象要獲取內(nèi)存資源或者其它更多資源。

而在Java中, JVM 中每創(chuàng)建和銷毀線程就需要資源和時間的損耗了,線程中也是存在上下文切換,這需要一定的開銷,并且線程的創(chuàng)建并不是越多越好,而如果創(chuàng)建的線程數(shù)太多,上下文切換的頻率就變高,可能使得多線程帶來的好處抵不過線程切換帶來的開銷,就有點得不償失了。

那我們需要如何管控好線程呢?

所以我們可以創(chuàng)建一個容器把線程數(shù)緩存在容器了,以便給他人使用,并且無需再自行創(chuàng)建和銷毀線程。

小結(jié):

線程池就是事先創(chuàng)建若干個可執(zhí)行的線程放入一個池(容器)中,需要的時候從池中獲取線程不用自行創(chuàng)建,使用完畢不需要銷毀線程而是放回池中,從而減少創(chuàng)建和銷毀。

使用線程池的好處

  • 降低了資源的消耗,重用存在的線程,減少線程的創(chuàng)建和銷毀的資源損耗。
  • 提高了響應(yīng)速度,無需等待創(chuàng)建和銷毀的時間,一旦任務(wù)到達的時候,即可通過線程池的線程執(zhí)行。
  • 提高了線程的管控性,線程是稀缺的資源,如果無限創(chuàng)建,不僅會消耗系統(tǒng)資源,還會降低系統(tǒng)的穩(wěn)定性,使用線程池可以進行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。

2. 你知道有多少種創(chuàng)建線程池的方式

JDK1.5以后提供一個Executors工具類 ,里面提供一些靜態(tài)工廠方法,生成一些常用的線程池。

newCachedThreadPool:創(chuàng)建一個可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當任務(wù)數(shù)增加時,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的最大線程大小。

那我們來看看底層的方法和實現(xiàn)過程:

底層:

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

我們實現(xiàn)的步驟:

public class ThreadPoolDemo {
    public static void main(String[] args) {
        threadPoolTest();
    }
    private static void threadPoolTest() {
        // 1. 使用工廠類獲取線程池對象
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 2. 提交任務(wù)
        for (int i = 1; i < 8; i++) {
            executorService.submit(new MyRunnable(i));
        }
    }
}
// 我們的任務(wù)類
class MyRunnable implements Runnable {
    private int id;
    public MyRunnable(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        // 打印是哪個線程的名稱。
        System.out.println(Thread.currentThread().getName() + "執(zhí)行了任務(wù)" + id);
    }
}

可以得到的結(jié)果:

可以發(fā)現(xiàn),線程池的開啟是一直運行的狀態(tài),而如果你想結(jié)束的話,可以使用一個shutdown方法即 executorService.shutdown(); 每次任務(wù)都會創(chuàng)建多一個線程出來了。

我們可以看下newCacheThreadPool的運行流程如下:

  • 提交任務(wù)進線程池。
  • 因為corePoolSize為0的關(guān)系,不創(chuàng)建核心線程,線程池最大為Integer.MAX_VALUE。
  • 嘗試將任務(wù)添加到SynchronousQueue隊列。
  • 如果SynchronousQueue入列成功,等待被當前運行的線程空閑后拉取執(zhí)行。如果當前沒有空閑線程,那么就創(chuàng)建一個非核心線程,然后從SynchronousQueue拉取任務(wù)并在當前線程執(zhí)行。
  • 如果SynchronousQueue已有任務(wù)在等待,入列操作將會阻塞。

當需要執(zhí)行很多短時間的任務(wù)時,newCacheThreadPool的線程復(fù)用率比較高, 會顯著的提高性能。而且線程60s后會回收,意味著即使沒有任務(wù)進來,newCacheThreadPool并不會占用很多資源。

newFixedThreadPool:創(chuàng)建固定大小的線程池。每次提交一個任務(wù)就創(chuàng)建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因為執(zhí)行異常而結(jié)束,那么線程池會補充一個新線程。

還是一樣看下底層和代碼實現(xiàn)過程吧:

底層:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

代碼實現(xiàn)過程:

public static void main(String[] args) {
    // threadPoolTest();
    threadPoolTest2();
}
private static void threadPoolTest2() {
    // 1. 使用工廠類獲取線程池對象
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    // 2. 提交任務(wù)
    for (int i = 1; i < 8; i++) {
        executorService.submit(new MyRunnable(i));
    }
}

得到的結(jié)果:

pool-1-thread-2執(zhí)行了任務(wù)2
pool-1-thread-1執(zhí)行了任務(wù)1
pool-1-thread-3執(zhí)行了任務(wù)3
pool-1-thread-3執(zhí)行了任務(wù)6
pool-1-thread-1執(zhí)行了任務(wù)5
pool-1-thread-2執(zhí)行了任務(wù)4
pool-1-thread-3執(zhí)行了任務(wù)7

我們可以發(fā)現(xiàn),創(chuàng)建線程數(shù)量就是我們指定3,核心線程數(shù)量和總線程數(shù)量相等,都是傳入的參數(shù)nThreads,所以只能創(chuàng)建核心線程,不能創(chuàng)建非核心線程。因為LinkedBlockingQueue的默認大小是Integer.MAX_VALUE,故如果核心線程空閑,則交給核心線程處理;如果核心線程不空閑,則入列等待,直到核心線程空閑。

與newCacheThreadPool的區(qū)別

  • 因為 corePoolSize == maximumPoolSize ,所以FixedThreadPool只會創(chuàng)建核心線程。 而CachedThreadPool因為corePoolSize=0,所以只會創(chuàng)建非核心線程。
  • 在 getTask() 方法,如果隊列里沒有任務(wù)可取,線程會一直阻塞在 LinkedBlockingQueue.take() ,線程不會被回收。 CachedThreadPool會在60s后收回。
  • 由于線程不會被回收,會一直卡在阻塞,所以沒有任務(wù)的情況下, FixedThreadPool占用資源更多
  • 都幾乎不會觸發(fā)拒絕策略,但是原理不同。FixedThreadPool是因為阻塞隊列可以很大(最大為Integer最大值),故幾乎不會觸發(fā)拒絕策略;CachedThreadPool是因為線程池很大(最大為Integer最大值),幾乎不會導(dǎo)致線程數(shù)量大于最大線程數(shù),故幾乎不會觸發(fā)拒絕策略。

​newSingleThreadExecutor:創(chuàng)建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當于單線程串行執(zhí)行所有任務(wù)。如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它。此線程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行

還是一樣看下底層和代碼實現(xiàn)過程吧:

底層

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

代碼實現(xiàn)過程

public static void main(String[] args) {
    // threadPoolTest();
    // threadPoolTest2();
    threadPoolTest3();
}
private static void threadPoolTest3() {
    // 1. 使用工廠類獲取線程池對象
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    // 2. 提交任務(wù)
    for (int i = 1; i < 8; i++) {
        executorService.submit(new MyRunnable(i));
    }
}

得到的結(jié)果:

pool-1-thread-1執(zhí)行了任務(wù)1
pool-1-thread-1執(zhí)行了任務(wù)2
pool-1-thread-1執(zhí)行了任務(wù)3
pool-1-thread-1執(zhí)行了任務(wù)4
pool-1-thread-1執(zhí)行了任務(wù)5
pool-1-thread-1執(zhí)行了任務(wù)6
pool-1-thread-1執(zhí)行了任務(wù)7

可以發(fā)現(xiàn),只創(chuàng)建了一個線程,有且僅有一個核心線程( corePoolSize == maximumPoolSize=1),使用了LinkedBlockingQueue(容量很大),所以,不會創(chuàng)建非核心線程。所有任務(wù)按照先來先執(zhí)行的順序執(zhí)行。如果這個唯一的線程不空閑,那么新來的任務(wù)會存儲在任務(wù)隊列里等待執(zhí)行。

newScheduledThreadpool:創(chuàng)建一個大小無限的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。

還是一樣看下底層和代碼實現(xiàn)過程吧:

底層

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
}

代碼實現(xiàn)

public static void main(String[] args) {
    //        threadPoolTest();
    //        threadPoolTest2();
    //        threadPoolTest3();
    threadPoolTest4();
}
private static void threadPoolTest4() {
    // 1. 使用工廠類獲取線程池對象
    ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
    // 2. 每個任務(wù)延遲兩秒執(zhí)行
    for (int i = 1; i < 8; i++) {
        scheduledExecutorService.schedule(new MyRunnable(i), 2, TimeUnit.SECONDS);
    }
    System.out.println("看是不是我先執(zhí)行了!");
}

可以看到的結(jié)果:

看是不是我先執(zhí)行了!
pool-1-thread-1執(zhí)行了任務(wù)1
pool-1-thread-1執(zhí)行了任務(wù)4
pool-1-thread-2執(zhí)行了任務(wù)2
pool-1-thread-3執(zhí)行了任務(wù)3
pool-1-thread-2執(zhí)行了任務(wù)6
pool-1-thread-1執(zhí)行了任務(wù)5
pool-1-thread-3執(zhí)行了任務(wù)7

我們可以發(fā)現(xiàn),線程池只創(chuàng)建我們指定的線程數(shù),并且返回的是一個繼承了ExecutorService的ScheduledExecutorService的接口。它給我們提供一些延遲的方法:

public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
延遲時間單位是unit,時間數(shù)是delay,任務(wù)是Runnable類型的command。
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                        long delay, TimeUnit unit);
而這個方法是上面方法的重載,不一樣的是任務(wù)是Callable類型的

3. 線程池的五種狀態(tài)你有了解嗎?

線程池它有以下五種狀態(tài):

具體有:

  • RUNNING:這是最正常的狀態(tài),能正常接受新的任務(wù),正常處理等待隊列中的任務(wù)。
  • SHUTDOWN:不接受新的任務(wù)提交,但是會繼續(xù)處理正在執(zhí)行的業(yè)務(wù)并且也會處理阻塞隊列中的任務(wù)。
  • STOP:不接受新的任務(wù)提交,不再處理等待隊列中的任務(wù),并且中斷正在執(zhí)行任務(wù)的線程。
  • TIDYING:所有的任務(wù)都執(zhí)行完畢或銷毀了,當前活動線程數(shù)為 0,線程池的狀態(tài)在轉(zhuǎn)換為 TIDYING 狀態(tài)時,會執(zhí)行鉤子方法 terminated()進入終止狀態(tài)。
  • TERMINATED:線程池徹底終止,即terminated()方法結(jié)束后,線程池的狀態(tài)就會變成這個。

4. 你知道ThreadPoolExecutor的構(gòu)造方法和參數(shù)嗎

我們先來看看它的構(gòu)造方法有哪些:

// 五個參數(shù)的構(gòu)造函數(shù)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {...}
// 六個參數(shù)的構(gòu)造函數(shù)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {...}
// 六個參數(shù)的構(gòu)造函數(shù)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler) {...}
// 七個參數(shù)的構(gòu)造函數(shù)
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {...}

我們再來詳解下構(gòu)造方法中涉及的7個參數(shù),其中最重要5個參數(shù)就是第一個構(gòu)造方法中的。

  • int corePoolSize:該線程池中核心線程數(shù)量

核心線程:線程池中有兩類線程,核心線程和非核心線程。核心線程默認情況下會一直存在于線程池中,即使這個核心線程什么都不干,而非核心線程(臨時工)如果長時間的閑置,就會被銷毀。但是如果將

allowCoreThreadTimeOut設(shè)置為true時,核心線程也是會被超時回收。

  • int maximumPoolSize:該線程池中允許存在的工作線程的最大數(shù)量。

該值相當于核心線程數(shù)量 + 非核心線程數(shù)量。

  • long keepAliveTime:非核心線程閑置超時時長。

非核心線程如果處于閑置狀態(tài)超過該值,就會被銷毀。如果設(shè)置allowCoreThreadTimeOut(true),則會也作用于核心線程。

  • TimeUnit unit:keepAliveTime的時間單位。

TimeUnit是一個枚舉類型 ,包括以下屬性:

 NANOSECONDS : 1微毫秒
MICROSECONDS : 1微秒
MILLISECONDS : 1毫秒
SECONDS : 秒
MINUTES : 分
HOURS : 小時
DAYS : 天

  • BlockingQueue workQueue:阻塞隊列,維護著等待執(zhí)行的Runnable任務(wù)對象。

當新任務(wù)來的時候,會先判斷當前運行線程數(shù)量是否達到了核心線程數(shù),如果達到了,就會被存放在阻塞隊列中排隊等待執(zhí)行。

常用的幾個阻塞隊列:

1.ArrayBlockingQueue

數(shù)組阻塞隊列,底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,需要指定隊列的大小。

2.SynchronousQueue

同步隊列,內(nèi)部容量為0,每個put操作必須等待一個take操作,反之亦然。

3.DelayQueue

延遲隊列,該隊列中的元素只有當其指定的延遲時間到了,才能夠從隊列中獲取到該元素 。

4.LinkedBlockingQueue

鏈式阻塞隊列,底層數(shù)據(jù)結(jié)構(gòu)是鏈表,默認大小是Integer.MAX_VALUE,也可以指定大小。

還有兩個非必須的參數(shù):

  • ThreadFactory threadFactory

創(chuàng)建線程的工廠 ,用于批量創(chuàng)建線程,統(tǒng)一在創(chuàng)建線程時設(shè)置一些參數(shù),如是否守護線程、線程的優(yōu)先級等。如果不指定,會新建一個默認的線程工廠。

  • RejectedExecutionHandler handler

拒絕處理策略,在線程數(shù)量大于最大線程數(shù)后就會采用拒絕處理策略,四種拒絕處理的策略為 :

  • ThreadPoolExecutor.AbortPolicy默認拒絕處理策略,丟棄任務(wù)并拋出RejectedExecutionException異常。
  • ThreadPoolExecutor.DiscardPolicy:丟棄新來的任務(wù),但是不拋出異常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列頭部(最舊的)的任務(wù),然后重新嘗試執(zhí)行程序(如果再次失敗,重復(fù)此過程)。
  • ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。

5. 你可以說下線程池的執(zhí)行過程原理嗎

昨天MyGirl跟我講了一下她去銀行辦理業(yè)務(wù)的一個場景:

  1. 首先MyGirl(任務(wù)A)先去銀行(線程池)辦理業(yè)務(wù),她發(fā)現(xiàn)她來早了,現(xiàn)在銀行才剛開門,柜臺窗口服務(wù)員還沒過來(相當于線程池中的初始線程為0),此時銀行經(jīng)理看到MyGirl來了,就安排她去一號柜臺窗口并安排了1號正式工作人員來接待她。
  2. 在MyGirl的業(yè)務(wù)還沒辦完時,一個不知名的路人甲(任務(wù)B)出現(xiàn)了,他也是要來銀行辦業(yè)務(wù),于是銀行經(jīng)理安排他去二號柜臺并安排了2號正式工作人員。假設(shè)該銀行的柜臺窗口就只有兩個(核心線程數(shù)量2)。
  3. 緊接著,在所有人業(yè)務(wù)都還沒做完的情況,持續(xù)來個三個不知名的路人乙丙丁,他們也是要來辦業(yè)務(wù)的,但是由于柜臺滿了,安排了他們?nèi)ヅ赃叺你y行大廳的座位上(阻塞隊列,這里假設(shè)大小為3)等候并給了對應(yīng)順序的號碼,說等前面兩個人辦理完后,按順序叫號你們呦,請注意聽。
  4. 過一會,一個路人戊也想來銀行辦理業(yè)務(wù),而經(jīng)理看到柜臺滿了,座位滿了,只能安排了一個臨時工(非核心線程,這里假設(shè)最大線程為3,即非核心為1)手持pad設(shè)備并給路人戊去辦理業(yè)務(wù)。
  5. 而此時,一個路人戌過來辦理業(yè)務(wù),而經(jīng)理看到柜臺滿了,座位滿了,臨時工也安排滿了(最大線程數(shù)+阻塞隊列都滿了),無奈經(jīng)理只能掏出一本《如何接待超出最大限度的手冊》,選擇拒接接待路人戌通知他,過會再來吧您嘞,這里已經(jīng)超負荷啦!
  6. 最后,相繼所有人的業(yè)務(wù)都辦完了,現(xiàn)在也沒人再來辦業(yè)務(wù),并且臨時工的空閑時間也超過了1小時以上了(最大空閑時間默認60秒),經(jīng)理讓臨時工都先下班回家了(銷毀線程)。
  7. 但是一個銀行要保證正常的運行,只能讓正式員工繼續(xù)上班,不得提早下班。

而實際上線程的流程原理跟這個一樣,我們來看下處理任務(wù)的核心方法execute,它的源碼大概是什么樣子的呢,當然我們也可以看源碼中的注釋,里面也寫的很清楚。這里具體講下思路。

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();  
    // 1. 獲取ctl,ctl是記錄著線程池狀態(tài)和線程數(shù)。
    int c = ctl.get();
    // 2. 判斷當前線程數(shù)小于corePoolSize核心線程,則調(diào)用addWorker創(chuàng)建核心線程執(zhí)行任務(wù)
    if (workerCountOf(c) < corePoolSize) {
       if (addWorker(command, true))
           return;
       // 創(chuàng)建線程失敗,需要重新獲取clt的狀態(tài)和線程數(shù)。
       c = ctl.get();
    }
    // 3. 如果不小于corePoolSize,進入下面的方法。
    // 判斷線程池是否運行狀態(tài)并且運行線程數(shù)大于corePoolSize,將任務(wù)添加到workQueue隊列。
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 3.1 再次檢查線程池是否運行狀態(tài)。
        // 如果isRunning返回false(狀態(tài)檢查),則remove這個任務(wù),然后執(zhí)行拒絕策略。
        if (! isRunning(recheck) && remove(command))
            reject(command);
            // 3.2 線程池處于running狀態(tài),但是沒有線程,則創(chuàng)建線程加入到線程池中
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 4. 如果放入workQueue失敗,則創(chuàng)建非核心線程執(zhí)行任務(wù),
    // 如果這時創(chuàng)建非核心線程失敗(當前線程總數(shù)不小于maximumPoolSize時),就會執(zhí)行拒絕策略。
    else if (!addWorker(command, false))
         reject(command);
}

我們可以大概看下思路圖:

先解釋下ctl

變量ctl定義為AtomicInteger,記錄了“線程池中的任務(wù)數(shù)量”和“線程池的狀態(tài)”兩個信息。以高三位記錄著線程池的狀態(tài)和低29位記錄線程池中的任務(wù)數(shù)量。

RUNNING : 111
SHUTDOWN : 000
STOP : 001
TIDYING : 010
TERMINATED : 011

最后總結(jié)一下執(zhí)行過程:

  • 任務(wù)到達時,會先判斷核心線程是否滿了,不滿則調(diào)用addWorker方法創(chuàng)建核心線程執(zhí)行任務(wù)。
  • 然后會判斷下線程池中的線程數(shù) < 核心線程,無論線程是否空閑,都會新建一個核心線程執(zhí)行任務(wù)(讓核心線程數(shù)量快速達到核心線程總數(shù))。此步驟會開啟鎖mainLock.lock();。
  • 而在線程池中的線程數(shù) >= 核心線程時,新來的線程任務(wù)會進入任務(wù)阻塞隊列中等待,然后空閑的核心線程會依次去阻塞隊列中取任務(wù)來執(zhí)行。
  • 當阻塞隊列滿了,說明這個時候任務(wù)很多了,此時就需要一些非核心線程臨時工來執(zhí)行這些任務(wù)了。于是會創(chuàng)建非核心線程去執(zhí)行這個任務(wù)。
  • 最后當阻塞隊列滿了, 且總線程數(shù)達到了maximumPoolSize,則會采取拒絕策略進行處理。
  • 當非核心線程取任務(wù)的時間達到keepAliveTime還沒有取到任務(wù)即空閑時間,就會回收非核心線程。

6. 能否寫一個簡單線程池的demo?

這里還是直接用簡單的ThreadPoolExecutor創(chuàng)建吧,等后續(xù)寫線程池相關(guān)文章,再詳細寫自己創(chuàng)建的線程池吧。

我們先創(chuàng)建一個任務(wù)類Task:

/**
 * 自定義任務(wù)類
 */
public class Task implements Runnable{
    private int id;
    public Task(int id) {
        this.id = id;
    }
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "即將執(zhí)行的任務(wù)是" + id + "任務(wù)");
        try {
            Thread.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "執(zhí)行完成的任務(wù)是" + id + "任務(wù)");
    }
}

測試代碼

public class ThreadPoolExecutorDemo {
    private static final int CORE_POOL_SIZE = 3;
    private static final int MAX_POOL_SIZE = 5;
    private static final int QUEUE_CAPACITY = 10;
    private static final Long KEEP_ALIVE_TIME = 1l;

    public static void main(String[] args) {
        //通過ThreadPoolExecutor構(gòu)造函數(shù)自定義參數(shù)創(chuàng)建
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAX_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(QUEUE_CAPACITY),
                new ThreadPoolExecutor.CallerRunsPolicy());
        for (int i = 0; i < 10; i++) {
            Task task = new Task( i);
            //執(zhí)行Runnable
            executor.execute(task);
        }
        //終止線程池
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        System.out.println("線程已經(jīng)全部執(zhí)行完");
    }
}

得到的結(jié)果

pool-1-thread-1即將執(zhí)行的任務(wù)是0任務(wù)
pool-1-thread-3即將執(zhí)行的任務(wù)是2任務(wù)
pool-1-thread-2即將執(zhí)行的任務(wù)是1任務(wù)
pool-1-thread-1執(zhí)行完成的任務(wù)是0任務(wù)
pool-1-thread-3執(zhí)行完成的任務(wù)是2任務(wù)
pool-1-thread-1即將執(zhí)行的任務(wù)是3任務(wù)
pool-1-thread-3即將執(zhí)行的任務(wù)是4任務(wù)
pool-1-thread-2執(zhí)行完成的任務(wù)是1任務(wù)
pool-1-thread-2即將執(zhí)行的任務(wù)是5任務(wù)
pool-1-thread-3執(zhí)行完成的任務(wù)是4任務(wù)
pool-1-thread-1執(zhí)行完成的任務(wù)是3任務(wù)
pool-1-thread-3即將執(zhí)行的任務(wù)是6任務(wù)
pool-1-thread-1即將執(zhí)行的任務(wù)是7任務(wù)
pool-1-thread-2執(zhí)行完成的任務(wù)是5任務(wù)
pool-1-thread-2即將執(zhí)行的任務(wù)是8任務(wù)
pool-1-thread-3執(zhí)行完成的任務(wù)是6任務(wù)
pool-1-thread-1執(zhí)行完成的任務(wù)是7任務(wù)
pool-1-thread-3即將執(zhí)行的任務(wù)是9任務(wù)
pool-1-thread-2執(zhí)行完成的任務(wù)是8任務(wù)
pool-1-thread-3執(zhí)行完成的任務(wù)是9任務(wù)
線程已經(jīng)全部執(zhí)行完

總結(jié)

這篇文章就到這里了,如果這篇文章對你也有所幫助,希望您能多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

最新評論