1. 程式人生 > 其它 >Java面試題-併發程式設計

Java面試題-併發程式設計

1.執行緒和程序的區別?
  • 程序:
    程序是程式中正在執行的一個程式,系統是系統資源分配的獨立實體,每個程序都擁有獨立的地址空間。一個程序無法訪問另一個程序的變數和資料結構,如果想讓一個程序訪問另一個程序的資源,需要使用程序間通訊,比如管道,檔案,套接字等。
  • 執行緒:
    執行緒是作業系統能夠進行運算排程的最小單位。它被包含在程序之中,是程序中的實際運作單位。一個程序中可以併發多個執行緒。
2.並行和併發有什麼區別?
  • 並行:多個處理器或多核處理器同時處理多個任務。
  • 併發:多個任務在同一個 CPU 核上,按細分的時間片輪流(交替)執行,從邏輯上來看那些任務是同時執行。
3.守護執行緒是什麼?

    守護執行緒是執行在後臺的一種特殊程序。它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的事件。在 Java 中垃圾回收執行緒就是特殊的守護執行緒。

4.建立執行緒有哪幾種方式?

    建立執行緒有三種方式:

  • 繼承 Thread 重寫 run 方法;
  • 實現 Runnable 介面;
  • 實現 Callable 介面。
5.說一下 runnable 和 callable 有什麼區別?

    runnable 沒有返回值,callable 可以拿到有返回值,callable 可以看作是 runnable 的補充。

6.執行緒有哪些狀態?
  • NEW 尚未啟動
  • RUNNABLE 正在執行中
  • BLOCKED 阻塞的(被同步鎖或者IO鎖阻塞)
  • WAITING 永久等待狀態
  • TIMED_WAITING 等待指定的時間重新被喚醒的狀態
  • TERMINATED 執行完成
7.sleep() 和 wait() 有什麼區別?
  • 類的不同:sleep() 來自 Thread,wait() 來自 Object;
  • 釋放鎖:sleep() 不釋放鎖;wait() 釋放鎖;
  • 用法不同:sleep() 時間到會自動恢復;wait() 可以使用 notify()/notifyAll()直接喚醒;
  • 使用場景:sleep 一般用於當前執行緒休眠,或者輪循暫停操作,wait 則多用於執行緒間的通訊;
8.Thread.yield 方法有什麼用?

    yield 方法會讓掉當前執行緒 CPU 的時間片,使正在執行中的執行緒重新程式設計就緒狀態,並重新競爭 CPU 的排程權。

9.yield 和 sleep 有什麼區別?
  • yield,sleep 都能暫停當前執行緒,sleep 可以指定具體休眠的時間,而 yield 則依賴 CUP 的時間片劃分;
  • yield,sleep 兩個在暫停過程中,如果已經持有鎖,則都不會釋放鎖資源;
  • yield 不能被中斷,而 sleep 可以接受中斷;
10.notify()和 notifyAll()有什麼區別?

    notifyAll()會喚醒所有的執行緒,notify()之後喚醒一個執行緒。notifyAll() 呼叫後,會將全部執行緒由等待池移到鎖池,然後參與鎖的競爭,競爭成功則繼續執行,如果不成功則留在鎖池等待鎖被釋放後再次參與競爭。而 notify()只會喚醒一個執行緒,具體喚醒哪一個執行緒由虛擬機器控制。

11.執行緒的 run() 和 start() 有什麼區別?

    start() 方法用於啟動執行緒,run() 方法用於執行執行緒的執行時程式碼。run() 可以重複呼叫,而 start() 只能呼叫一次。

12.建立執行緒池有哪幾種方式?使用執行緒池有什麼好處?

執行緒池建立有七種方式,最核心的是最後一種:

  • newSingleThreadExecutor():它的特點在於工作執行緒數目被限制為 1,操作一個無界的工作佇列,所以它保證了所有任務的都是被順序執行,最多會有一個任務處於活動狀態,並且不允許使用者改動執行緒池例項,因此可以避免其改變執行緒數目;

  • newCachedThreadPool():它是一種用來處理大量短時間工作任務的執行緒池,具有幾個鮮明特點:它會試圖快取執行緒並重用,當無快取執行緒可用時,就會建立新的工作執行緒;如果執行緒閒置的時間超過 60 秒,則被終止並移出快取;長時間閒置時,這種執行緒池,不會消耗什麼資源。其內部使用 SynchronousQueue 作為工作佇列;

  • newFixedThreadPool(int nThreads):重用指定數目(nThreads)的執行緒,其背後使用的是無界的工作佇列,任何時候最多有 nThreads 個工作執行緒是活動的。這意味著,如果任務數量超過了活動佇列數目,將在工作佇列中等待空閒執行緒出現;如果有工作執行緒退出,將會有新的工作執行緒被建立,以補足指定的數目 nThreads;

  • newSingleThreadScheduledExecutor():建立單執行緒池,返回 ScheduledExecutorService,可以進行定時或週期性的工作排程;

  • newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()類似,建立的是個 ScheduledExecutorService,可以進行定時或週期性的工作排程,區別在於單一工作執行緒還是多個工作執行緒;

  • newWorkStealingPool(int parallelism):這是一個經常被人忽略的執行緒池,Java 8 才加入這個建立方法,其內部會構建ForkJoinPool,利用Work-Stealing演算法,並行地處理任務,不保證處理順序;

  • ThreadPoolExecutor():是最原始的執行緒池建立,上面1-3建立方式都是對ThreadPoolExecutor的封裝。

13.執行緒池的核心引數?執行過程?
  • corePoolSize:核心執行緒數
    核心執行緒會一直存活,及時沒有任務需要執行。
    當執行緒數小於核心執行緒數時,即使有執行緒空閒,執行緒池也會優先建立新執行緒處理。
    設定allowCoreThreadTimeout=true(預設false)時,核心執行緒會超時關閉。

  • queueCapacity:任務佇列容量(阻塞佇列)
    當核心執行緒數達到最大時,新任務會放在佇列中排隊等待執行。

  • maxPoolSize:最大執行緒數
    當執行緒數>=corePoolSize,且任務佇列已滿時。執行緒池會建立新執行緒來處理任務。
    當執行緒數=maxPoolSize,且任務佇列已滿時,執行緒池會拒絕處理任務而丟擲異常。

  • keepAliveTime:執行緒空閒時間
    當執行緒空閒時間達到keepAliveTime時,執行緒會退出,直到執行緒數量=corePoolSize。
    如果allowCoreThreadTimeout=true,則會直到執行緒數量=0。

  • allowCoreThreadTimeout:允許核心執行緒超時

  • rejectedExecutionHandler:任務拒絕處理器
    兩種情況會拒絕處理任務:(1)當執行緒數已經達到maxPoolSize,切佇列已滿,會拒絕新任務。(2)當執行緒池被呼叫shutdown()後,會等待執行緒池裡的任務執行完畢,再shutdown。如果在呼叫shutdown()和執行緒池真正shutdown之間提交任務,會拒絕新任務。執行緒池會呼叫rejectedExecutionHandler來處理這個任務。如果沒有設定預設是AbortPolicy,會丟擲異常。

  • 執行過程:

    • 當執行緒數小於核心執行緒數時,建立執行緒。
    • 當執行緒數大於等於核心執行緒數,且任務佇列未滿時,將任務放入任務佇列。
    • 當執行緒數大於等於核心執行緒數,且任務佇列已滿。(1)若執行緒數小於最大執行緒數,建立執行緒。(2)若執行緒數等於最大執行緒數,丟擲異常,拒絕任務。
14.執行緒池都有哪些狀態?
  • RUNNING:這是最正常的狀態,接受新的任務,處理等待佇列中的任務。
  • SHUTDOWN:不接受新的任務提交,但是會繼續處理等待佇列中的任務。
  • STOP:不接受新的任務提交,不再處理等待佇列中的任務,中斷正在執行任務的執行緒。
  • TIDYING:所有的任務都銷燬了,workCount 為 0,執行緒池的狀態在轉換為 * TIDYING 狀態時,會執行鉤子方法 terminated()。
  • TERMINATED:terminated()方法結束後,執行緒池的狀態就會變成這個。
15.執行緒池中 submit() 和 execute() 方法有什麼區別?
  • execute():只能執行 Runnable 型別的任務。
  • submit():可以執行 Runnable 和 Callable 型別的任務。
16.為什麼阿里不讓用 Executors 建立執行緒池?
  • newSingleThreadExecutor 和 newFixedThreadPool 在 workQueue 引數直接使用了new LinkedBlockingQueue() 無界佇列理論上可以無限新增任務到執行緒池。如果提交到執行緒池的任務有問題,比如 sleep 永久,會造成記憶體洩漏,最終導致 OOM。

  • CachedThreadPool 和 ScheduledThreadPool允許的建立執行緒數量為 Integer.MAX_VALUE,可能會建立大量的執行緒,從而導致 OOM。

17.執行緒池的拒絕策略有哪幾種?
  • CallerRunsPolicy :當觸發拒絕策略,只要執行緒池沒有關閉的話,則使用呼叫執行緒直接執行任務。一般併發比較小,效能要求不高,不允許失敗。但是,由於呼叫者自己執行任務,如果任務提交速度過快,可能導致程式阻塞,效能效率上必然的損失較大

  • AbortPolicy:丟棄任務,並丟擲拒絕執行 RejectedExecutionException 異常資訊。執行緒池預設的拒絕策略。必須處理好丟擲的異常,否則會打斷當前的執行流程,影響後續的任務執行。

  • DiscardPolicy:直接丟棄,其他啥都沒有

  • DiscardOldestPolicy:當觸發拒絕策略,只要執行緒池沒有關閉的話,丟棄阻塞佇列 workQueue 中最老的一個任務,並將新任務加入

18.在 Java 程式中怎麼保證多執行緒的執行安全?
  • 方法一:使用安全類,比如 Java. util. concurrent 下的類。
  • 方法二:使用自動鎖 synchronized。
  • 方法三:使用手動鎖 Lock。

手動鎖 Java 示例程式碼如下:

Lock lock = new ReentrantLock();
lock. lock();
try {
    System. out. println("獲得鎖");
} catch (Exception e) {
    // TODO: handle exception
} finally {
    System. out. println("釋放鎖");
    lock. unlock();
}
19.多執行緒中 synchronized 鎖升級的原理是什麼?
  • synchronized 鎖升級原理:在鎖物件的物件頭裡面有一個 threadid 欄位,在第一次訪問的時候 threadid 為空,jvm 讓其持有偏向鎖,並將 threadid 設定為其執行緒 id,再次進入的時候會先判斷 threadid 是否與其執行緒 id 一致,如果一致則可以直接使用此物件,如果不一致,則升級偏向鎖為輕量級鎖,通過自旋迴圈一定次數來獲取鎖,執行一定次數之後,如果還沒有正常獲取到要使用的物件,此時就會把鎖從輕量級升級為重量級鎖,此過程就構成了 synchronized 鎖的升級。

  • 鎖的升級的目的:鎖升級是為了減低了鎖帶來的效能消耗。在 Java 6 之後優化 synchronized 的實現方式,使用了偏向鎖升級為輕量級鎖再升級到重量級鎖的方式,從而減低了鎖帶來的效能消耗。

20.什麼是死鎖?

    當執行緒 A 持有獨佔鎖a,並嘗試去獲取獨佔鎖 b 的同時,執行緒 B 持有獨佔鎖 b,並嘗試獲取獨佔鎖 a 的情況下,就會發生 AB 兩個執行緒由於互相持有對方需要的鎖,而發生的阻塞現象,我們稱為死鎖。

21.怎麼防止死鎖?
  • 儘量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),設定超時時間,超時可以退出防止死鎖。
  • 儘量使用 Java. util. concurrent 併發類代替自己手寫鎖。
  • 儘量降低鎖的使用粒度,儘量不要幾個功能用同一把鎖。
  • 儘量減少同步的程式碼塊。
22.ThreadLocal 是什麼?有哪些使用場景?
  • 含義:ThreadLocal 為每個使用該變數的執行緒提供獨立的變數副本,所以每一個執行緒都可以獨立地改變自己的副本,而不會影響其它執行緒所對應的副本。

  • 使用場景:ThreadLocal 的經典使用場景是資料庫連線和 session 管理等。

  • 副作用:由於ThreadLocalMap 的生命週期跟 Thread 一樣長,如果沒有手動刪除對應 key 的 value 就會導致記憶體洩漏,而不是因為弱引用。所以每次使用完ThreadLocal,都呼叫它的 remove() 方法,清除資料。

23.說一下 Synchronized 底層實現原理?

    synchronized 是由一對 monitorenter/monitorexit 指令實現的,monitor 物件是同步的基本實現單元。在 Java 6 之前,monitor 的實現完全是依靠作業系統內部的互斥鎖,因為需要進行使用者態到核心態的切換,所以同步操作是一個無差別的重量級操作,效能也很低。但在 Java 6 的時候,Java 虛擬機器 對此進行了大刀闊斧地改進,提供了三種不同的 monitor 實現,也就是常說的三種不同的鎖:偏向鎖(Biased Locking)、輕量級鎖和重量級鎖,大大改進了其效能。

24.Synchronized 和 volatile 的區別是什麼?
  • volatile 是變數修飾符;Synchronized 是修飾類、方法、程式碼段。
  • volatile 僅能實現變數的修改可見性,不能保證原子性;而 Synchronized 則可以保證變數的修改可見性和原子性。
  • volatile 不會造成執行緒的阻塞;Synchronized 可能會造成執行緒的阻塞。
25.Synchronized 和 Lock 有什麼區別?
  • Synchronized 可以給類、方法、程式碼塊加鎖;而 lock 只能給程式碼塊加鎖。
  • Synchronized 不需要手動獲取鎖和釋放鎖,使用簡單,發生異常會自動釋放鎖,不會造成死鎖;而 lock 需要自己加鎖和釋放鎖,如果使用不當沒有 unLock()去釋放鎖就會造成死鎖。
  • 通過 Lock 可以知道有沒有成功獲取鎖,而 Synchronized 卻無法辦到。
26.synchronized 和 ReentrantLock 區別是什麼?

    Synchronized 早期的實現比較低效,對比 ReentrantLock,大多數場景效能都相差較大,但是在 Java 6 中對 synchronized 進行了非常多的改進。

主要區別如下:

  • ReentrantLock 使用起來比較靈活,但是必須有釋放鎖的配合動作;
  • ReentrantLock 必須手動獲取與釋放鎖,而 Synchronized 不需要手動釋放和開啟鎖;
  • ReentrantLock 只適用於程式碼塊鎖,而 Synchronized 可用於修飾方法、程式碼塊等。
27.說一下 Atomic 的原理?

    Atomic 主要利用 CAS (Compare And Wwap) 和 volatile 和 native 方法來保證原子操作,從而避免 Synchronized 的高開銷,執行效率大為提升。

28.join 方法有什麼用?什麼原理?
  • 作用:Thread類中的join方法的主要作用就是同步,它可以使得執行緒之間的並行執行變為序列執行;
  • 原理:join方法的原理就是呼叫相應執行緒的wait方法進行等待操作的,例如A執行緒中呼叫了B執行緒的join方法,則相當於在A執行緒中呼叫了B執行緒的wait方法,當B執行緒執行完(或者到達等待時間),B執行緒會自動呼叫自身的notifyAll方法喚醒A執行緒,從而達到同步的目的。
29.什麼是 CAS?
  • CAS,全稱Compare And Swap(比較與交換),解決多執行緒並行情況下使用鎖造成效能損耗的一種機制。
  • CAS(V, A, B),V為記憶體地址、A為預期原值,B為新值。如果記憶體地址的值與預期原值相匹配,那麼將該位置值更新為新值。否則,說明已經被其他執行緒更新,處理器不做任何操作;無論哪種情況,它都會在 CAS 指令之前返回該位置的值。而我們可以使用自旋鎖,迴圈CAS,重新讀取該變數再嘗試再次修改該變數,也可以放棄操作。
30.為什麼不推薦 stop 停止執行緒?
  • stop方法是過時的:從Java編碼規則來說,已經過時的方式不建議採用.

  • stop方法會導致程式碼邏輯不完整:stop方法是一種"惡意" 的中斷,一旦執行stop方法,即終止當前正在執行的執行緒,不管執行緒邏輯是否完整,這是非常危險的.

  • stop方法會破壞原子邏輯:多執行緒為了解決共享資源搶佔的問題,使用了鎖的概念,避免資源不同步,但是正是因為此原因,stop方法卻會帶來更大的麻煩,它會丟棄所有的鎖,導致原子邏輯受損.

31.如何優雅的終止一個執行緒?

使用 volatile 修飾的 flag 變數來控制執行緒中的邏輯,來達到停止執行緒的效果同樣可以。

public class ThreadInterruptVolatileDemo {

   private static volatile boolean flag = false;

   public static void main(String[] args) throws InterruptedException {
       Thread thread = new Thread(new InterruptTask());
       thread.start();
       thread.sleep(500);
       flag = true;
    }

   static class InterruptTask implements Runnable {
       @Override
       public void run() {
           int count = 0;
           while (!flag) {
               count++;
           }
           System.out.println("迴圈次數:" + count + ",執行緒中斷");
       }
    }
}
32.什麼是重入鎖(ReentrantLock)?

就像下面這樣:一個類中,同步方法之間的呼叫就需要重複獲取this鎖

public class Demo1 {
    public synchronized void functionA(){
        System.out.println("iAmFunctionA");
        functionB();
    }
    public synchronized void functionB(){
        System.out.println("iAmFunctionB");
    }
}
  • 含義:當某個執行緒獲取到鎖時,該執行緒還能繼續獲取該鎖,也就是說執行緒可以重複獲取同一把鎖;
  • 意義:在某個執行緒需要重複獲取同一把鎖的情況下,不會導致死鎖的發生;
  • 常見的重入鎖:Synchronized,ReentrantLock;
  • 實現原理:通過為每個鎖關聯一個請求計數器和一個獲得該鎖的執行緒。當計數器為0時,認為鎖是未被佔用的。執行緒請求一個未被佔用的鎖時,JVM將記錄該執行緒並將請求計數器設定為1,此時該執行緒就獲得了鎖,當該執行緒再次請求這個鎖,計數器將遞增,當執行緒退出同步方法或者同步程式碼塊時,計數器將遞減,當計數器為0時,執行緒就釋放了該物件,其他執行緒才能獲取該鎖;
33.什麼是讀寫鎖?
  • 讀寫鎖允許同一時刻多個讀執行緒訪問,但是寫執行緒和其他執行緒均被阻塞。
  • 讀寫鎖維護一個讀鎖一個寫鎖,讀寫分離,併發性得到了提升。
  • Java 中提供讀寫鎖的實現類是:ReentrantReadWriteLock。
34.公平鎖和非公平鎖的區別?
  • 公平鎖 指在分配鎖前檢查是否有執行緒在排隊等待獲取該鎖,優先將鎖分配給排隊時間最長的執行緒;
  • 非公平鎖 指在分配鎖時不考慮執行緒排隊等待的情況,直接嘗試獲取鎖,在獲取不到鎖時再排到隊尾等待;
  • 公平鎖需要在多核的情況下維護一個鎖執行緒等待佇列,基於該佇列進行鎖的分配,因此效率比非公平鎖低很多,java中的synchronized時非公平鎖,ReentranLock預設的lock方法採用的時非公平鎖;
35.有哪些鎖優化的方式?
  • 減少鎖持有時間
  • 減小鎖粒度
  • 鎖分離
  • 鎖粗化
  • 鎖消除
36.什麼是偏向鎖?
  • 含義:偏向鎖是一種針對加鎖操作的優化手段。如果一個執行緒獲得了鎖,那麼鎖就進入偏向模式。當這個執行緒再次請求鎖時,無需再做任何同步操作。
  • 效率:對於幾乎沒有鎖競爭的場合,偏向鎖有比較好的優化效果,因為連續多次極有可能是同一個執行緒請求相同的鎖。而對於鎖競爭比較激烈的場合,其效果不佳。因為在競爭激烈的場合,最有可能的情況是每次都是不同的執行緒來請求相同的鎖。
  • JDK1.6為什麼引入偏向鎖:經過 HotSpot 的作者大量的研究發現,大多數時候是不存在鎖競爭的,常常是一個執行緒多次獲得同一個鎖,因此如果每次都要競爭鎖會增大很多沒有必要付出的代價,為了降低獲取鎖的代價,才引入的偏向鎖。
37.什麼是輕量級鎖?
  • 含義:如果偏向鎖失敗,那麼虛擬機器並不會立即掛起執行緒,它還會使用一種稱為輕量級鎖的優化手段。
  • 實現:輕量級鎖的操作也很方便,它只是簡單地將物件頭部作為指標指向持有鎖的執行緒堆疊的頭部,來判斷一個執行緒是否持有物件鎖。
  • 過程:如果執行緒獲得輕量級鎖成功,則可以順利進入臨界區,如果輕量級鎖加鎖失敗,則表示其他執行緒搶先爭奪到了鎖,那麼當前執行緒的鎖請求就會膨脹為重量級鎖。
38.什麼是自旋鎖?
  • 自旋鎖:鎖膨脹後,為了避免執行緒真實地在作業系統層面掛起,而是升級為自旋鎖。
  • 當前執行緒暫時獲取不到鎖,但是如果簡單粗暴地將這個執行緒掛起是一種得不償失的操作,因此虛擬機器會讓當前執行緒做幾個空迴圈,在經過若干次迴圈後,如果可以得到鎖,那麼就順利進入臨界區。
39.什麼是鎖消除?
  • 含義:鎖消除是Java虛擬機器在JIT編譯期間,通過對執行上下文的掃描,去除不可能存在共享資源競爭的鎖,通過鎖消除,可以節省毫無意義的請求鎖時間。
  • 原理:鎖消除是由於逃逸分析帶來的優化,它消除了多餘的同步。當內部同步程式碼沒有逃逸到外部時,runtime就可以完全消除同步了。
40.volatile 有什麼用?有哪些應用場景?
  • 作用:保證了變數的可見性(visibility)。被volatile關鍵字修飾的變數,如果值發生了變更,其他執行緒立馬可見,避免出現髒讀的現象。
  • 應用場景:狀態的轉變、讀多寫少的情況
41.Java 中原子操作的類有哪些?
  • AtomicBoolean:原子更新布林型別。
  • AtomicInteger:原子更新整型。
  • AtomicLong: 原子更新長整型。
  • AtomicIntegerArray:原子更新整形陣列。
  • AtomicLongArray:原子更新長整型陣列。
  • AtomicReferenceArray:原子更新引用型別數組裡的元素。
42.什麼是 ABA 問題,怎麼解決?
  • 什麼是 ABA 問題:
    因為 CAS 需要在操作值的時候,檢查值有沒有變化,如果沒有變化則更新,如果一個值原來是 A,變成了 B,又變成了 A,那麼使用 CAS 進行檢測時會發現值沒有發生變更,其實是變過的。
  • 解決方案:
    新增版本號,每次更新的時候追加版本號,A-B-A——> 1A - 2B - 3A
    從 JDK 1.5 開始,Atomic 包提供了一個 AtomicStampedReference 類來解決 ABA 的問題。
43.什麼是阻塞佇列?有哪些應用場景?
  • 什麼是阻塞佇列:
    阻塞佇列是一個支援阻塞的插入和移除方法的佇列。即當佇列滿時,佇列會阻塞插入元素的執行緒,直到佇列不滿;當佇列空時,獲取元素的執行緒會等待佇列變為非空。
  • 應用場景:
    常用於生產者和消費者場景,生產者是往佇列裡新增元素的執行緒,消費者是從佇列裡取元素的執行緒。
  • 原理:採用通知模式。這有點類似於作業系統中學過的訊號量。當生產者著往滿的佇列中新增元素會阻塞住生產者,直到消費者消費了一個元素後,通知生產者佇列可用。ArrayBlockingQueue使用了Condition實現。
44.Java 中的阻塞佇列有哪些?
  • ArrayBlockingQueue:是一個用陣列實現的有界阻塞佇列,此佇列按照先進先出(FIFO)的原則對元素進行排序。支援公平鎖和非公平鎖。【注:每一個執行緒在獲取鎖的時候可能都會排隊等待,如果在等待時間上,先獲取鎖的執行緒的請求一定先被滿足,那麼這個鎖就是公平的。反之,這個鎖就是不公平的。公平的獲取鎖,也就是當前等待時間最長的執行緒先獲取鎖】
  • LinkedBlockingQueue:一個由連結串列結構組成的有界佇列,此佇列的長度為Integer.MAX_VALUE。此佇列按照先進先出的順序進行排序。
  • PriorityBlockingQueue: 一個支援執行緒優先順序排序的無界佇列,預設自然序進行排序,也可以自定義實現compareTo()方法來指定元素排序規則,不能保證同優先順序元素的順序。
  • DelayQueue: 一個實現PriorityBlockingQueue實現延遲獲取的無界佇列,在建立元素時,可以指定多久才能從佇列中獲取當前元素。只有延時期滿後才能從佇列中獲取元素。(DelayQueue可以運用在以下應用場景:1.快取系統的設計:可以用DelayQueue儲存快取元素的有效期,使用一個執行緒迴圈查詢DelayQueue,一旦能從DelayQueue中獲取元素時,表示快取有效期到了。2.定時任務排程。使用DelayQueue儲存當天將會執行的任務和執行時間,一旦從DelayQueue中獲取到任務就開始執行,從比如TimerQueue就是使用DelayQueue實現的。)
  • SynchronousQueue: 一個不儲存元素的阻塞佇列,每一個put操作必須等待take操作,否則不能新增元素。支援公平鎖和非公平鎖。SynchronousQueue的一個使用場景是線上程池裡。Executors.newCachedThreadPool()就使用了SynchronousQueue,這個執行緒池根據需要(新任務到來時)建立新的執行緒,如果有空閒執行緒則會重複使用,執行緒空閒了60秒後會被回收。
  • LinkedTransferQueue: 一個由連結串列結構組成的無界阻塞佇列,相當於其它佇列,LinkedTransferQueue佇列多了transfer和tryTransfer方法。
  • LinkedBlockingDeque: 一個由連結串列結構組成的雙向阻塞佇列。佇列頭部和尾部都可以新增和移除元素,多執行緒併發時,可以將鎖的競爭最多降到一半。
45.什麼是冪等性?

    在程式設計中.一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函式,或冪等方法,是指可以使用相同引數重複執行,並能獲得相同結果的函式。這些函式不會影響系統狀態,也不用擔心重複執行會對系統造成改變。例如,“getUsername()和setTrue()”函式就是一個冪等函式. 更復雜的操作冪等保證是利用唯一交易號(流水號)實現.

    我的理解:冪等就是一個操作,不論執行多少次,產生的效果和返回的結果都是一樣的。