java多線程併發系列--基礎知識點(筆試、面試必備)

關注我,能夠獲取最新知識、經典面試題以及技術分享

  多線程和併發是求職大小廠面試中必問的知識點,其涉及到點不少,難度很大。有些人面對這些問題有點迷茫,爲了解決這狀況,總結了一下java多線程併發的基礎知識點。並且要想深刻研究java多線程併發也必須先掌握基礎知識,可爲後續各個模塊深刻研究作好作好準備。如今廢話很少說,各位看官請查看基礎知識點,後續還有源碼解析(synchronize底層原理,線程池原理,LockAQS,同步、併發容器等源碼解析)。java

1 基本概念

 程序: 是計算機指令的集合,它以文件的形式存儲在磁盤上,即程序是靜態的代碼面試

 進程:數據庫

  • 是一個程序在其自身的地址空間中的一次執行活動,是系統運行程序的基本單位
  • 進程是資源申請、調度和獨立運行的單位

 線程:設計模式

  • 是進程中的一個單一的連續控制流程。一個進程能夠擁有多個線程。
  • 線程又稱爲輕量級進程,它和進程同樣擁有獨立的執行控制,由操做系統負責調度,區

別在於線程沒有獨立的存儲空間,而是和所屬進程中的其它線程共享一個存儲空間,這
使得線程間的通訊遠較進程簡單。數組

 三者之間的關係:緩存

  • 線程是進程劃分紅的更小的運行單位。線程和進程最大的不一樣在於基本上各進程是獨立的,而各線程則不必定,由於同一進程中的線程極有可能會相互影響。
  • 從另外一角度來講,進程屬於操做系統的範疇,主要是同一段時間內,能夠同時執行一個以上的程序,而線程則是在同一程序內幾乎同時執行一個以上的程序段。

內存機制可查看文章《推薦收藏系列:一文理解JVM虛擬機(內存、垃圾回收、性能優化)解決面試中遇到問題》安全

2 線程組成

組成部分:虛擬CPU、執行的代碼以及處理的數據。
性能優化

3 線程與進程區別

 進程: 指系統中正在運行中的應用程序,它擁有本身獨立的內存空間;多線程

 線程: 是指進程中一個執行流程,一個進程中容許同時啓動多個線程,他們分別執行不一樣的任務,多個線程共享內存,從而極大地提升了程序的運行效率;併發

 主要區別:

  • 每一個進程都須要操做系統爲其分配獨立的內存地址空間
  • 而同一進程中的全部線程在同一塊地址空間中,這些線程能夠共享數

據,所以線程間的通訊比較簡單,消耗的系統開銷也相對較小

4 爲何要使用多線程

 使用多線程好處:

  • 能夠同時併發執行多個任務
  • 程序的某個功能部分正在等待某些資源的時候,此時又不肯意由於等待而形成程序暫停,那麼就能夠建立另外的線程進行其它的工做;
  • 多線程能夠最大限度地減低CPU的閒置時間,從而提升CPU的利用率;

5 主線程

Java程序啓動時,一個線程馬上運行,它執行main方法,這個線程稱爲程序的主線程,任何Java程序都至少有一個線程,即主線程。

 主線程的特殊之處在於:

  • 它是產生其它線程子線程的線程;
  • 一般它必須最後結束,由於它要執行其它子線程的關閉工做。

6 線程優先級

單核計算機只有一個CPU,各個線程輪流得到CPU的使用權,才能執行任務:

  • 優先級較高的線程有更多得到CPU的機會,反之亦然;
  • 優先級用整數表示,取值範圍是1~10,通常狀況下,線程的默認
  • 優先級都是5,可是也能夠經過setPriority和getPriority方法來設置或返回優先級;

Thread類有以下3個靜態常量來表示優先級:

  • MAX_PRIORITY:取值爲10,表示最高優先級
  • MIN_PRIORITY:取值爲1,表示最低優先級
  • NORM_PRIORITY:取值爲5,表示默認的優先級

7 線程的生命週期

 線程狀態(State枚舉值表明線程狀態):

  • 新建狀態( NEW): 線程剛建立, 還沒有啓動。Thread thread = new Thread()
  • 可運行狀態(RUNNABLE): 線程對象建立後,其餘線程(好比 main 線程)調用了該對象的 start 方法。該狀態的線程位於可運行線程池中,等待被線程調度選中,獲取 cpu 的使用權。
  • 運行(running): 線程得到 CPU 資源正在執行任務(run() 方法),此時除非此線程自動放棄 CPU 資源或者有優先級更高的線程進入,線程將一直運行到結束
  • 阻塞狀態(Blocked): 線程正在運行的時候,被暫停,一般是爲了等待某個時間的發生(好比說某項資源就緒)以後再繼續運行。sleep,suspendwait等方法均可以致使線程阻塞
  • 等待(WAITING): 進入該狀態的線程須要等待其餘線程作出一些特定動做(通知或中斷)。
  • 超時等待(TIMED_WAITING): 該狀態不一樣於WAITING,它能夠在指定的時間後自行返回。
  • 終止(TERMINATED): 表示該線程已經執行完畢,若是一個線程的run方法執行結束或者調用stop方法後,該線程就會死亡。對於已經死亡的線程,沒法再使用start方法令其進入就緒。

 線程在Running的過程當中可能會遇到阻塞(Blocked)狀況:

  • 調用join()sleep()方法,sleep()時間結束或被打斷,join()中斷,IO完成都會回到Runnable狀態,等待JVM的調度。
  • 調用wait(),使該線程處於等待池(wait blocked pool),直到notify()/notifyAll(),線程被喚醒被放到鎖定池(lock blocked pool ),釋放同步鎖使線程回到可運行狀態(Runnable)
  • 對Running狀態的線程加同步鎖(Synchronized)使其進入(lock blocked pool ),同步鎖被釋放進入可運行狀態(Runnable)。

8 線程建立方式

 線程建立方式:

  • 實現Runnable接口,重載run(),無返回值
  • 繼承Thread類,複寫run()
  • 實現Callable接口,經過FutureTask/Future來建立有返回值的Thread線程,經過Executor執行
  • 使用Executors建立ExecutorService,入參Callable或Future

1.實現Runnable接口,重載run(),無返回值,Runnable接口的存在主要是爲了解決Java中不容許多繼承的問題。

public class ThreadRunnable implements Runnable {
  public void run() {
    for (int i = 0; i < 10; i++) {
      System.out.println(Thread.currentThread().getName() + ":" + i);
    }
  }
}
  
public class ThreadMain {
  public static void main(String[] args) throws Exception {
    ThreadRunnable threadRunnable1 = new ThreadRunnable();
    ThreadRunnable threadRunnable2 = new ThreadRunnable();
    ThreadRunnable threadRunnable3 = new ThreadRunnable();
    Thread thread1 = new Thread(threadRunnable1);
    Thread thread2 = new Thread(threadRunnable2);
    Thread thread3 = new Thread(threadRunnable3);    
    thread1.start();
    thread2.start();
    thread3.start();
  }
}

2.繼承Thread類,重寫run(),經過調用Thread的start()會調用建立線程的run(),不一樣線程的run方法裏面的代碼交替執行。但因爲Java不支持多繼承.所以繼承Thread類就表明這個子類不能繼承其餘類.

public class ThreadCustom extends Thread {
  public void run() {
    for (int i = 0; i < 10; i++) {
      System.out.println(Thread.currentThread() + ":" + i);
    }
  }
}
  
  
public class ThreadTest {
  public static void main(String[] args)
  {
    ThreadCustom thread = new ThreadCustom();
    thread.start();
  }
}

3.實現Callable接口,經過FutureTask/Future來建立有返回值的Thread線程,經過Executor執行,該方式有返回值,能夠得到異步。

public class ThreadCallableCustom {
  public static void main(String[] args) throws Exception {
    FutureTask<Integer> futureTask = new FutureTask<Integer>(new Callable<Integer>() {
      public Integer call() throws Exception {
        for (int i = 0; i < 10; i++) {
          System.out.println(Thread.currentThread().getName() + ":" + i);
        }
        return 1;
      }
    });
    Executor executor = Executors.newFixedThreadPool(1);
    ((ExecutorService) executor).submit(futureTask);
  
    //得到線程執行狀態
    System.out.println(Thread.currentThread().getName() + ":" + futureTask.get());
  }
}

4.使用Executors建立ExecutorService,入參Callable或Future,適用於線程池和併發

public class ThreadExecutors {
  private final String threadName;
  
  public ThreadExecutors(String threadName) {
    this.threadName = threadName;
  }
  
  private ThreadFactory createThread() {
    ThreadFactory tf = new ThreadFactory() {
      public Thread newThread(Runnable r) {
        Thread thread = new Thread();
        thread.setName(threadName);
        thread.setDaemon(true);
        try {
          sleep(1000);
        }
        catch (InterruptedException e) {
          e.printStackTrace();
        }
        return thread;
      }
    };
    return tf;
  }
  
  public Object runCallable(Callable callable) {
    return Executors.newSingleThreadExecutor(createThread()).submit(callable);
  }
  
  public Object runFunture(Runnable runnable) {
    return Executors.newSingleThreadExecutor(createThread()).submit(runnable);
  }
}

public class ThreadTest {
  public static void main(String[] args) throws Exception {
    ThreadExecutors threadExecutors = new ThreadExecutors("callableThread");
    threadExecutors.runCallable(new Callable() {
      public String call() throws Exception {
        return "success";
      }
    });
  
    threadExecutors.runFunture(new Runnable() {
      public void run() {
        System.out.println("execute runnable thread.");
      }
    });
  }
}

9 Runnable接口和Callable接口區別

1)兩個接口須要實現的方法名不同,Runnable須要實現的方法爲run(),Callable須要實現的方法爲call()
2)實現的方法返回值不同,Runnable任務執行後無返回值,Callable任務執行後能夠獲得異步計算的結果。
3)拋出異常不同,Runnable不能夠拋出異常,Callable能夠拋出異常。

10 線程安全

線程安全定義

當多個線程訪問某個一類(對象或方法)時,這個類始終都能表現出正確的行爲,那麼這個類(對象或方法)就是線程安全的(即在多線程環境中被調用時,可以正確地處理多個線程之間的共享變量,使程序功能正確完成)。

線程安全示例

餓漢式單例模式-線程安全

public class EagerSingleton(){
 
    private static final EagerSingleton instance = new EagerSingleton();
 
    private EagerSingleton(){};
    
    public static EagerSingleton getInstance(){
       return instance;
    }
}

如何解決線程安全問題?

能夠經過加鎖的方式:

  • 同步(synchronized)代碼塊:只須要將操做共享數據的代碼放在synchronized
  • 同步(synchronized)方法:將操做共享數據的代碼抽取出來放到一個synchronized方法裏面就能夠了
  • Lock鎖:加同步鎖 lock() 以及釋放同步鎖unlock()

11 什麼是死鎖、活鎖?

死鎖,是指兩個或兩個以上的進程(或線程)在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。

活鎖,任務或者執行者沒有被阻塞,因爲某些條件沒有知足,致使一直重複嘗試,失敗,嘗試,失敗。

 產生死鎖的必要條件:

  • 互斥條件:所謂互斥就是進程在某一時間內獨佔資源。
  • 請求與保持條件:一個進程因請求資源而阻塞時,對已得到的資源保持不放。
  • 不剝奪條件:進程已得到資源,在末使用完以前,不能強行剝奪。
  • 循環等待條件:若干進程之間造成一種頭尾相接的循環等待資源關係。

 死鎖的解決方法:

  • 撤消陷於死鎖的所有進程。
  • 逐個撤消陷於死鎖的進程,直到死鎖不存在。
  • 從陷於死鎖的進程中逐個強迫放棄所佔用的資源,直至死鎖消失。

從另一些進程那裏強行剝奪足夠數量的資源分配給死鎖進程,以解除死鎖狀態。

12 什麼是悲觀鎖、樂觀鎖?

1)悲觀鎖

悲觀鎖,老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖。

  • 傳統的關係型數據庫裏邊就用到了不少這種鎖機制,好比行鎖,表鎖等,讀鎖,寫鎖等,都是在作操做以前先上鎖。
  • Java 裏面的同步原語 synchronized 關鍵字的實現也是悲觀鎖。

2)樂觀鎖

樂觀鎖,顧名思義,就是很樂觀,每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可使用版本號等機制。樂觀鎖適用於多讀的應用類型,這樣能夠提升吞吐量。

13 多個線程間鎖的併發控制

多個線程間鎖的併發控制,對象鎖多個線程、每一個線程持有該方法所屬對象的鎖以及類鎖。synchronized, wait, notify 是任何對象都具備的同步工具

對象鎖的同步和異步

  • 同步:synchronized,同步的概念就是共享,只須要針對共享的資源,才須要考慮同步。
  • 異步:asynchronized,異步的概念就是獨立,相互之間不受到任何制約。

同步的目的就是爲線程安全,其實對於線程安全來講,須要知足兩個特性:原子性(同步)、可見性。

14 Volatile關鍵字

Volatile做用,實現變量在多個線程間可見,保證內存可見性和禁止指令重排

多線程的內存模型:main memory(主存)、working

memory(線程棧),在處理數據時,線程會把值從主存load到本地棧,完成操做後再save回去(volatile關鍵詞的做用:每次針對該變量的操做都激發一次load and save)。

15 ThreadLocal

  線程局部變量,以空間換時間的手段,爲每一個線程提供變量的獨立副本,以無鎖的狀況下保障線程安全。主要解決的就是讓每一個線程執行完成以後再結束,這個時候就要用到join()方法。

適用場景:

  • 在併發不是很高的時候,加鎖的性能會更好
  • 在高併發量場景下,使用ThreadLocal能夠在必定程度上減小鎖競爭。

16 多線程同步和互斥實現方法

  1). 線程同步,是指線程之間所具備的一種制約關係,一個線程的執行依賴另外一個線程的消息,當它沒有獲得另外一個線程的消息時應等待,直到消息到達時才被喚醒。

 線程間的同步方法,大致可分爲兩類:用戶模式和內核模式。顧名思義:

內核模式,就是指利用系統內核對象的單一性來進行同步,使用時須要切換內核態與用戶態。內核模式下的方法有:

  • 事件
  • 信號量
  • 互斥量

用戶模式,就是不須要切換到內核態,只在用戶態完成操做。用戶模式下的方法有:

  • 原子操做(例如一個單一的全局變量)
  • 臨界區

  2). 線程互斥,是指對於共享的進程系統資源,在各單個線程訪問時的排它性。

當有若干個線程都要使用某一共享資源時,任什麼時候刻最多隻容許一個線程去使用,其它要使用該資源的線程必須等待,直到佔用資源者釋放該資源。
線程互斥能夠當作是一種特殊的線程同步。

17 線程之間通訊

線程是操做系統中獨立的個體,但這些個體之間若是不通過特殊的協做就不能成爲一個總體,線程間的通訊就成爲總體的必用方式之一。

線程間通訊的幾種方式?

線程之間的通訊方式:

  • 共享內存
  • 消息傳遞

共享內存:在共享內存的併發模型裏,線程之間共享程序的公共狀態,線程之間經過寫-讀內存中的公共狀態來隱式進行通訊。典型的共享內存通訊方式,就是經過共享對象進行通訊。


消息傳遞:在消息傳遞的併發模型裏,線程之間沒有公共狀態,線程之間必須經過明確的發送消息來顯式進行通訊。在 Java 中典型的消息傳遞方式,就是 wait() 和 notify() ,或者 BlockingQueue 。

18 什麼是 Java Lock 接口?

java.util.concurrent.locks.Lock 接口,比 synchronized 提供更具拓展行的鎖操做。它容許更靈活的結構,能夠具備徹底不一樣的性質,而且能夠支持多個相關類的條件對象。它的優點有:

  • 可使鎖更公平。
  • 可使線程在等待鎖的時候響應中斷。
  • 可讓線程嘗試獲取鎖,並在沒法獲取鎖的時候當即返回或者等待一段時間。
  • 能夠在不一樣的範圍,以不一樣的順序獲取和釋放鎖。

19 Java AQS

AQS ,AbstractQueuedSynchronizer ,即隊列同步器。它是構建鎖或者其餘同步組件的基礎框架(如 ReentrantLock、ReentrantReadWriteLock、Semaphore 等),J.U.C 併發包的做者(Doug Lea)指望它可以成爲實現大部分同步需求的基礎。它是 J.U.C 併發包中的核心基礎組件。

 優點:

AQS 解決了在實現同步器時涉及當的大量細節問題,例如獲取同步狀態、FIFO 同步隊列。基於 AQS 來構建同步器能夠帶來不少好處。它不只可以極大地減小實現工做,並且也沒必要處理在多個位置上發生的競爭問題。

在基於 AQS 構建的同步器中,只能在一個時刻發生阻塞,從而下降上下文切換的開銷,提升了吞吐量。同時在設計 AQS 時充分考慮了可伸縮性,所以 J.U.C 中,全部基於 AQS 構建的同步器都可以得到這個優點。

20 同步類容器

何爲同步容器?能夠簡單地理解爲經過synchronized來實現同步的容器,若是有多個線程調用同步容器的方法,它們將會串行執行。

 特色:

  • 是線程安全的
  • 某些場景下可能須要加鎖來保護複合操做

 常見同步類容器:

  • 如Vector、HashTable
  • 使用JDK的Collections.synchronized等工廠方法去建立實現的。
  • 底層是用傳統的synchronized關鍵字對方法進行同步。
  • 沒法知足高併發場景下的性能需求

21 併發類容器

jdk5.0之後提供了多種併發類容器來替代同步類容器從而改善性能。

同步類容器侷限性:

  • 都是串行化的。
  • 雖實現了線程安全,卻下降了併發性
  • 在多線程環境時,嚴重下降了應用程序的吞吐量。

經常使用的併發類容器:

  • ConcurrentHashMap
  • Copy-On-Write容器

 ConcurrentHashMap原理

  • 內部使用段(Segment)來表示這些不一樣的部分
  • 每一個段至關於一個小的HashTable,它們有本身的鎖。
  • 把一個總體分紅了16個段(Segment)。也就是最高支持16個線程的併發修改操做。
  • 這也是在多線程場景時經過減少鎖的粒度從而下降鎖競爭的一種方案。

 Copy-On-Write容器

Copy-On-Write簡稱COW,是一種用於程序設計中的優化策略。

  • 讀寫分離,讀和寫分開
  • 最終一致性
  • 使用另外開闢空間的思路,來解決併發衝突

 JDK裏的COW容器有兩種:

  • CopyOnWriteArrayList:適用於讀操做遠遠多於寫操做的場景,例如,緩存.
  • CopyOnWriteArraySet:線程安全的無序的集合,能夠將它理解成線程安全的HashSet,適用於Set 大小一般保持很小,只讀操做遠多於可變操做,須要在遍歷期間防止線程間的衝突

22 併發Queue

 併發Queue:

  • ConcurrentLinkedQueue,高性能隊列,當許多線程共享訪問一個公共集合時,ConcurrentLinkedQueue 是一個恰當的選擇。
  • BlockingQueue,阻塞隊列,是一個支持兩個附加操做的隊列,經常使用於生產者和消費者的場景。

 ConcurrentLinkedQueue

  • 適用於高併發場景
  • 使用無鎖的方式,實現了高併發狀態下的高性能
  • 其性能好於BlockingQueue
  • 遵循先進先出的原則

經常使用方法:

  • Add()和offer()都是加入元素的方法
  • Poll()和peek()都是取頭元素節點,區別在於前者會刪除元素,後者不會。

 BlockingQueue接口實現:

  • ArrayBlockingQueue:基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長的數組,以便緩存隊列中的數據對象,其內部沒實現讀寫分離,也就意味着生產和消費者不能徹底並行,適用不少場景。
  • LinkedBlockingQueue:基於鏈表的阻塞隊列,同ArrayBlockingQueue相似,其內部也維持着一個數據緩衝隊列(該隊列由一個鏈表構成),LinkedBlockingQueue之因此可以高效地處理併發數據,是由於其內部實現採用分離鎖(讀寫分離兩個鎖),從而實現生產者和消費者操做徹底並行運行。
  • PriorityBlockingQueue:基於優先級別的阻塞隊列(優先級的判斷經過構造函數傳入的Compator對象來決定,也就是說傳入隊列的對象必須實現Comparable接口),在實現PriorityBlockingQueue時,內部控制線程同步的鎖採用的是公平鎖
  • DelayQueue:帶有延遲時間的Queue,其中的元素只有當其指定的延遲時間到了,纔可以從隊列中獲取到該元素。DelayQueue中的元素必須先實現Delayed接口,DelayQueue是一個沒有大小限制的隊列,應用場景不少,好比對緩存超時的數據進行移除、任務超時處理、空閒鏈接的關閉等等。
  • SynchronousQueue:一種沒有緩衝的隊列,生產者產生的數據直接會被消費者獲取而且馬上消費

23 多線程的設計模式

  • 基於並行設計模式演變而來
  • 屬於設計優化的一部分
  • 是對一些經常使用的多線程結構的總結和抽象
  • 常見的多線程設計模式有哪些?

24 Concurrent.util經常使用類

CountDownLatch: 用於監聽某些初始化操做,等初始化執行完畢後,通知主線程繼續工做。

CycilcBarrier: 全部線程都準備好後,才一塊兒出發,只要有一我的沒有準備好,你們都等待。

Concurrent.util經常使用類
定義:實現異步回調,jdk針對該場景提供了一個實現的封裝,簡化了調用
適合場景:處理耗時的業務邏輯時,可有效的減小系統的響應時間,提升系統的吞吐量。

Concurrent.util經常使用類
Semaphore:信號量,適合高併發訪問, 用於進行訪問流量的控制

ReentrantLock(重入鎖)
重入鎖,在須要進行同步的代碼部分加上鎖定,但不要忘記最後必定要釋放鎖定,否則會形成鎖永遠沒法釋放,其餘線程永遠也進不來的結果。

 鎖與等待/通知

  • 多線程間進行協做工做則須要Object的wait()和notify()、notifyAll()方法進行配合工做
  • 在使用鎖的時候,可使用一個新的等待/通知的類,它就是Condition
  • 這個Condition是針對具體某一把鎖的

 多Condition

  • 可經過一個Lock對象產生多個Condition進行多線程間的交互
  • 使得部分須要喚醒的線程喚醒,其餘線程則繼續等待通知。

 ReentrantReadWriteLock(讀寫鎖)

  • 其核心就是實現讀寫分離的鎖。尤爲適應在在高併發訪問下讀多寫少的狀況下,性能要遠高於重入鎖。
  • 將讀寫鎖分離爲讀鎖和寫鎖
  • 在讀鎖下,多個線程能夠併發進行訪問
  • 在寫鎖下,只能一個一個的順序訪問
  • 鎖優化

25 線程池

 使用 Executor 框架的緣由:

  • 每次執行任務建立線程 new Thread() 比較消耗性能,建立一個線程是比較耗時、耗資源的。
  • 調用 new Thread() 建立的線程缺少管理,被稱爲野線程,並且能夠無限制的建立,線程之間的相互競爭會致使過多佔用系統資源而致使系統癱瘓,還有線程之間的頻繁交替也會消耗不少系統資源。
  • 接使用 new Thread() 啓動的線程不利於擴展,好比定時執行、按期執行、定時按期執行、線程中斷等都不便實現

 線程池的建立方式:

普通任務線程池

  • newFixedThreadPool(int nThreads) 方法,建立一個固定長度的線程池。

    • 每當提交一個任務就建立一個線程,直到達到線程池的最大數量,這時線程規模將再也不變化。
    • 當線程發生未預期的錯誤而結束時,線程池會補充一個新的線程。
  • newCachedThreadPool() 方法,建立一個可緩存的線程池。

    • 若是線程池的規模超過了處理需求,將自動回收空閒線程。
    • 當需求增長時,則能夠自動添加新線程。線程池的規模不存在任何限制。
  • newSingleThreadExecutor() 方法,建立一個單線程的線程池。

    • 它建立單個工做線程來執行任務,若是這個線程異常結束,會建立一個新的來替代它。
    • 它的特色是,能確保依照任務在隊列中的順序來串行執行。

定時任務線程池

  • newScheduledThreadPool(int corePoolSize) 方法,建立了一個固定長度的線程池,並且以延遲或定時的方式來執行任務,相似 Timer 。
  • newSingleThreadExecutor() 方法,建立了一個固定長度爲 1 的線程池,並且以延遲或定時的方式來執行任務,相似 Timer 。

 線程池的關閉方式

ThreadPoolExecutor 提供了兩個方法,用於線程池的關閉,分別是:

  • shutdown() 方法,不會當即終止線程池,而是要等全部任務緩存隊列中的任務都執行完後才終止,但不再會接受新的任務。
  • shutdownNow() 方法,當即終止線程池,並嘗試打斷正在執行的任務,而且清空任務緩存隊列,返回還沒有執行的任務

26 總結

  因爲java多線程併發涉及到的知識點太多了,這邊不可能一一列全,不過我會在後續的更新中一一去補充完善,並且會涉及原理以及源碼層次的解析。謝謝觀看,有錯誤歡迎指出更改!!

最後麻煩各位看官點個贊,謝謝支持!!!
相關文章
相關標籤/搜索