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

          Unsafe.putOrderedXXX系列方法詳解(數(shù)組賦值的第二種方式)

          共 3188字,需瀏覽 7分鐘

           ·

          2021-06-02 11:42

          在Netty中,IO線程用于存儲任務(wù)的容器是MpscUnboundedArrayQueue類.
          所有對外的讀寫操作,都'委托'給IO線程來執(zhí)行,非IO線程(比如業(yè)務(wù)線程)若要寫數(shù)據(jù),必須將寫操作封裝成一個任務(wù),提交到IO線程的任務(wù)隊列中.IO線程會擇機(jī)執(zhí)行任務(wù)隊列中的任務(wù),將數(shù)據(jù)寫入到網(wǎng)絡(luò)(實際只是寫到TCP緩沖區(qū)). 那么這個任務(wù)隊列就很重要了,它必須是高性能的. 在Netty以前的版本中,使用JDK的BlockingQueue實現(xiàn)這個任務(wù)隊列,而Netty是一個追求性能極致的框架(不被規(guī)則和常規(guī)所束縛),目前選擇jctools這個工具包中的MpscUnboundedArrayQueue類實現(xiàn)任務(wù)隊列.


          這個MpscUnboundedArrayQueue隊列很特別,它是數(shù)組和鏈表的結(jié)合.但是它不是哈希,它的結(jié)構(gòu)類似下面這樣




          同等大小的數(shù)組之間通過鏈表方式連接.


          MpscUnboundedArrayQueue<Integer> queue = new MpscUnboundedArrayQueue<>(4);
          new Thread(() -> { while (true) { try { for (int i = 1; i < 100; i++) { Thread.sleep(3000); queue.offer(i); } } catch (InterruptedException e) { e.printStackTrace(); } }}, "生產(chǎn)者-1").start();

          new Thread(() -> { while (true) { try { for (int i = 200; i < 300; i++) { Thread.sleep(2000); queue.offer(i); } } catch (InterruptedException e) { e.printStackTrace(); } }}, "生產(chǎn)者-2").start();
          new Thread(() -> { while (true) { try { for (int i = 300; i < 400; i++) { Thread.sleep(1000); queue.offer(i); } } catch (InterruptedException e) { e.printStackTrace(); } }}, "生產(chǎn)者-3").start();



          以上3個生產(chǎn)者向隊列中'生產(chǎn)'數(shù)據(jù),過了一會,通過dump堆信息.再通過Eclipse MAT查看堆信息.



          如上圖,展開數(shù)組,可以看到它的結(jié)構(gòu)是一個數(shù)組'鏈'一個數(shù)組.


          當(dāng)非IO線程提交任務(wù)的時候,就需要向數(shù)組中存儲元素值.那么它是如何給數(shù)組賦值的呢?

          一般情況,給數(shù)組賦值如下


          int[] arr = new int[8];arr[3] = 9527;



          而MpscUnboundedArrayQueue類中,是通過Unsafe.putOrderedXXX系列的方法,給數(shù)組賦值的.



          如并發(fā)中的CAS, 內(nèi)存申請, 線程阻塞和解除阻塞park/unpark, 以及putOrderedXXX等等, 都是Unsafe類提供的方法.




          在此之前,先研究下對象的內(nèi)存布局.



          面試題



          Object obj = new Object()在內(nèi)存中占用多少字節(jié)?



          Java對象是由markword,類型指針,數(shù)組長度(如果對象是數(shù)組的話),實例數(shù)據(jù),對齊空間等組成.如下圖



          我們以數(shù)組為例

          int[] arr = new int[7];


          通過代碼驗證, int[]數(shù)組的內(nèi)存布局情況.

          依賴的包

          <dependency>      <groupId>org.openjdk.jol</groupId>      <artifactId>jol-core</artifactId>      <version>0.9</version></dependency>


          import org.openjdk.jol.info.ClassLayout;
          public class Example {
          public static void main(String[] args) { int[] arr = new int[7]; System.out.println(ClassLayout.parseInstance(arr).toPrintable());
          }}


          同時設(shè)置虛擬機(jī)參數(shù) -XX:+UseCompressedClassPointers ,表示啟用壓縮類指針, 比如在64位系統(tǒng)上,一個指針占用8字節(jié),啟用這個參數(shù)之后,指針占用4字節(jié).

          打印結(jié)果如下


          根據(jù)內(nèi)存布局,我們可以知道數(shù)組的第一個元素距離起始位置4+4+4+4 = 16個字節(jié).



          如上圖,[I表示int數(shù)組含義,具體映射關(guān)系,可以直接參數(shù)OpenJDK源碼.



          在Unsafe類中有個arrayBaseOffset方法,就是用來返回數(shù)組中第一個元素的偏移地址,驗證代碼如下.



          輸出16,與上面查看對象內(nèi)存布局的結(jié)果是一致的.

          如果要修改數(shù)組中的某一個元素,要知道3個值
          1.數(shù)組首地址
          2.第一個元素偏移地址
          3.每個元素的大小

          在學(xué)習(xí)C語言的時候,經(jīng)??M繞耳邊的一句話是'數(shù)組名表示數(shù)組首地址', 在Java中,數(shù)組名也是數(shù)組首地址.
          通過unsafe.arrayBaseOffset可以獲取第一個元素偏移地址.
          在Java中,int占4字節(jié),double占8字節(jié)等等.通過unsafe.arrayIndexScale方法可以獲取數(shù)組中元素占用的大小,代碼如下.


          通過以上的分析,最后得到如下一張圖.




          有了數(shù)組首地址,第一個元素偏移地址和元素大小,就可以指向數(shù)組的任意元素的地址,也就可以修改元素了.

          有了以上的基礎(chǔ)知識,接下來就是本文要說的方法Unsafe.putOrderedXXX(...).


          如上圖,通過unsafe.putOrderedXXX(...)給第2個元素賦值450.


          unsafe.putOrderedLong(a, offset, 450);


          第一個參數(shù)a是數(shù)組的名稱,即數(shù)組首地址, 第二個參數(shù)offset是計算得到,即第二個元素距離首地址的偏移地址, 第三個元素450是要賦的值.

          在jctools工具類中的org.jctools.queues.BaseMpscLinkedArrayQueue#offer方法就是向數(shù)組中存儲元素的核心方法,它如何存儲元素的核心代碼如下.


          調(diào)用的方法就是unsafe.putOrderedXXX(...).





          瀏覽 43
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(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>
                  日韩另类在线观看 | 想要XX网站入口 | 亚洲精品国产免费 | 日本福利片 | 国产一级a毛一级a看免费人交 |