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

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ThreadLocal是什么呢?其實ThreadLocal不是一個線程的本地實現版本,也不是一個Thread。 ThreadLocal的目的就是為每一個使用ThreadLocal的線程都提供一個值, 讓該值和使用它的線程綁定,當然每一個線程都可以獨立地改變它綁定的值。 主要函數 | Public Methods | | | | | -- | -- | | T | get()<br/>Returns the value of this variable for the current thread.<br/>返回當前線程的線程局部變量副本| | void | remove()<br/>Removes the entry for this variable in the current thread.<br/>如果我們想把ThreadLocal所綁定的對象的引用清空,請不要粗暴的把ThreadLocal設置null,而應該調用remove()方法| | void |set(T value)<br/>Sets the value of this variable for the current thread.設置當前線程的線程局部變量副本的值 ?| | Protected Methods | | | | | -- | -- | | T | initialValue()<br/> Provides the initial value of this variable for the current thread.<br/>該方法返回當前線程在該線程局部變量的初始值。這個方法是一個延遲調用方法,在一個線程第1次調用get()且此時還沒調用set(Object)時才執行,并且僅執行1次。ThreadLocal中返回的是null。該方法是一個protected的方法,它主要是為設置局部變量的初始值提供方便。| ThreadLocal是如何做到讓每一個線程和一個值綁定的呢? 其實實現的思路很簡單,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。 比如下面的示例實現: 示例1: ~~~ public?class?ThreadLocal?{?? ??private?Map?values?=?Collections.synchronizedMap(new?HashMap());? ??public?Object?get()?{? ????Thread?curThread?=?Thread.currentThread();? ????Object?o?=?values.get(curThread);? ????if?(o?==?null?&&?!values.containsKey(curThread))?{? ??????o?=?initialValue();? ??????values.put(curThread,?o);? ????}? ????return?o;? ??}? ??public?void?set(Object?newValue)?{? ????values.put(Thread.currentThread(),?newValue);? ??}? ??public?Object?initialValue()?{? ????return?null;? ??}? }? ~~~ 注意:以上只是一個粗略的實現。我覺得上面的沒有必要使用Collections.synchronizedMap。 因為不同的線程不可能對HashMap的同一項進行操作。 在JDK中的ThreadLocal的實現感覺很巧妙: 下面是去掉了注釋后ThreadLocal的代碼 ~~~ public?class?ThreadLocal?{ ????private?final?int?threadLocalHashCode?=?nextHashCode(); ???????private?static?AtomicInteger?nextHashCode?=? ????????new?AtomicInteger(); ????private?static?final?int?HASH_INCREMENT?=?0x61c88647; ???private?static?int?nextHashCode()?{ ????????return?nextHashCode.getAndAdd(HASH_INCREMENT);? ????} ????protected?T?initialValue()?{ ????????return?null; ????} ????public?ThreadLocal()?{ ????} ???????public?T?get()?{ ????????Thread?t?=?Thread.currentThread(); ????????ThreadLocalMap?map?=?getMap(t); ????????if?(map?!=?null)?{ ????????????ThreadLocalMap.Entry?e?=?map.getEntry(this); ????????????if?(e?!=?null) ????????????????return?(T)e.value; ????????} ????????return?setInitialValue(); ????} ????private?T?setInitialValue()?{ ????????T?value?=?initialValue(); ????????Thread?t?=?Thread.currentThread(); ????????ThreadLocalMap?map?=?getMap(t); ????????if?(map?!=?null) ????????????map.set(this,?value); ????????else ????????????createMap(t,?value); ????????return?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); ????} ?????public?void?remove()?{ ?????????ThreadLocalMap?m?=?getMap(Thread.currentThread()); ?????????if?(m?!=?null) ?????????????m.remove(this); ?????} ????ThreadLocalMap?getMap(Thread?t)?{ ????????return?t.threadLocals; ????} ????void?createMap(Thread?t,?T?firstValue)?{ ????????t.threadLocals?=?new?ThreadLocalMap(this,?firstValue); ????} ????static?ThreadLocalMap?createInheritedMap(ThreadLocalMap?parentMap)?{ ????????return?new?ThreadLocalMap(parentMap); ????} ???????T?childValue(T?parentValue)?{ ????????throw?new?UnsupportedOperationException(); ????} ~~~ 注意1:每個線程有個ThreadLocalMap?threadLocals,它是把ThreadLocal作為threadLocals鍵值在使用的。這點比示例1的算法先進多。它沒有了同步問題。因為它被創建后根本就沒讀寫操作。 注意2:ThreadLocalMap就在ThreadLocal中,但是它并沒有使用HashMap,它使用的算法有復雜,沒看明白。 注意3:如果我們對hashcode不是通過該對象的成員生成,而是使其自動生成時,且采用取余形式得到哈希值,增量(HASH_INCREMENT)最好是個素數。這樣增量的才不能被任何才小于取余值(哈希表的長度)整除,否則會哈希到同一個桶中。 ThreadLocalMap中就是對hashcode取余的方式得到哈希值的。 ~~~ int?len?=?tab.length; int?i?=?key.hashCode?&?(len-1); ~~~ 因為 ~~~ ??/** ???*?The?initial?capacity?--?MUST?be?a?power?of?two. ???*/ ??private?static?final?int?INITIAL_CAPACITY?=?16; ~~~ 所以上面的"int?i?=?key.hashCode?&?(len-1);"相當于"int?i?=?key.hashCode?%len;" 雖然"HASH_INCREMENT"不是個素數,但是它卻不能被tab.length(它等于2的n此方且大于等于16)被整除的。 注意4:ThreadLocalMap中采用的是弱引用 ~~~ ??static?class?Entry?extends?WeakReference?{ ????????????/**?The?value?associated?with?this?ThreadLocal.?*/ ????????????Object?value; ????????????Entry(ThreadLocal?k,?Object?v)?{ ????????????????super(k); ????????????????value?=?v; ????????????} ????????} ~~~ 注意5:JDK為什么不使用hashMap或WeakHashMap,而是自己寫了ThreadLocalMap。應該主要是為提供了對不同key(這里是ThreadLocal)對象的但hashCode相同的存儲的支持。 如果希望線程局部變量初始化其它值,那么需要自己實現ThreadLocal的子類并重寫initialValue()該方法, 通常使用一個內部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類為每一個類分配一個序號: Java代碼 ~~~ public?class?SerialNum?{?: ??????//?The?next?serial?number?to?be?assigned? ??????private?static?int?nextSerialNum?=?0;? ??? ??????private?static?ThreadLocal?serialNum?=?new?ThreadLocal()?{? ??????????protected?synchronized?Object?initialValue()?{? ??????????????return?new?Integer(nextSerialNum++);? ??????????}? ??????};? ??? ??????public?static?int?get()?{? ??????????return?((Integer)?(serialNum.get())).intValue();? ??????}? ??}? ~~~ SerialNum類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當前線程的序號時,簡單地調用: Java代碼 ????int?serial?=?SerialNum.get();? 即可。 使用方法一 Hibernate的文檔中關于使ThreadLocal管理多線程訪問的部分。 具體代碼如下 ~~~ ??public?static?final?ThreadLocal?session?=?new?ThreadLocal(); ??public?static?Session?currentSession()?{ ??????Session?s?=?(Session)session.get(); ??????//open?a?new?session,if?this?session?has?none ???if(s?==?null){ ??????s?=?sessionFactory.openSession(); ??????session.set(s); ???} ??????return?s; ?} ~~~ 我們逐行分析 1。?初始化一個ThreadLocal對象,ThreadLocal有三個成員方法?get()、set()、initialvalue()。 ????如果不初始化initialvalue,則initialvalue返回null。 3。?session的get根據當前線程返回其對應的線程內部變量,也就是我們需要的net.sf.hibernate.Session(相當于對應每個數據庫連接). 多線程情況下共享數據庫鏈接是不安全的。ThreadLocal保證了每個線程都有自己的s(數據庫連接)。 5。如果是該線程初次訪問,自然,s(數據庫連接)會是null,接著創建一個Session,具體就是行6。 6。創建一個數據庫連接實例?s 7。保存該數據庫連接s到ThreadLocal中。 8。如果當前線程已經訪問過數據庫了,則從session中get()就可以獲取該線程上次獲取過的連接實例。 使用方法二 當要給線程初始化一個特殊值時,需要自己實現ThreadLocal的子類并重寫該方法, 通常使用一個內部匿名類對ThreadLocal進行子類化,EasyDBO中創建jdbc連接上下文就是這樣做的: ~~~ public?class?JDBCContext{ ?private?static?Logger?logger?=?Logger.getLogger(JDBCContext.class); ?private?DataSource?ds; ?protected?Connection?connection; ?private?boolean?isValid?=?true; ?private?static?ThreadLocal?jdbcContext; ? ?private?JDBCContext(DataSource?ds){ ??this.ds?=?ds; ??createConnection();?? ?} ?public?static?JDBCContext?getJdbcContext(javax.sql.DataSource?ds) ?{?? ??if(jdbcContext==null)jdbcContext=new?JDBCContextThreadLocal(ds); ??JDBCContext?context?=?(JDBCContext)?jdbcContext.get(); ??if?(context?==?null)?{ ???context?=?new?JDBCContext(ds); ? ? jdbcContext.set(context); ??} ??return?context; ?} ?private?static?class?JDBCContextThreadLocal?extends?ThreadLocal?{ ??public?javax.sql.DataSource?ds; ??public?JDBCContextThreadLocal(javax.sql.DataSource?ds) ??{ ???this.ds=ds; ??} ??protected?synchronized?Object?initialValue()?{ ???return?new?JDBCContext(ds); ??} ?} } ~~~ 使用單例模式,不同的線程調用getJdbcContext()獲得自己的jdbcContext, 都是通過JDBCContextThreadLocal內置子類來獲得JDBCContext對象的線程局部變量 總結 ????ThreadLocal和同步機制,兩者面向的問題領域不同。 ????同步機制是為了同步多個線程對相同資源的并發訪問,是為了多個線程之間進行通信的有效方式;????而ThreadLocal是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源(變量),這樣當然不需要對多個線程進行同步了。 ????所以,如果你需要進行多個線程之間進行通信,則使用同步機制;如果需要隔離多個線程之間的共享沖突,可以使用ThreadLocal,這將極大地簡化你的程序,使程序更加易讀、簡潔。 如果我們想把ThreadLocal所綁定的對象的引用清空,請不要粗暴的把ThreadLocal引用設置null,而應該調用remove()方法。否則會造成內存泄露。關于此的更多內容請參考《**[ThreadLocal的內存泄露](http://hubingforever.blog.163.com/blog/static/1710405792011102411334093/ "閱讀全文")**》
                  <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>

                              哎呀哎呀视频在线观看