<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>

          圖文并茂的聊聊ReentrantReadWriteLock的位運算

          共 5082字,需瀏覽 11分鐘

           ·

          2021-06-24 01:48

          我相信不少讀者,在看JDK源碼時,會看到位運算代碼,可能有些人和阿星一樣是轉(zhuǎn)行的,缺乏計算機(jī)相關(guān)的基礎(chǔ)知識,看的是一頭霧水。

          導(dǎo)致有些人直接被勸退,也有些人選擇理解字面上的意思,細(xì)節(jié)跳過。

          但是一顆疑惑的種子在我們心中埋了下來「為什么使用位運算就能達(dá)到這樣的效果?」。

          恰好ReentrantReadWriteLock讀寫狀態(tài)的設(shè)計用到了位運算,我們以此來展開今天的話題。

          一段位運算代碼

          我們來到ReentrantReadWriteLock.Sync內(nèi)部類,發(fā)現(xiàn)了這段代碼(后面以RRW簡稱

                  
          //偏移位數(shù)
          static final int SHARED_SHIFT = 16;
          //讀鎖計數(shù)基本單位
          static final int SHARED_UNIT = (1 << SHARED_SHIFT);
          //讀鎖、寫鎖可重入最大數(shù)量
          static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
          //獲取低16位的條件
          static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

          //獲取讀鎖重入數(shù)
          static int sharedCount(int c)    return c >>> SHARED_SHIFT; }
          //獲取寫鎖重入數(shù)
          static int exclusiveCount(int c) return c & EXCLUSIVE_MASK; }

          上面的這些位運算代碼是用來干嘛的?

          因為RRW的中的int整型變量state要同時維護(hù)讀鎖、寫鎖兩種狀態(tài),所以RRW的是通過高低位切割來實現(xiàn)。

          int4個字節(jié),一個字節(jié)8位,總共32位,切割一下,高16位表示讀,低16位表示寫。

          這樣做的好處就是節(jié)約資源,就像現(xiàn)實中老板把你一個人當(dāng)兩個人用是一樣的道理。

          講到這里,大家也明白了,上面的位運算代碼就是完成高低位切割的。

          讀鎖位運算

          //偏移位數(shù)
          static final int SHARED_SHIFT = 16;
          //讀鎖計數(shù)基本單位
          static final int SHARED_UNIT = (1 << SHARED_SHIFT);

          讀鎖使用高16位,每次獲取讀鎖成功+1,所以讀鎖計數(shù)基本單位是1的高16位,即1左移16位(1 << 16)。

          1左移16位等于65536,每次獲取讀鎖成功都+65536,這時有讀者跳出來問,不是+1嘛,怎么變成+65536了,這不對啊。

          別急別急,看看下面這段代碼

          //偏移位數(shù)
          static final int SHARED_SHIFT = 16;
          //獲取讀鎖重入數(shù)
          static int sharedCount(int c)    return c >>> SHARED_SHIFT; }

          上面sharedCount函數(shù)通過位運算是做無符號右移16位獲取讀鎖的重入數(shù),為什么可以獲取到呢?

          阿星原地向前走16步,再后退16步,又回到原點,1左移16位等于65536,65536右移16位等于1。

          比如我們獲取到了3次讀鎖,就是65536 * 3 = 196608,轉(zhuǎn)換下公式就是3左移16位等于196608,196608右移16位等于3。

          雖然我們每次獲取到讀鎖都會+65536,但是獲取讀鎖時會做右移16位,所以效果和+1是一樣。

          寫鎖位運算

          //偏移位數(shù)
          static final int SHARED_SHIFT = 16;
          //獲取低16位的條件
          static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
          //獲取寫鎖重入數(shù)
          static int exclusiveCount(int c) return c & EXCLUSIVE_MASK; }

          剩下的寫鎖就非常簡單,獲取低16位不用左右移動,只要把高16位全部補(bǔ)0即可。

          反推一下,因為不需要左右移動,其實就和正常的數(shù)字一樣,只不過因為高16位補(bǔ)0,導(dǎo)致數(shù)值范圍在0~65535,也就是說寫鎖獲取成功直接+1就好了。

          我們目光轉(zhuǎn)到EXCLUSIVE_MASK變量,1右移16位后-1,得到65535,65535的二進(jìn)制就是111111111111111

          現(xiàn)在來看exclusiveCount函數(shù),該函數(shù)內(nèi)做了位運算&,&又稱""運算。

          ""運算是兩個二進(jìn)制,每位數(shù)運算,運算規(guī)則如下

          • 0&0=0
          • 0&1=0
          • 1&0=0
          • 1&1=1

          如果相對應(yīng)位都是1,則結(jié)果為1,否則為0

          可能有些讀者大大還是不太明白,下面放張圖16位二進(jìn)制""運算圖

          我們發(fā)現(xiàn)""運算時,只要有一方為0,那結(jié)果一定是0,所以為了切割低16位,可以使用&來完成。

          從上圖可以看出,EXCLUSIVE_MASK16位都是0,低16位都是1,和它&的變量,高16位全部會變成0,低16位全部保留下來,最終達(dá)到獲取低16位效果。

          c & EXCLUSIVE_MASK,假設(shè)c1&的過程如下圖

          這樣看可能沒太大感覺,我們把數(shù)值調(diào)大點,假設(shè)c6553665537&的過程如下圖

          現(xiàn)在有感覺了吧,c的高16位都會變成0,低16位會原樣保留,最終達(dá)到獲取低16位效果。

          EXCLUSIVE_MASK范圍在0~65535,所以c的范圍也不會超過0~65535,因為超過了也會通過& EXCLUSIVE_MASK回到0~65535。

          提個問題

          阿星」:int如何實現(xiàn)序列化與反序列化?

          萌新」:好家伙,我直接用Integer就好了,父類Number實現(xiàn)了序列化接口Serializable

          阿星」:不使用Serializable,自己手寫一個呢?

          萌新」:啊,這。。。。

          為了讓大家更好的消化之前的內(nèi)容,阿星手把手帶大家實現(xiàn)int與字節(jié)的互轉(zhuǎn)。

          int4個字節(jié),一個字節(jié)8位,總共32位。

          int轉(zhuǎn)byte數(shù)組

          思路很簡單,我們只需要從右往左按8位一個一個截取,再存儲到byte數(shù)組里面,代碼如下:

          public static byte[] intToBytes(int n) {
                  //長度4字節(jié)的數(shù)組
                  byte[] buf = new byte[4];
                  for (int i = 0; i < buf.length; i++) {
                      //循環(huán)右移動8位,存儲到數(shù)組中
                      buf[i] = (byte) (n >> (8 * i));
                  }
                  return buf;
              }

          過程圖如下

          byte數(shù)組轉(zhuǎn)int

          我們從int轉(zhuǎn)換成了byte[],現(xiàn)在要從byte[]轉(zhuǎn)換成int,代碼如下

          public static int bytesToInt(byte[] buf) {
              return buf[0] & 0xff
                      | ((buf[1] << 8) & 0xff00)
                      | ((buf[2] << 16) & 0xff0000)
                      | ((buf[3] << 24) & 0xff000000);
          }

          代碼中涉及到了"左移、與、或"位運算,左移我們前面都說了,還有一個,一樣,只是運算規(guī)則不同,的運算規(guī)則如下

          • 0&0=0
          • 0&1=1
          • 1&0=1
          • 1&1=1

          如果相對應(yīng)位都是 0,則結(jié)果為 0,否則為 1

          0xff的二進(jìn)制是11111111,0xff后面每追加20,效果等于左移8位,依次類推,所以我們最終是利用<<、|、&、0xff來還原。

          過程圖如下

          小結(jié)

          ReentrantReadWriteLock中讀寫狀態(tài)公用一個狀態(tài),巧妙的利用高低位來節(jié)約資源,在整個實現(xiàn)過程中,使用了位運算來做高低位切割。

          1. 上班摸魚,我是認(rèn)真的

          2. 國產(chǎn)最強(qiáng)開源 API 網(wǎng)關(guān),沒有之一,不接受任何反駁!

          3. 如何把Spring Boot的Jar包做成exe?超詳細(xì)教程來了!

          4. 上海有哪些牛逼的互聯(lián)網(wǎng)公司?

          最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。

          獲取方式:點“在看”,關(guān)注公眾號并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

          文章有幫助的話,在看,轉(zhuǎn)發(fā)吧。

          謝謝支持喲 (*^__^*)

          瀏覽 27
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <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>
                  毛片av大全 | 一区二区视频传媒 | 网红鹿少女演绎点外卖视频 | 在线观看视频一区 | 黄片成人在线观看 |