<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的位運算

          共 677字,需瀏覽 2分鐘

           ·

          2021-11-18 09:35

          大家好,歡迎來到學習ReentrantReadWriteLock基礎,今天我們來聊一聊讀寫狀態(tài)的設計。

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

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

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

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

          一段位運算代碼

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

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

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

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

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

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

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

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

          讀鎖位運算

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

          讀鎖使用高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位等于6553665536右移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?<1;
          //獲取寫鎖重入數(shù)
          static?int?exclusiveCount(int?c)?{?return?c?&?EXCLUSIVE_MASK;?}

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

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

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

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

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

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

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

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

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

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

          c & EXCLUSIVE_MASK,假設c1,&的過程如下圖

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

          現(xiàn)在有感覺了吧,c的高16位都會變成0,低16位會原樣保留,最終達到獲取低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?????????????//循環(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

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

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

          過程圖如下

          小結(jié)

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

          歷史好文推薦

          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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一区网站 | 色起五月天婷婷玉立亚洲 |