91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java中的ThreadLocal能干什么

發布時間:2022-01-20 13:45:47 來源:億速云 閱讀:112 作者:清風 欄目:開發技術

這篇“java中的ThreadLocal能干什么”文章,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要參考一下,對于“java中的ThreadLocal能干什么”,小編整理了以下知識點,請大家跟著小編的步伐一步一步的慢慢理解,接下來就讓我們進入主題吧。

    ThreadLocal是什么?它能干什么?

    在闡述ThreadLocal之前,我們先來看下它的設計者是怎么描述ThreadLocal的吧。

    java中的ThreadLocal能干什么

    看完官方的描述后,結合自己的理解,ThreadLocal提供了一種對應獨立線程內的數據訪問機制,實現了變量在線程之間隔離,在線程生命周期內獨立獲取或者設置的能力。如果我們想在線程內傳遞參數但是有不想作為方法參數的時候,ThreadLocal就可以排上用場了。不過值得注意的是ThreadLocal并不會解決變量共享問題。實際上從ThreadLocal的名稱上面來看,線程本地變量也已經大致說明了它的作用,所以變量的命名還是非常重要的,要做到顧名思義。如果覺得還不是很理解,沒關系,我們可以通過以下的場景再加深下理解。

    假如有以下的場景,假設只有一個數據庫連接,客戶端1、2、3都需要獲取數據庫連接來進行具體的數據庫操作,但是同一時間點只能有一個線程獲取連接,其他線程只能等待。因此就會出現數據庫訪問效率不高的問題。

    java中的ThreadLocal能干什么

    那我們有沒有什么辦法能夠避免線程等待的情況呢?上述問題的根本原因是數據庫連接是共享變量,同事只能有一個線程可以進行操作。那如果三個線程都有自己的數據庫連接,互相隔離,那不就不會出現等待的問題了嘛。那么此時我么可以使用ThreadLocal實現在不同線程中的變量隔離。可以看出來,ThreadLocal是一種已空間換取時間的做法。

    java中的ThreadLocal能干什么

    ThreadLocal實現線程隔離的秘密

    從上文中,我們了解到ThreadLocal可以實現變量訪問的線程級別的隔離。那么它是到底如何實現的呢?這還需要結合Thread以及ThreadLocal的源碼來分析才能揭開ThreadLocal實現線程隔離的神秘面紗。

    public class Thread implements Runnable {
        ...
        /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;
        ...
        
    }

    Thread源碼中我們發現,它有一個threadLocals變量,它的類型是ThreadLocal中的內部類ThreadLocalMap。我們在看下ThreadLocalMap的定義是怎樣的。從源碼中我們可以看出來,ThreadLocalMap實際上就是Entry數組,這個Entry對應的key實際就是ThreadLocal的實例,value就是實際的變量值。

    public class ThreadLocal<T> {
      ...
        
       static class ThreadLocalMap {
         
          static class Entry extends WeakReference<ThreadLocal<?>> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
           ...
           //底層數據結構是數組
           private Entry[] table;
           ...
         
       }
      ...
      
    }

    通過查看上述的源碼,如果還不太好理解的話,我們再結合下現實中的例子來理解。大家都有支付寶賬戶,我們通過它來管理著我們的銀行卡、余額、花唄這些金融服務。

    java中的ThreadLocal能干什么

    我們以支付寶以及支付寶賬戶進行類比,假設ThreadLocal就是支付寶,每個支付寶賬戶實際就是單獨的線程,而賬戶中的余額屬性就相當于Thread的私有屬性ThreadLocalMap。我們在日常生活中,進行賬戶余額的充值或者消費,并不是直接通過賬戶進行操作的,而是借助于支付寶進行維護的。這就相當于每個線程對ThreadLocalMap進行操作的時候也不是直接操作的,而是借助于ThreadLocal來操作。

    java中的ThreadLocal能干什么

    那么Thread到底是怎么借助ThreadLocal進行私有屬性管理的呢?還是需要進一步查看Thread進行set以及get操作的源碼。從以下的ThreadLocal的源碼中我們可以看出,在進行操作之前,需要獲取當前的執行操作的線程,再根據線程或者線程中私有的ThreadLocalMap屬性來進行操作。

    java中的ThreadLocal能干什么

    在進行數據獲取的時候,也是按照同樣的流程,先獲取當前的線程,再獲取線程中對應的ThreadLocalMap屬性來進行后續的值的獲取。

    java中的ThreadLocal能干什么

    經過上述的源碼的分析,我們可以得出這樣的結論,ThreadLocal之所以可以實現變量的線程隔離訪問,實際上就是借助于Thread中的ThreadLocalMap屬性來進行操作。由于都是操作線程本身的屬性,因此并不會影響其他線程中的變量值,因此可以實現線程級別的數據修改隔離。

    java中的ThreadLocal能干什么

    為什么ThreadLocal會出現OOM的問題?

    內存泄漏演示

    我們都知道,ThreadLocal如果使用不當的話會出現內存泄漏的問題,那么我們就通過下面的這段代碼來分析下,內存泄漏的原因到底是什么。

    /**
     * @author mufeng
     * @description 測試ThreadLocal內存溢出
     * @date 2022/1/16 19:01
     * @since
     */
    public class ThreadLocalOOM {
    
        /**
         * 測試線程池
         */
        private static Executor threadPool = new ThreadPoolExecutor(3, 3, 40,
                TimeUnit.SECONDS, new LinkedBlockingDeque<>());
    
    
        static class Info {
            private byte[] info = new byte[10 * 1024 * 1024];
        }
    
        private  static ThreadLocal<Info> infoThreadLocal = new ThreadLocal<>();
    
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 10; i++) {
                threadPool.execute(() -> {
                    infoThreadLocal.set(new Info());
                    System.out.println("Thread started:" + Thread.currentThread().getName());
                });
                Thread.sleep(100);
            }
    
        }
    }

    手動進行GC之后,我們可以發現堆中仍然有超過30M的堆內存占用,如上面的代碼,在線程池中活躍的線程會有三個,對應的value為10M,說明在線程還存活的情況下,對應的value并沒有被回收,因此存在內存泄漏的情況,如果存在大量線程的情況,就會出現OOM

    java中的ThreadLocal能干什么

    當我們修改代碼在線程中進行remove操作,手動GC之后我們發現堆內存趨近于0了,之前沒有被回收的對象已經被回收了。

    java中的ThreadLocal能干什么

    內存泄漏問題分析

    以上是對于ThreadLocal發生內存泄漏問題的演示,那么再來仔細分析下背后的原因是什么。ThreadLocal中實際存儲數據的是ThreadLocalMap,實際上Map對應的key是一個虛引用,在GC的時候可以被回收掉,但是問題就在于key所對應的value,它是強引用,只要線程存活,那么這條引用鏈就會一致存在,如果出現大量線程的時候就會有OOM的風險。 所以在使用ThreadLocal的時候一定記得要顯式的調用remove方法進行清理,防止內存泄漏。

    java中的ThreadLocal能干什么

    父子線程的參數傳遞

    到這里,我相信大家對于ThreadLocal的原理有了比較深入的理解了。結合上文中的ThreadLocal代碼,不知道大家有沒有思考過一個問題,我們在使用ThreadLocal的時候都是在同一個線程內進行了set以及get操作,那么如果set操作與get操作在父子線程中是否還可以正常的獲取呢?帶著這樣的疑問,我們來看下如下的代碼。

    /**
     * @author mufeng
     * @description 父子線程參數傳遞
     * @date 2022/1/16 9:54
     * @since
     */
    public class InheritableThreadLocalMain {
    
        private static final ThreadLocal<String> count = new ThreadLocal<>();
    
        public static void main(String[] args) {
    
            count.set("父子線程參數傳遞!!!");
            System.out.println(Thread.currentThread().getName() + ":" + count.get());
    
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + ":" + count.get());
            }).start();
    
        }
    
    }

    與之前代碼有所不同,ThreadLocal的設值是在main線程中進行的,但是獲取操作實際是在主線程下的子線程中進行的,大家可以分析一下運行結果是怎么樣的。

    java中的ThreadLocal能干什么

    看到這個運行結果,不知道大家分析的對不對呢。實際上如果理解了上文的核心的話,這個問題應該很好分析的。ThreadLocal獲取數據的時候,首先是需要獲取當前的線程的,根據線程獲取實際存儲數據的ThreadLocalMap,上文代碼中設置和獲取在父子線程中進行,那肯定是獲取不到設置的數據的。但是在現實的項目開發中,我們會經常遇到需要將父線程的變量值傳遞給子線程進行處理,那么應該要怎么來實現呢?這個時候InheritableThreadLocal就派上用場了。

    /**
     * @author mufeng
     * @description 父子線程參數傳遞
     * @date 2022/1/16 9:54
     * @since
     */
    public class InheritableThreadLocalMain {
    
        private static final ThreadLocal<String> count = new InheritableThreadLocal<>();
    
        public static void main(String[] args) {
    
            count.set("父子線程參數傳遞!!!");
            System.out.println(Thread.currentThread().getName() + ":" + count.get());
    
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + ":" + count.get());
            }).start();
    
        }
    
    }

    java中的ThreadLocal能干什么

    那么InheritableThreadLocal到底是如何實現父子線程的參數傳遞的呢?我么還是的看看源碼中的實現原理。實際上在Thread源碼中,除了有Threadlocal私有屬性還有InheritableThreadLocal私有屬性。

    public class Thread implements Runnable {
        
         /* ThreadLocal values pertaining to this thread. This map is maintained
         * by the ThreadLocal class. */
        ThreadLocal.ThreadLocalMap threadLocals = null;
    
        /*
         * InheritableThreadLocal values pertaining to this thread. This map is
         * maintained by the InheritableThreadLocal class.
         */
        ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    ...
        public Thread(Runnable target) {
            init(null, target, "Thread-" + nextThreadNum(), 0);
        }
        
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize) {
            init(g, target, name, stackSize, null, true);
        }
        
        private void init(ThreadGroup g, Runnable target, String name,
                          long stackSize, AccessControlContext acc,
                          boolean inheritThreadLocals) {
            ...
            //關鍵
             if (inheritThreadLocals && parent.inheritableThreadLocals != null)
                this.inheritableThreadLocals =
                    ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); 
            ...    
            
        }
        ...
        
    }

    實際在進行子線程創建的時候,在線程初始化過程中,判斷了父線程中的inheritableThreadLocals屬性是否為空,如果不為空的話需要進行值的復制,這樣便實現了父子線程的值傳遞。

    java中的ThreadLocal能干什么

    常用的java框架有哪些

    1.SpringMVC,Spring Web MVC是一種基于Java的實現了Web MVC設計模式的請求驅動類型的輕量級Web框架。2.Shiro,Apache Shiro是Java的一個安全框架。3.Mybatis,MyBatis 是支持普通 SQL查詢,存儲過程和高級映射的優秀持久層框架。4.Dubbo,Dubbo是一個分布式服務框架。5.Maven,Maven是個項目管理和構建自動化工具。6.RabbitMQ,RabbitMQ是用Erlang實現的一個高并發高可靠AMQP消息隊列服務器。7.Ehcache,EhCache 是一個純Java的進程內緩存框架。

    以上是“java中的ThreadLocal能干什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    东至县| 奉贤区| 临海市| 天津市| 古交市| 叶城县| 翁源县| 武城县| 象山县| 綦江县| 河曲县| 汉川市| 贵阳市| 如皋市| 电白县| 绥阳县| 江津市| 甘肃省| 新干县| 聊城市| 西平县| 崇义县| 胶州市| 灵璧县| 桐城市| 白山市| 翼城县| 武邑县| 靖远县| 马山县| 莱州市| 襄垣县| 阿瓦提县| 雅安市| 荆州市| 勃利县| 临城县| 西林县| 徐州市| 贵州省| 精河县|