<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                netty在內存分配中大量使用了線程本地緩存,并對ThreadLocal進行了擴展。 ## 9.3.1 java的ThreadLocal **使用** ThreadLocal為每個線程存儲了其對應的副本,下面的例子中,我們啟動多個線程,每個線程保存不同的數據。 ``` public class JavaThreadLocalDemo2 { public static void main(String[] args) { Task task = new Task(); Thread tasks[] = new Thread[10]; for(int i=0;i<10;i++) { tasks[i] = new Thread(task); } for(int i=0;i<10;i++) { tasks[i].start(); } } static class Task implements Runnable{ ThreadLocal<Float> local = new ThreadLocal<Float>(); @Override public void run() { Float process = new Random().nextFloat(); local.set(process); try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) {} System.out.println(Thread.currentThread().getName() +" "+local.get() +" "+ (local.get()==process)); } } } ``` **實現** 每個Thread實例的內部有一個ThreadLocal.ThreadLocalMap對象的實例threadLocals,內部有一個Entry[] table用來保存threadLocal和其對應的Object;每個ThreadLocal有一個唯一的threadLocalHashCode,每次調用set時,先獲取當前線程的ThreadLocalMap,然后使用map的set方法將ThreadLocal和value設置進去。 ``` public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ``` map的set中,首先根據ThreadLocal的哈希值獲取其在table中的位置,如果該位置內容為null,保存到這個元素上即可;如果該位置元素不為null且key為相同ThreadLocal,替換value;如果該位置元素不為null且key為null(出現null的原因是由于Entry的key是繼承了軟引用,在下一次GC時不管它有沒有被引用都會被回收掉,Value不會被回收)。當出現null時,會調用replaceStaleEntry()方法接著循環尋找相同的key,如果存在,直接替換舊值。如果不存在,則在當前位置上重新創建新的Entry。如果該位置元素不為相同ThreadLocal且不為null,說明其他ThreadLocal已經使用,遍歷鏈表查找其他位置。 保存到table之后,cleanSomeSlots會查詢是否有過期的元素,如果有并且大于閥值(超過2/3),執行rehash() ``` private void set(ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); } ``` map的get方法中,獲取當前線程的ThreadLocalMap后,在getEntry中獲取ThreadLocal對于的值。getEntry方法會根據index查找,由于可能發生沖突,會調用getEntryAfterMiss遍歷數組。 ``` public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } ``` 通過對java的ThreadLocal實現的了解,我們可以看到,在set時會發生沖突,會遍歷尋找合適的位置,而在get時如果首次未命中,也會遍歷尋找ThreadLocal對應的值。在Netty高并發中,會有頻繁的讀取,因此Netty自己實現了ThreadLocal以提高效率。 # Netty的ThreadLocal 首先,Netty將線程分為了兩種,一種是Netty實現的可快速存取本地緩存的FastThreadLocalThread,一種是普通的Thread。這點在線程池創建過程中使用的`DefaultThreadFactory`中可以看到,線程池創建的線程都是FastThreadLocalThread。FastThreadLocalThread中有一個變量InternalThreadLocalMap保存本地的相關數據。 在線程中,netty講線程的本地變量都保存在InternalThreadLocalMap中,這個對象看名字是個Map,但其實里面由數組indexedVariables保存設置的本地變量。數組indexedVariables的大小默認為32,每個線程內部都有一個InternalThreadLocalMap的實例,可以設置多個ThreadLocal,這個ThreadLocal不是Java默認的ThreadLocal,而是使用FastThreadLocal,每個FastThreadLocal有一個唯一的Id保存在index中,對應著FastThreadLocalThread內部的InternalThreadLocalMap的位置。因此,netty相比Java的ThreadLocal來說,每個key都有固定的index,這樣不會發生沖突,從而提高了效率。 netty中如果使用的是普通線程的ThreadLocal,那么會在Thread的ThreadLocalMap中保存InternalThreadLocalMap,FastThreadLocal存放在其index對應的位置上。 ![NettyThreadLocal](http://web.uxiaowo.com/netty/Future/ThreadLocal.png) # 測試 CompareJavaTL使用java的ThreadLocal,寫/讀時間為338ms和248ms CompareNettyTL使用Netty的FastThreadLocal,寫/讀時間為283ms和8ms 可見,Netty的ThreadLocal機制在讀寫時效率都要比java的高,根據之前的分析, ``` public class CompareJavaTL { static int count = 100000000; static int times = 100000000; public static void main(String[] args) { ThreadLocal<String> tl = new ThreadLocal<String>(); long begin = System.currentTimeMillis(); for(int i=0;i<count;i++) { tl.set("javatl"); } System.out.println(System.currentTimeMillis()-begin); begin = System.currentTimeMillis(); for(int i=0;i<times;i++) { tl.get(); } System.out.println(System.currentTimeMillis()-begin); } } ``` ``` public class CompareNettyTL { static int count = 100000000; static int times = 100000000; public static void main(String[] args) { new FastThreadLocalThread(new Runnable() { @Override public void run() { FastThreadLocal<String> tl = new FastThreadLocal<String>(); long begin = System.currentTimeMillis(); for(int i=0;i<count;i++) { tl.set("javatl"); } System.out.println(System.currentTimeMillis()-begin); begin = System.currentTimeMillis(); for(int i=0;i<times;i++) { tl.get(); } System.out.println(System.currentTimeMillis()-begin); } }).start(); } } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看