<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          簡單粗暴的 Synchronized 與 ReentrantLock 區(qū)別總結(jié)

          共 3714字,需瀏覽 8分鐘

           ·

          2021-05-10 23:06

          公眾號(hào)關(guān)注 “GitHub今日熱榜
          設(shè)為 “星標(biāo)”,帶你挖掘更多開發(fā)神器!






          這篇文章是關(guān)于這兩個(gè)同步鎖的簡單總結(jié)比較,關(guān)于底層源碼實(shí)現(xiàn)原理沒有過多涉及,后面會(huì)有關(guān)于這兩個(gè)同步鎖的底層原理篇幅去介紹。


          相似點(diǎn):


          這兩種同步方式有很多相似之處,它們都是加鎖方式同步,而且都是阻塞式的同步,也就是說當(dāng)如果一個(gè)線程獲得了對(duì)象鎖,進(jìn)入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進(jìn)行線程阻塞和喚醒的代價(jià)是比較高的(操作系統(tǒng)需要在用戶態(tài)與內(nèi)核態(tài)之間來回切換,代價(jià)很高,不過可以通過對(duì)鎖優(yōu)化進(jìn)行改善)。


          功能區(qū)別:


          這兩種方式最大區(qū)別就是對(duì)于Synchronized來說,它是java語言的關(guān)鍵字,是原生語法層面的互斥,需要jvm實(shí)現(xiàn)。而ReentrantLock它是JDK 1.5之后提供的API層面的互斥鎖,需要lock()和unlock()方法配合try/finally語句塊來完成


          便利性:很明顯Synchronized的使用比較方便簡潔,并且由編譯器去保證鎖的加鎖和釋放,而ReenTrantLock需要手工聲明來加鎖和釋放鎖,為了避免忘記手工釋放鎖造成死鎖,所以最好在finally中聲明釋放鎖。


          鎖的細(xì)粒度和靈活度:很明顯ReenTrantLock優(yōu)于Synchronized


          性能的區(qū)別:


          在Synchronized優(yōu)化以前,synchronized的性能是比ReenTrantLock差很多的,但是自從Synchronized引入了偏向鎖,輕量級(jí)鎖(自旋鎖)后,兩者的性能就差不多了,在兩種方法都可用的情況下,官方甚至建議使用synchronized,其實(shí)synchronized的優(yōu)化我感覺就借鑒了ReenTrantLock中的CAS技術(shù)。都是試圖在用戶態(tài)就把加鎖問題解決,避免進(jìn)入內(nèi)核態(tài)的線程阻塞。


          1.Synchronized


          Synchronized進(jìn)過編譯,會(huì)在同步塊的前后分別形成monitorenter和monitorexit這個(gè)兩個(gè)字節(jié)碼指令。在執(zhí)行monitorenter指令時(shí),首先要嘗試獲取對(duì)象鎖。如果這個(gè)對(duì)象沒被鎖定,或者當(dāng)前線程已經(jīng)擁有了那個(gè)對(duì)象鎖,把鎖的計(jì)算器加1,相應(yīng)的,在執(zhí)行monitorexit指令時(shí)會(huì)將鎖計(jì)算器就減1,當(dāng)計(jì)算器為0時(shí),鎖就被釋放了。如果獲取對(duì)象鎖失敗,那當(dāng)前線程就要阻塞,直到對(duì)象鎖被另一個(gè)線程釋放為止。


          public class SynDemo{
           
            public static void main(String[] arg){
              Runnable t1=new MyThread();
              new Thread(t1,"t1").start();
              new Thread(t1,"t2").start();
            }
           
          }
          class MyThread implements Runnable {
           
            @Override
            public void run() {
              synchronized (this) {
                for(int i=0;i<10;i++)
                  System.out.println(Thread.currentThread().getName()+":"+i);
              }
              
            }
           
          }


          2.ReentrantLock


          由于ReentrantLock是java.util.concurrent包下提供的一套互斥鎖,相比Synchronized,ReentrantLock類提供了一些高級(jí)功能,主要有以下3項(xiàng):


          1.等待可中斷,持有鎖的線程長期不釋放的時(shí)候,正在等待的線程可以選擇放棄等待,這相當(dāng)于Synchronized來說可以避免出現(xiàn)死鎖的情況。通過lock.lockInterruptibly()來實(shí)現(xiàn)這個(gè)機(jī)制。


          2.公平鎖,多個(gè)線程等待同一個(gè)鎖時(shí),必須按照申請(qǐng)鎖的時(shí)間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認(rèn)的構(gòu)造函數(shù)是創(chuàng)建的非公平鎖,可以通過參數(shù)true設(shè)為公平鎖,但公平鎖表現(xiàn)的性能不是很好。


          公平鎖、非公平鎖的創(chuàng)建方式:


          //創(chuàng)建一個(gè)非公平鎖,默認(rèn)是非公平鎖
          Lock lock = new ReentrantLock();
          Lock lock = new ReentrantLock(false);
           
          //創(chuàng)建一個(gè)公平鎖,構(gòu)造傳參true
          Lock lock = new ReentrantLock(true);


          3.鎖綁定多個(gè)條件,一個(gè)ReentrantLock對(duì)象可以同時(shí)綁定對(duì)個(gè)對(duì)象。ReenTrantLock提供了一個(gè)Condition(條件)類,用來實(shí)現(xiàn)分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機(jī)喚醒一個(gè)線程要么喚醒全部線程。


          ReenTrantLock實(shí)現(xiàn)的原理:


          之后還會(huì)總結(jié)一篇ReenTrantLock相關(guān)的原理底層原理分析,簡單來說ReenTrantLock的實(shí)現(xiàn)是一種自旋鎖,通過循環(huán)調(diào)用CAS操作來實(shí)現(xiàn)加鎖。它的性能比較好也是因?yàn)楸苊饬耸咕€程進(jìn)入內(nèi)核態(tài)的阻塞狀態(tài)。想盡辦法避免線程進(jìn)入內(nèi)核的阻塞狀態(tài)是我們?nèi)シ治龊屠斫怄i設(shè)計(jì)的關(guān)鍵鑰匙。


          什么情況下使用ReenTrantLock:


          答案是,如果你需要實(shí)現(xiàn)ReenTrantLock的三個(gè)獨(dú)有功能時(shí)。


          ReentrantLock的用法如下:


          public class SynDemo{
           
            public static void main(String[] arg){
              Runnable t1=new MyThread();
              new Thread(t1,"t1").start();
              new Thread(t1,"t2").start();
            }
           
          }
          class MyThread implements Runnable {
           
            private Lock lock=new ReentrantLock();
            public void run() {
                lock.lock();
                try{
                  for(int i=0;i<5;i++)
                    System.out.println(Thread.currentThread().getName()+":"+i);
                }finally{
                  lock.unlock();
                }
            }
           
          }




          出處:blog.csdn.net/zxd8080666/article/details/83214089










          關(guān)注GitHub今日熱榜,專注挖掘好用的開發(fā)工具,致力于分享優(yōu)質(zhì)高效的工具、資源、插件等,助力開發(fā)者成長!







          點(diǎn)個(gè)在看


          瀏覽 67
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产激情终合 | 国产精品大全 | 稀缺小u女呦品呦cB视频 | 动漫做爱网站 | 日韩一级性爱 |