收集常見的問題,之後或許用獲得java
- 線程池的原理,爲何要建立線程池?建立線程池的方式? 答:當向線程池提交一個任務的時候。
- 先看線程池中的核心線程是否有空閒的,若是有建立一個工做線程來執行任務。若是核心線程都在工做,那麼進入下一步
- 判斷任務隊列是否滿了,若是任務隊列未滿,則把任務存儲到任務隊列,執行下一步。若是滿了,執行拒絕策略。
- 添加到任務隊列以後,再判斷核心線程是否有空閒的,若是沒有空閒的,那麼嘗試建立新的非核心線程執行任務。
在實際的生產環境中,線程的數量必須獲得控制,盲目的大量建立線程對系統性能是有傷害的,合理使用線程好處:程序員
- 減小在建立和銷燬現場上所消耗的時間和系統資源
- 提升響應速度,無需建立能夠直接運行
- 提升線程的可管理性。使用線程池能夠進行統一分配,調優和監控,可是要作到合理利用線程池,必須對其原理了如指掌。
建立線程池的方式:面試
- Executors框架,有可能致使OOM異常
- 手動建立線程池,咱們更明白線程池的參數,方便調優
參考:多線程之線程池(六)數據庫
- 線程的生命週期,何時會出現僵死進程? 線程是輕量級的進程,進程能夠說是線程的容器。
參考:多線程之併發基礎-線程狀態與操做(三)編程
- 說說線程安全問題,什麼是實現線程安全,如何實現線程安全? 併發編程中最常出現的情形就是多個線程共享一個資源,這些共享的資源極可能致使錯誤或者數據不一致的情形,須要想辦法來解決這種問題。線程安全是多線程領域的問題,線程安全能夠簡單理解爲一個方法或者一個實例能夠在多線程環境中使用而不會出現問題。
線程安全實現方式:數組
- 互斥同步,加鎖,悲觀方案,保證共享數據同一時刻只有一個線程訪問。,互斥是因,同步是果。
- 非阻塞同步,CAS,樂觀方案,先進行操做,若是沒有其餘線程也進行操做,那麼就操做成功了,若是有其它線程也在操做共享數據,那麼再重試。
- 無同步方案,通常爲純代碼,有一些特性,如不依賴堆上的公用系統資源
參考:Java高效併發(九)安全
-
synchronized便可修飾非靜態方式,也可修飾靜態方法,還可修飾代碼塊,有何區別? 答:synchronized修飾非靜態同步方法時,鎖住的是當前實例;synchronized修飾靜態同步方法時,鎖住的是該類的Class對象;synchronized修飾靜態代碼塊時,鎖住的是synchronized關鍵字後面括號內的對象。bash
-
建立線程池有哪幾個核心參數? 如何合理配置線程池的大小?多線程
- corePoolSize: 線程池的基本大小。當提交一個任務的時候,線程池就會建立一個新的線程執行任務,即便核心線程池中有空閒線程,也會新建,直到線程池中的數量等於corePoolSize就再也不建立。若是調用了線程池的prestartAllCoreThreads()方法,線程池會提早建立並啓動全部的線程。
- maximumPoolSize:線程池容許建立的最大線程數。當使用無界隊列的時候,這個參數就沒什麼效果了。
- keepAliveTime:線程池的工做線程空閒之後,保持存活的時間,若是任務多,而且任務執行時間段,能夠調大時間,提升線程的利用率。
- unit 保活時間的單位
- workQueue: 任務隊列,用於保持或等待執行的任務阻塞隊列。有以下隊列可供選擇:
- ArrayBlockingQueue: 基於數組結構的有界隊列,此隊列按FIFO原則對元素進行排序
- LinkedBlockingQueue: 基於鏈表的阻塞隊列,FIFO原則,吞吐量一般高於ArrayBlockingQueue.
- SynchronousQueue: 不存儲元素的阻塞隊列。每一個插入必需要等到另外一個線程調用移除操做。
- PriorityBlockingQueue: 具備優先級的無阻塞隊列
- threadFactory:用於設置建立線程的工廠。
- handler:拒絕策略,當隊列線程池都滿了,必須採用一種策略來處理還要提交的任務。在實際應用中,咱們能夠將信息記錄到日誌,來分析系統的負載和任務丟失狀況JDK中提供了4中策略:
- AbortPolicy: 直接拋出異常。 默認的策略
- CallerRunsPolicy: 只用調用者所在的線程來運行任務
- DiscardOldestPolicy: 丟棄隊列中最老的一我的任務,並執行當前任務。
- DiscardPolicy: 直接丟棄新進來的任務
線程池中線程的數量過大和太小都沒法使系統的性能發揮到最優,肯定線程池的大小能夠考慮下面的角度:併發
- 任務性質:CPU密集,IO密集,和混合密集
- 任務執行時間:長,中,低
- 任務優先級:高,中,低
- 任務的依賴性:是否依賴其它資源,如數據庫鏈接
- 建議使用有界隊列,防止撐爆內存
CPU密集型:線程數=按照核數或者核數+1
IO密集型: 線程數=CPU核數 * (1 + 平均等待時間/平均工做時間)
參考:多線程之線程池(六)
- volatile、ThreadLocal的使用場景和原理? JMM中主要是圍繞併發過程當中如何處理原子性,可見性和有序性三個特性來創建的。最終能夠保證線程安全性.
一個變量定義爲volatile以後,它將具備兩種特性:
- 保證次變了對全部線程的可見性,一條線程修改了這個值,新值對其它線程是能夠當即得知的。
- 禁止指令重排優化。
Synchronized保證了原子性,可見性與有序性,它的工做時對同步的代碼塊加鎖,使得每次只有一個線程進入代碼塊,從而保證線程安全。synchronized反應到字節碼層面就是monitorenter與monitorexit.
Volatile適合作什麼? 適合作標量,當一個線程對某個變量進行讀寫操做,而其它線程僅僅進行讀操做的時候,是能夠保證volatile的正確性的。以下:
volatile bool stopped;
public void stop(){
stopped = true
}
while(!stoppped){
// 執行操做
}
複製代碼
參考:多線程之volatile與synchronized(二)
- ThreadLocal何時會出現OOM的狀況?爲何? 答:當一個線程調用ThreadLocal的set方法設置變量時候,當前線程的ThreadLocalMap裏面就會存放一個記錄,這個記錄的key爲ThreadLocal的引用,value則爲設置的值。若是當前線程一直存在而沒有調用ThreadLocal的remove方法,而且這時候其它地方仍是有對ThreadLocal的引用,則當前線程的ThreadLocalMap變量裏面會存在ThreadLocal變量的引用和value對象的引用是不會被釋放的,這就會形成內存泄露的。
參考:使用ThreadLocal不當可能會致使內存泄露 借ThreadLocal出現OOM內存溢出問題再談弱引用WeakReference
- 線程池的狀態有哪些?
- Running: 能接受新的任務,而且能處理阻塞隊列中的任務
- Shutdown: 再也不接受新的任務,可是能處理存量任務
- ShutdownNow: 再也不接受新的任務,也不處理存量任務
- Tidying: 全部任務都已經終止
- Terminated: terminated()方法執行以後進入此狀態
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
複製代碼
最後
持續更新,多線程相關問題
題目參考