真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

java中的ThreadLocal是什么

這篇文章將為大家詳細講解有關java中的ThreadLocal是什么,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

成都創(chuàng)新互聯(lián)于2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術服務公司,擁有項目成都網(wǎng)站建設、網(wǎng)站設計網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元光澤做網(wǎng)站,已為上家服務,為光澤各地企業(yè)和個人服務,聯(lián)系電話:13518219792

簡單介紹

ThreadLocal一般稱為線程本地變量,它是一種特殊的線程綁定機制,將變量與線程綁定在一起,為每一個線程維護一個獨立的變量副本。通過ThreadLocal可以將對象的可見范圍限制在同一個線程內(nèi)。

跳出誤區(qū)

需要重點強調的的是,不要拿ThreadLocal和synchronized做類比,因為這種比較壓根就是無意義的!sysnchronized是一種互斥同步機制,是為了保證在多線程環(huán)境下對于共享資源的正確訪問。而ThreadLocal從本質上講,無非是提供了一個“線程級”變量作用域,它是一種線程封閉(每個線程獨享變量)技術,更直白點講,ThreadLocal可以理解為將對象的作用范圍限制在一個線程上下文中,使得變量的作用域為“線程級”。

沒有ThreadLocal的時候,一個線程在其生命周期內(nèi),可能穿過多個層級,多個方法,如果有個對象需要在此線程周期內(nèi)多次調用,且是跨層級的(線程內(nèi)共享),通常的做法是通過參數(shù)進行傳遞;而ThreadLocal將變量綁定在線程上,在一個線程周期內(nèi),無論“你身處何地”,只需通過其提供的get方法就可輕松獲取到對象。極大地提高了對于“線程級變量”的訪問便利性。

來看個簡單的例子

假設我們要為每個線程關聯(lián)一個唯一的序號,在每個線程周期內(nèi),我們需要多次訪問這個序號,這時我們就可以使用ThreadLocal了.(當然下面這個例子沒有完全體現(xiàn)出跨層級跨方法的調用,理解就可以了)

package concurrent;

import java.util.concurrent.atomic.AtomicInteger;

/**
* Created by chengxiao on 2016/12/12.
*/
public class ThreadLocalDemo {
   public static void main(String []args){
       for(int i=0;i<5;i++){
           final Thread t = new Thread(){
               @Override
               public void run(){
                   System.out.println("當前線程:"+
                   Thread.currentThread().getName()+",已分配ID:"
                   +ThreadId.get());
               }
           };
           t.start();
       }
   }
   static   class ThreadId{
       //一個遞增的序列,使用AtomicInger原子變量保證線程安全
       private static final AtomicInteger nextId = new AtomicInteger(0);
       //線程本地變量,為每個線程關聯(lián)一個唯一的序號
       private static final ThreadLocal threadId =
               new ThreadLocal() {
                   @Override
                   protected Integer initialValue() {
                       return nextId.getAndIncrement();//相當于nextId++,
                       由于nextId++這種操作是個復合操作而非原子操作,
                       會有線程安全問題(可能在初始化時就獲取到相同的ID,
                       所以使用原子變量
                   }
               };

      //返回當前線程的唯一的序列,如果第一次get,會先調用initialValue,
      后面看源碼就了解了
       public static int get() {
           return threadId.get();
       }
   }
}

執(zhí)行結果,可以看到每個線程都分配到了一個唯一的ID,同時在此線程范圍內(nèi)的"任何地點",我們都可以通過ThreadId.get()這種方式直接獲取。

當前線程:Thread-4,已分配ID:1
當前線程:Thread-0,已分配ID:0
當前線程:Thread-2,已分配ID:3
當前線程:Thread-1,已分配ID:4
當前線程:Thread-3,已分配ID:2

 set操作,為線程綁定變量

public void set(T value) {
   //1.首先獲取當前線程對象
   Thread t = Thread.currentThread();
   //2.獲取該線程對象的ThreadLocalMap
   ThreadLocalMap map = getMap(t);
   //如果map不為空,執(zhí)行set操作,以當前threadLocal對象為key,
   //實際存儲對象為value進行set操作
   if (map != null)
       map.set(this, value);
   else
   //如果map為空,則為該線程創(chuàng)建ThreadLocalMap
       createMap(t, value);
}

可以看到,ThreadLocal不過是個入口,真正的變量是綁定在線程上的。

ThreadLocalMap getMap(Thread t) {
//線程對象持有ThreadLocalMap的引用
   return t.threadLocals;
}

下面給是Thread類中的定義,每個線程對象都擁有一個ThreadLocalMap對象

ThreadLocal.ThreadLocalMap threadLocals = null;

現(xiàn)在,我們能看出ThreadLocal的設計思想了:

1.ThreadLocal僅僅是個變量訪問的入口;

2.每一個Thread對象都有一個ThreadLocalMap對象,這個ThreadLocalMap持有對象的引用;

3.ThreadLocalMap以當前的threadlocal對象為key,以真正的存儲對象為value。get時通過threadlocal實例就可以找到綁定在當前線程上的對象。

乍看上去,這種設計確實有些繞。我們完全可以在設計成Map這種形式,一個線程對應一個存儲對象。

ThreadLocal這樣設計的目的主要有兩個:

一是可以保證當前線程結束時相關對象能盡快被回收;

二是ThreadLocalMap中的元素會大大減少,我們都知道m(xù)ap過大更容易造成哈希沖突而導致性能變差。

我們再來看看get方法

public T get() {
//1.首先獲取當前線程
Thread t = Thread.currentThread();
//2.獲取線程的map對象
ThreadLocalMap map = getMap(t);
//3.如果map不為空,以threadlocal實例為key
//獲取到對應Entry,然后從Entry中取出對象即可。
if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this);
    if (e != null)
        return (T)e.value;
}
//如果map為空,也就是第一次沒有調用set直接get
//(或者調用過set,又調用了remove)時,為其設定初始值
return setInitialValue();
}

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

initialValue方法,默認是null,訪問權限是protected,即允許重寫。

protected T initialValue() {
return null;
}

 談到這兒,我們應該已經(jīng)對ThreadLocal的設計目的及設計思想有一定的了解了。

還有一個會引起疑惑的問題,我們說ThreadLocal為每一個線程維護一個獨立的變量副本,那么是不是說各個線程之間真正的做到對于對象的“完全自治”而不對其他線程的對象產(chǎn)生影響呢?其實這已經(jīng)不屬于對于ThreadLocal的討論,而是你出于何種目的去使用ThreadLocal。如果我們?yōu)橐粋€線程關聯(lián)的對象是“完全獨享”的,也就是每個線程擁有一整套的新的 棧中的對象引用+堆中的對象,那么這種情況下是真正的徹底的“線程獨享變量”,相當于一種深度拷貝,每個線程自己玩自己的,對該對象做任何的操作也不會對別的線程有任何影響。

另一種更普遍的情況,所謂的獨享變量副本,其實也就是每個線程都擁有一個獨立的對象引用,而堆中的對象還是線程間共享的,這種情況下,自然還是會涉及到對共享資源的訪問操作,依然會有線程不安全的風險。所以說,ThreadLocal無法解決線程安全問題。

所以,需不需要完全獨享變量,進行完全隔離,就取決于你的應用場景了??梢韵胂?,對象過大的時候,如果每個線程都有這么一份“深拷貝”,并發(fā)又比較大,對于服務器的壓力自然是很大的。像web開發(fā)中的servlet,servlet是線程不安全的,一請求一線程,多個線程共享一個servlet對象;而早期的CGI設計中,N個請求就對應N個對象,并發(fā)量大了之后性能自然就很差。

java中的ThreadLocal是什么

ThreadLocal使用注意

ThreadLocal的出現(xiàn)是一種空間換時間的思想的運用,是為了多線程環(huán)境下單線程內(nèi)變量共享的問題。它的原理就是每個線程通過ThreadLocal.ThreadLocalMap,保存當前線程中所有ThreadLocal變量引用的key和值。相當于每個線程有各自的變量副本,線程內(nèi)共享這個變量數(shù)據(jù),線程間互不影響。

ThreadLocal有它自己的使用場景,比如Spring中用它了解決Session、Connection等多線程并發(fā)訪問問題,但不能它不能用來代替為了解決多線程安全問題的同步關鍵字,因為它實際上沒有多線程間的變量共享,而線程安全問題是指多線程間變量共享,且共享變量可修改,進而可能會出現(xiàn)多線程并發(fā)修改共享變量的問題,這種需要通過同步手段解決。

ThreadLocal變量一般要聲名成static類型,即當前線程中只有一個T類型變量的實例,線程內(nèi)可共享該實例數(shù)據(jù)且不會出問題,如將其聲名成非static,則一個線程內(nèi)就存儲多個T類型變量的實例,有點存儲空間的浪費,一般很少有這樣的應用場景。另外根據(jù)實際情況,ThreadLocal變量聲名時也多加上private final關鍵詞表明它時類內(nèi)私有、引用不可修改。

在線程池環(huán)境下,由于線程是一直運行且復用的,使用ThreadLocal時會出現(xiàn)這個任務看到上個任務ThreadLocal變量值以及內(nèi)存泄露等問題,解決方法就是在當前任務執(zhí)行完后將ThreadLocal變量remove或設置為初始值,類似在Struts2 框架中Filter里的處理方法。

Spark中如何使用ThreadLocal的呢?

spark使用的是InheritableThreadLocal,該類擴展了 ThreadLocal,為子線程提供從父線程那里繼承的值:在創(chuàng)建子線程時,子線程會接收所有可繼承的線程局部變量的初始值,以獲得父線程所具有的值。通常,子線程的值與父線程的值是一致的;但是,通過重寫這個類中的 childValue 方法,子線程的值可以作為父線程值的一個任意函數(shù)。

當必須將變量(如用戶 ID 和 事務 ID)中維護的每線程屬性(per-thread-attribute)自動傳送給創(chuàng)建的所有子線程時,應盡可能地采用可繼承的線程局部變量,而不是采用普通的線程局部變量。

InheritableThreadLocal,在spark中主要有三個地方用到:

1,SparkContext內(nèi)部

java中的ThreadLocal是什么

2,DynamicVariable內(nèi)部

動態(tài)變量是scala的特性

java中的ThreadLocal是什么

3,InputFileBlockHolder內(nèi)部

java中的ThreadLocal是什么

關于“java中的ThreadLocal是什么”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。


本文標題:java中的ThreadLocal是什么
URL網(wǎng)址:http://weahome.cn/article/gcshhs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部