天天看點

Synchronized和ReetrantLock的進一步認識1.Synchroized2. ReetrantLock3. 線程池

文章目錄

  • 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 不存儲任何線程
  • 還有其他的就不一一列舉了