最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中ThreadLocal的使用

 更新時間:2023年09月26日 09:02:06   作者:手寫情書  
這篇文章主要介紹了Java中ThreadLocal的使用,靜態(tài)內(nèi)部類的加載是在程序中調(diào)用靜態(tài)內(nèi)部類的時候加載的,和外部類的加載沒有必然關系, 但是在加載靜態(tài)內(nèi)部類的時候 發(fā)現(xiàn)外部類還沒有加載,那么就會先加載外部類 ,加載完外部類之后,再加載靜態(tài)內(nèi)部類,需要的朋友可以參考下

1.預備知識-靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類的加載時機?他和外部類的加載有沒有什么關系

靜態(tài)內(nèi)部類的加載是在程序中調(diào)用靜態(tài)內(nèi)部類的時候加載的,和外部類的加載沒有必然關系, 但是在加載靜態(tài)內(nèi)部類的時候 發(fā)現(xiàn)外部類還沒有加載,那么就會先加載外部類 ,加載完外部類之后,再加載靜態(tài)內(nèi)部類.(初始化靜態(tài)變量和靜態(tài)代碼塊etc),如果在程序中單純的使用 外部類,并不會觸發(fā)靜態(tài)內(nèi)部類的加載

擴展 :

一個類內(nèi)部有靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類 , 靜態(tài)內(nèi)部類和非靜態(tài)內(nèi)部類一樣,都是在被調(diào)用時才會被加載 ,不過在加載靜態(tài)內(nèi)部類的過程中如果沒有加載外部類,也會加載外部類,靜態(tài)變量,靜態(tài)方法,靜態(tài)塊等都是類級別的屬性,而不是單純的對象屬性.他們在類第一次被使用時被加載 (記住,是一次使用,不一定是實例化),我們可以簡單得用 類名.變量 或者 類名.方法來調(diào)用它們, 與調(diào)用沒有被static 修飾過變量和方法不同的是:一般變量和方法是用當前對象的引用(即this)來調(diào)用的, 靜態(tài)的方法和變量則不需要.從一個角度上來說,它們是共享給所有對象的,不是一個角度私有. 這點上,靜態(tài)內(nèi)部類也是一樣的

類的加載時機:(暫時的認知里是四種) new 一個類的時候,調(diào)用類內(nèi)部的 靜態(tài)變量,調(diào)用類的靜態(tài)方法,調(diào)用類的 靜態(tài)內(nèi)部類

public class OuterClass {
    public static String OUTER_DATE = "外部類靜態(tài)變量加載時間 "+System.currentTimeMillis();
    static {
        System.out.println("外部類靜態(tài)塊加載時間:" + System.currentTimeMillis());
    }
    public OuterClass() {
        System.out.println("外部類構造函數(shù)時間:" + System.currentTimeMillis());
    }
    static class InnerStaticClass{
        public static String INNER_STATIC_DATE = "靜態(tài)內(nèi)部類靜態(tài)變量加載時間 "+System.currentTimeMillis();
        private String name;
        static {
            System.out.println("靜態(tài)內(nèi)部類靜態(tài)代碼塊加載時間:" + System.currentTimeMillis());
        }
    }
    class InnerClass {
        public String INNER_DATE = "";
        public InnerClass() {
            INNER_DATE = "非靜態(tài)內(nèi)部類構造器加載時間"+System.currentTimeMillis();
        }
    }
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        System.out.println("非靜態(tài)內(nèi)部類加載時間: "+outer.new InnerClass().INNER_DATE);
        /**
         * 內(nèi)部靜態(tài)類可以直接用,不需要new
         * 靜態(tài)內(nèi)部類的加載是代碼中需要靜態(tài)內(nèi)部類的時候才加載,而不是和外部類一起加載的
         * 加載靜態(tài)內(nèi)部類之前,先把外部類的靜態(tài)變量和靜態(tài)代碼塊先執(zhí)行完
         * 執(zhí)行完外部類的代碼后,再執(zhí)行靜態(tài)內(nèi)部類的 靜態(tài)變量和靜態(tài)代碼塊
         * 靜態(tài)內(nèi)部類的 靜態(tài)變量和靜態(tài)代碼塊執(zhí)行完后,然后執(zhí)行業(yè)務代碼
         * new  外部類的時候 。外部類的靜態(tài)代碼塊和靜態(tài)變量先執(zhí)行,外部類構造函數(shù)后執(zhí)行
         */
        System.out.println("靜態(tài)內(nèi)部類加載時間____:"+InnerStaticClass.INNER_STATIC_DATE);
    }
}
//什么時候考慮使用靜態(tài)內(nèi)部類?
//A類中需要一個B類,但是B類只為A類服務,這種情況不需要將B類單獨剝離,只需要在A內(nèi)部即可
//一個類的構建有非常多參數(shù)或者十分復雜的一個對象的時候--引申到了建造者模式

2.ThredLocal

2.1ThrealLocal簡介

ThrealLocal叫做現(xiàn)成變量,意思就是ThradLocal中填充的變量屬于當前線程,該變量對其他線程而言是隔離的,也就是說該變量是當前線程獨有的變量.ThradLocal為變量在每個線程中都創(chuàng)建了副本,那么每個線程可訪問自己內(nèi)部的副本變量.

  • 因為每個Thread內(nèi)有自己的實例副本,且副本只能由當前Thread使用.這也是ThreadLocal命名的由來
  • 既然每個Thred都有自己的實例副本,且其他Thread不可訪問,那么不存在多線程的共享問題

總的來說,ThredLocal適用于每個線程需要自己獨立的實例且該實例需要在多個方法中被使用,也即變量在線程隔離而在方法或類間共享的場景

在這里插入圖片描述

2.2 ThreadLocal與Synchronized的區(qū)別

ThreadLocal其實是與線程綁定的一個變量.ThreadLocal和Synchonized都用于解決多線程并發(fā)訪問

但是ThreadLocal與synchronized有本質(zhì)的區(qū)別 :

  • Synchronized用于線程間的數(shù)據(jù)共享,而ThreadLocal則用于線程間的數(shù)據(jù)隔離
  • Synchronized是利用鎖的機制,使變量或代碼塊在某一時刻只能被一個線程訪問.而ThredLocal為每一個線程提供了變量的副本,使得每個線程某一個時間訪問到的不是同一個對象,這樣就隔離了多個現(xiàn)線程歲數(shù)據(jù)的共享, 而Synchronized卻正好相反,它用于在多個線程間通信時能夠獲得數(shù)據(jù)共享

一句話理解ThreadLocal,向ThreadLocal里面存東西就是向它里面的Map存東西的,然后ThreadLocal把這個Map掛到當前的線程底下,這樣Map就只屬于這個線程了

2.3 ThreadLocal的簡單使用

public class ThreadLocaDemo {
    private static ThreadLocal<String> localVar = new ThreadLocal<String>();
    static void print(String str) {
        //打印當前線程中本地內(nèi)存中本地變量的值
        System.out.println(str + " :" + localVar.get());
        //清除本地內(nèi)存中的本地變量
        localVar.remove();
    }
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            public void run() {
                ThreadLocaDemo.localVar.set("local_A");
                print("A");
                //打印本地變量
                System.out.println("after remove : " + localVar.get());
            }
        },"A").start();
        Thread.sleep(1000);
        new Thread(new Runnable() {
            public void run() {
                ThreadLocaDemo.localVar.set("local_B");
                print("B");
                System.out.println("after remove : " + localVar.get());
            }
        },"B").start();
    }
}

2.4ThrealLocal的內(nèi)存泄漏問題

 public void set(T value) {
        //1、獲取當前線程
        Thread t = Thread.currentThread();
        //2、獲取線程中的屬性 threadLocalMap ,如果threadLocalMap 不為空,
        //則直接更新要保存的變量值,否則創(chuàng)建threadLocalMap,并賦值
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            // 初始化thradLocalMap 并賦值
            createMap(t, value);
    }
  static class ThreadLocalMap {
        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
    }

可看出ThreadLocalMap是ThreadLocal的內(nèi)部靜態(tài)類,而它的構成主要是用Entry來保存數(shù)據(jù) ,而且還是繼承的弱引用.在Entry內(nèi)部使用ThreadLocal作為key,使用我們設置的value作為value.

//這個是threadlocal 的內(nèi)部方法
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    //ThreadLocalMap 構造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }
    public T get() {
        //1、獲取當前線程
        Thread t = Thread.currentThread();
        //2、獲取當前線程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //3、如果map數(shù)據(jù)為空,
        if (map != null) {
            //3.1、獲取threalLocalMap中存儲的值
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果是數(shù)據(jù)為null,則初始化,初始化的結果,TheralLocalMap中存放key值為threadLocal,值為null
        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 remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

remove方法,直接將ThrealLocal 對應的值從當前相差Thread中的ThreadLocalMap中刪除.為什么要刪除,這涉及到內(nèi)存泄露的問

實際上 ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用,弱引用的特點是,如果這個對象只存在弱引用,那么在下一次垃圾回收的時候必然會被清理掉

所以如果 ThreadLocal 沒有被外部強引用的情況下,在垃圾回收的時候會被清理掉的,這樣一來 ThreadLocalMap中使用這個 ThreadLocal 的 key 也會被清理掉。但是,value 是強引用,不會被清理,這樣一來就會出現(xiàn) key 為 null 的 value

ThreadLocal其實是與線程綁定的一個變量,如此就會出現(xiàn)一個問題:如果沒有將ThreadLocal內(nèi)的變量刪除(remove)或替換,它的生命周期將會與線程共存。通常線程池中對線程管理都是采用線程復用的方法,在線程池中線程很難結束甚至于永遠不會結束,這將意味著線程持續(xù)的時間將不可預測,甚至與JVM的生命周期一致。舉個例字,如果ThreadLocal中直接或間接包裝了集合類或復雜對象,每次在同一個ThreadLocal中取出對象后,再對內(nèi)容做操作,那么內(nèi)部的集合類和復雜對象所占用的空間可能會開始持續(xù)膨脹

在這里插入圖片描述

在這里插入圖片描述

我從這個圖中我們可以非常直觀的看出,ThreadLocalMap其實是Thread線程的一個屬性值,而ThreadLocal是維護ThreadLocalMap這個屬性指的一個工具類。

Thread線程可以擁有多個ThreadLocal維護的自己線程獨享的共享變量(這個共享變量只是針對自己線程里面共享)

到此這篇關于Java中ThreadLocal的使用的文章就介紹到這了,更多相關ThreadLocal的使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

宝鸡市| 祥云县| 绥江县| 通州市| 祁门县| 教育| 天全县| 光山县| 顺昌县| 绿春县| 炎陵县| 土默特左旗| 上思县| 民县| 海淀区| 乌兰察布市| 西丰县| 阜新市| 奉贤区| 霸州市| 商水县| 邹城市| 淳化县| 邯郸县| 克东县| 永昌县| 博客| 泸溪县| 义乌市| 壶关县| 泗洪县| 大城县| 临武县| 灵川县| 舞钢市| 无棣县| 康定县| 台南县| 抚顺县| 敦化市| 桃源县|