建立多線程的方式
1)繼承Thread類建立線程java
2)實現Runnable接口建立線程node
3)使用Callable和Future建立線程面試
4)使用線程池算法
start()和run()的區別
run()是線程對象執行的內容,start()是啓動線程對象spring
如何建立一個線程池Excutorservice
- 核心線程數
- 當池中線程數小於核心線程數時建立新線程
- 核心線程數不會被回收
- 最大線程數
- 當池中線程數大於核心線程數小於最大線程數且隊列滿時建立新線程
- 大於核心線程數小於最大線程數的線程在空閒時間超過超時時間後會被回收
- 阻塞隊列
- 當池中線程數大於等於核心線程數時任務會優先放入隊列中
- 經常使用的4種線程池
- fixedThreadPool: 核心線程數和最大線程數定長,多的任務放入阻塞隊列中
- cachedThreadPool: 核心線程數爲0,最大線程數無限大,線程超過空閒時間時回收
- scheduledThreadPool: 核心線程數定長,最大線程數無限大,線程執行完任務即回收,可週期性執行
- singleThreadPool: 單線程,任務放入阻塞隊列中,用於順序執行
多線程同步有哪幾種方法
- synchronized
- lock
- CountDownLatch
區別數據庫
- synchronized是jvm層面的,而lock是第三方的類,都是可重入鎖
- lock能夠判斷鎖的狀態,trylock能夠設置超時,lockInterruptibly能夠中斷等待
synchronized鎖代碼塊和鎖方法有什麼區別
- 修飾方法
- 修飾通常方法,鎖住的是對象,不一樣的對象是不一樣的鎖
- 修飾靜態方法,鎖住的是類,該類的全部對象共享這把鎖
- 對象被鎖時能夠調用該對象的非同步方法
- 修飾代碼塊
- 做用範圍是括號中的範圍
- this: 鎖住的是對象
- *.class: 鎖住的是類
鎖有哪些狀態(sleep和wait有什麼區別)
- 鎖的狀態
- 準備狀態
- 就緒狀態
- 運行狀態
- 阻塞狀態
- wait: object類,當前線程釋放了對象monitor變成掛起狀態,可用notify喚醒去搶奪對象monitor,多個線程等待時,notify只能隨機喚醒一個,全喚醒須要使用notifyAll
- sleep: Thread類中,沒有釋放對象monitor,當前線程睡眠狀態,時間到後自動喚醒
- 死亡狀態
- ReentrantLock
- lock的具體實現,是可重入鎖(同一個對象可重複遞歸調用的鎖)
- 公平鎖是線程獲取鎖的順序是按照加鎖順序,非公平鎖則是搶鎖機制
什麼是樂觀鎖,什麼是悲觀鎖
- 悲觀鎖:老是假設最壞的狀況,每次去拿數據的時候都認爲別人會修改,因此每次在拿數據的時候都會上鎖,如synchronized
- 樂觀鎖:每次去拿數據的時候都認爲別人不會修改,因此不會上鎖,可是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,能夠使用版本號等機制。如atomic包下面的原子變量,使用了volatile原語,實現方式是CAS:
- V(需讀寫的內存位置)+A(準備用來比較的參數)+B(準備寫入的新值),若A的參數與V的對應的值相匹配,就寫入值B;若不匹配,就寫入這個不匹配的值而非B。
一致性hash算法
一致性hash採用的是環狀結構,hash出來的key落到順時針最近的結點上,這樣能夠保證在結點增長刪除的狀況下影響最小,而爲了應對平衡性問題採用了虛擬結點的方式,將實際結點數放大,使key更均勻的落到每一個結點上。設計模式
java線程池裏面的arrayblockingqueue,linkedblockingqueue的用途和區別
- arrayblockingqueue是使用數組實現的必須指定長度,爲了達到環,當索引下標等於數組長度時會歸0,put和take操做共用同一把鎖,數據的寫入和讀取只移動索引。
- linkedblockingqueue是使用鏈表實現的,每次寫入會新增一個node放到鏈表尾部,讀取則從表頭刪除node,因爲put和take單獨操做分別使用各自的鎖,在效率上比arrayblockingqueue要高。