文章目錄
- 1.Synchroized
- 2. ReetrantLock
- 3. 線程池
1.Synchroized
前提:八股看了一遍又一遍,每次看這個Synchroized都有點不同,這次把整體總結一下
- 用處:同步代碼塊、同步方法
- 對于非靜态的一般上鎖就是針對目前的對象執行個體;而對于靜态的則針對的目前類的所有對象,因為對于類的資訊我們是存在方法區的,JVM中隻有一份。
- 對象:一個對象在存儲中,包含了對象頭、執行個體資料、對其資料。而對象頭又包含了MarkWord、類指針(指向類的資訊),而對于鎖這一部分,其實主要是MarWord這一部分:分代年齡(GC)、hashCode(HashMap)、标記位(這一部分标記了無鎖、偏向鎖、輕量級鎖、重量級鎖)
- 簡單說一下:無鎖、偏向鎖(隻有一個線程)、輕量級鎖(多個線程順序執行)、重量級鎖(搶鎖),當然還有自旋鎖,自适應自旋鎖等。
是以對于鎖來說,其實就是對象螢幕來針對目前對象的對象頭的标志位的一個搶占(對于類的話,應該是類對象吧,隻有一個),主要以對象頭标志搶占為主:
- 擁有對象螢幕(鎖)的線程
- 其他線程來的時候會進行cas搶鎖,搶不到進到等待隊列中(競争隊列、候選隊列),因為可能同時有大量線程在等待隊列中,是以我們将一部分線程拿到候選隊列,作為下一次的鎖的優先競争者
- Ondesk,下一次擷取鎖的線程,在目前線程釋放鎖之後,會在候選隊列的一個線程中喚醒一個指定到Ondesk,然後再開始競争,這裡的競争主要是Ondesk線程和此時正在cas的線程,是以這是競争切換,明顯不公平
- 還有一個阻塞隊列,是調用wait函數的線程,會把目前對象的鎖釋放,然後把目前線程放到阻塞隊列中,隻有其他線程進行notify喚醒,才可以重新進入等待隊列的候選隊列
注:
三種隊列:等待隊列(競争隊列+候選隊列)、阻塞隊列、運作的線程、下次競争的線程
2. ReetrantLock
順便把它講了吧,這是JDK實作的,而上面的是内置的;并且ReentrantLock需要手動釋放鎖,出現異常可能會産生死鎖,而Synchronized會自動釋放;兩者都是非公平鎖+可重入鎖,但是前者(lock)可以實作公平鎖,并且可中斷。
- 内部最重要的可以說是AQS-隊列抽象同步器
- 繼承它的内部類分别實作了公平鎖、和非公平鎖
- 思想:一個是state狀态 = c、一個是線程隊列
- 1.公平鎖
- 剛開始不會直接CAS搶鎖
- if c == 0
- 判斷隊列是否為空,為空則cas搶鎖,c = 1;否則加入隊列
- else 可重入(一般判斷線程名是否相等)
- 加入隊列
- 2.非公平鎖
- 直接cas搶鎖(明顯不公平)
- if c == 0
- cas 搶鎖成功 c ==1;失敗加入隊列
- else 可重入
- 加入隊列
注:可以看到其實和synchroized一樣都是剛開始進行cas搶鎖,明顯不公平。
3. 線程池
繼續--------
為什麼需要?
1.可以進行重用,來任務的時候快速的啟動,避免線程的銷毀
2.線程池統一管理、統一配置設定
參數:
核心線程數量、最大線程數量、存活時間、機關、阻塞隊列、拒絕政策、線程工廠
常見的幾種線程池:
- newFixedPoolThread(n,n,0,s,LinkedBlockingQuene)
- newSinglePoolThread(1,1,0,s,LinkedBlockedQueue)
- newCachePoolThread(0,Max_Value,60,s,SynchronousQuene)
- newSchedulePoolThread–定時執行
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5); scheduledThreadPool.schedule(new Runnable() { @Override public void run() { System.out.println("delay 3 seconds"); } }, 3, TimeUnit.SECONDS);
工作原理:
對于新來的任務
- 建立核心線程
- 核心線程數量達到最大,進入隊列
- 隊列滿了,建立非核心線程
- 都滿了,則拒絕政策
- 時間到了,非核心線程死亡
拒絕政策:
- 直接丢棄
- 丢棄 + 并抛出異常
- 抛棄隊列隊首,加入目前線程
- 調用目前任務的線程代為執行
阻塞隊列:
- LinkedBlockingQueue 無窮大
- SynchronousQueue 不存儲任何線程
- 還有其他的就不一一列舉了