併發程式設計
保證資料的一致性
事務管理,鎖機制,版本控制
執行緒的建立方式
繼承Thread類,重寫其run()方法,呼叫start()方法啟動執行緒
實現Runnable介面,重寫run()方法,呼叫start()方法啟動執行緒
實現Callable介面與FutureTask
使用執行緒池(Executor框架)
停止一個執行緒的執行
異常法停止:執行緒呼叫interrupt()方法後,線上程的run方法中判斷當前物件的interrupted()狀態,如果是中斷狀態則丟擲異常,達到中斷執行緒的效果。
在沉睡中停止:先將執行緒sleep,然後呼叫interrupt標記中斷狀態,interrupt會將阻塞狀態的執行緒中斷。會丟擲中斷異常,達到停止執行緒的效果
stop()暴力停止:執行緒呼叫stop()方法會被暴力停止,方法已棄用,該方法會有不好的後果:強制讓執行緒停止有可能使一些請理性的工作得不到完成。
使用return停止執行緒:呼叫interrupt標記為中斷狀態後,在run方法中判斷當前執行緒狀態,如果為中斷狀態則return,能達到停止執行緒的效果。
Java執行緒的狀態
NEW:尚未啟動的執行緒狀態,即執行緒建立,還未呼叫start方法
RUNNABLE:就緒狀態(呼叫start,等待排程)+正在執行
BLOCKED:等待監視器鎖時,陷入阻塞狀態
WAITING:等待狀態的執行緒正在等待另一執行緒執行特定的操作(如notify)
TIMED_WAITING:具有指定等待時間的等待狀態
TERMINATED:執行緒完成執行,終止狀態
notify 和 notifyAll 的區別
喚醒隨機一個和全部
Java中有哪些常用的鎖
內建鎖(synchronized)
ReentrantLock
讀寫鎖(ReadWriteLock)
樂觀鎖和悲觀鎖
自旋鎖
synchronized 工作原理
synchronized是Java提供的原子性內建鎖,使用synchronized之後,會在編譯之後在同步的程式碼塊前後加上monitorenter和monitorexit位元組碼指令,他依賴作業系統底層互斥鎖實現
waitSet和entryList+計數器
無鎖、偏向鎖、輕量級鎖和重量級鎖
reentrantlock工作原理
底層實現主要依賴於 AbstractQueuedSynchronizer(AQS)這個抽象類。AQS 是一個提供了基本同步機制的框架,其中包括了佇列、狀態值等
可中斷性,設定超時時間,公平鎖和非公平鎖,多個條件變數,可重入性
synchronized和reentrantlock應用場景的區別
synchronized:簡單同步需求,程式碼塊同步,內建鎖的使用
ReentrantLock:
高階鎖功能需求,如公平鎖、響應中斷;
效能最佳化:提供了更細粒度的控制;
複雜同步結構
synchronized 支援重入嗎?如何實現的?
是可重入的
如果鎖狀態是0,代表該鎖沒有被佔用,使用CAS操作獲取鎖,將執行緒ID替換成自己的執行緒ID。
如果鎖狀態不是0,代表有執行緒在訪問該方法。此時,如果執行緒ID是自己的執行緒ID,如果是可重入鎖,會將status自增1,然後獲取到該鎖,進而執行相應的方法;如果是非重入鎖,就會進入阻塞佇列等待。
syncronized鎖升級的過程
無鎖--沒有開啟偏向鎖
偏向鎖--一個執行緒,還沒有一個執行緒拿到這個鎖的話,這個狀態叫做匿名偏向,當一個執行緒拿到偏向鎖的時候,下次想要競爭鎖只需要拿執行緒ID跟MarkWord當中儲存的執行緒ID進行比較,如果執行緒ID相同則直接獲取鎖(相當於鎖偏向於這個執行緒),不需要進行CAS操作和將執行緒掛起的操作。
輕量級鎖--鎖競爭,CAS操作實現,自旋
重量級鎖:當有兩個以上的執行緒獲取鎖,執行緒會被作業系統排程然後掛起
JVM對Synchornized的最佳化
鎖膨脹:synchronized 從無鎖升級到偏向鎖,再到輕量級鎖,最後到重量級鎖的過程
鎖消除:檢測不到某段程式碼被共享和競爭的可能性,就會將這段程式碼所屬的同步鎖消除掉
鎖粗化:將多個連續的加鎖、解鎖操作連線在一起,擴充套件成一個範圍更大的鎖。
自適應自旋鎖:指透過自身迴圈,嘗試獲取鎖的一種方式
AQS
AQS全稱為AbstractQueuedSynchronizer,是Java中的一個抽象類。 AQS是一個用於構建鎖、同步器、協作工具類的工具類(框架)
AQS核心思想是,如果被請求的共享資源空閒,那麼就將當前請求資源的執行緒設定為有效的工作執行緒,將共享資源設定為鎖定狀態;如果共享資源被佔用,就需要一定的阻塞等待喚醒機制來保證鎖分配。這個機制主要用的是CLH佇列的變體實現的,將暫時獲取不到鎖的執行緒加入到佇列中。
CLH:Craig、Landin and Hagersten佇列,是單向連結串列,AQS中的佇列是CLH變體的虛擬雙向佇列(FIFO),AQS是透過將每條請求共享資源的執行緒封裝成一個節點來實現鎖的分配
使用一個Volatile的int型別的成員變數來表示同步狀態,透過CAS完成對State值的修改
AQS原理
AQS最核心的就是三大部分:
狀態:state;
控制執行緒搶鎖和配合的FIFO佇列(雙向連結串列);
期望協作工具類去實現的獲取/釋放等重要方法(重寫)
Threadlocal作用,原理,具體裡面存的key value是啥,會有什麼問題,如何解決?
ThreadLocal是Java中用於解決執行緒安全問題的一種機制,它允許建立執行緒區域性變數
Thread類中,有個ThreadLocal.ThreadLocalMap 的成員變數。
ThreadLocalMap內部維護了Entry陣列,每個Entry代表一個完整的物件,key是ThreadLocal本身,value是ThreadLocal的泛型物件值。
ThreadLocal的作用
執行緒隔離,降低耦合度,效能優勢
ThreadLocal的原理
當建立一個ThreadLocal變數時,實際上就是一個ThreadLocal物件的例項。每個ThreadLocal物件都可以儲存任意型別的值,這個值對每個執行緒來說是獨立的。
有內容->get()->獲得值
無內容->get()->initialValue()->放入ThreadLocalMap並返回
set()->儲存鍵值對
remove()->移除鍵值對
存在的問題
ThreadLocal物件本身不會立即被垃圾回收,直到沒有其他引用指向它為止
如果不顯式呼叫remove()方法,或者執行緒結束時未正確清理ThreadLocal變數,可能會導致記憶體洩漏,因為key是弱引用能被自動回收,但是如果是執行緒池一類或者什麼原因,執行緒沒能銷燬,作為強引用的value其實一直存在,導致記憶體洩漏
悲觀鎖和樂觀鎖的區別
Java中想實現一個樂觀鎖,都有哪些方式
CAS,版本號,時間戳
CAS 有什麼缺點
ABA問題,迴圈時間長開銷大,只能保證一個共享變數的原子操作
為什麼不能所有的鎖都用CAS
大量執行緒自旋會導致CPU資源浪費
voliatle關鍵字有什麼作用
保證變數對所有執行緒的可見性(從主存中讀取),禁止指令重排序最佳化(讀寫屏障)
volatile和sychronized比較
Synchronized: Synchronized是一種排他性的同步機制,程式碼塊或方法
Volatile: Volatile是一種輕量級的同步機制,從記憶體中讀取變數
公平鎖和非公平鎖
公平鎖的優點在於各個執行緒公平平等,每個執行緒等待一段時間後,都有執行的機會,而它的缺點就在於整體執行速度更慢,吞吐量更小
非公平鎖的優勢就在於整體執行速度更快,吞吐量更大,但同時也可能產生執行緒飢餓問題
Synchronized是公平鎖嗎
Synchronized不屬於公平鎖,ReentrantLock是公平鎖
如果是公平鎖,那麼一旦已經有執行緒在排隊了,當前執行緒就不再嘗試獲取鎖;對於非公平鎖而言,無論是否已經有執行緒在排隊,都會嘗試獲取一下鎖,獲取不到的話,再去排隊
執行緒池的工作原理
核心執行緒->等待佇列->最大執行緒->丟棄策略
執行緒池的引數
核心執行緒數量,最大執行緒數量,額外空閒執行緒存活時間,時間的單位,工作佇列,拒絕策略,執行緒工廠(可以用來給執行緒取名字等等)
拒接策略
執行緒池呼叫者的執行緒去處理;丟擲拒絕異常;不處理並拒絕;丟棄最老的任務;自定義
執行緒池種類
ScheduledThreadPool:可以設定定期的執行任務
FixedThreadPool:它的核心執行緒數和最大執行緒數是一樣的
CachedThreadPool:可以稱作可快取執行緒池,它的特點在於執行緒數是幾乎可以無限增加的
SingleThreadExecutor:它會使用唯一的執行緒去執行任務
執行緒池一般是怎麼用的
應該手動 new ThreadPoolExecutor 來建立執行緒池
shutdown (),shutdownNow()
shutdown使用了以後會置狀態為SHUTDOWN,正在執行的任務會繼續執行下去,沒有被執行的則中斷。此時,則不能再往執行緒池中新增任何任務
shutdownNow 為STOP,並試圖停止所有正在執行的執行緒,不再處理還在池佇列中等待的任務,當然,它會返回那些未執行的任務
提交給執行緒池中的任務可以被撤回嗎?
提交會得到一個Future
物件。這個Future
物件提供了幾種方法來管理任務的執行,包括取消任務