成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

ThreadLocal全面解析

開發(fā) 前端
ThreadLocal是Java中一個(gè)用來實(shí)現(xiàn)線程封閉技術(shù)的類。它提供了一個(gè)本地線程變量,可以在多線程環(huán)境下使每個(gè)線程都擁有自己的變量副本。

ThreadLocal是Java中一個(gè)非常重要的線程技術(shù)。它可以讓每個(gè)線程都擁有自己的變量副本,避免了線程間的競(jìng)爭(zhēng)和數(shù)據(jù)泄露問題。在本文中,我們將詳細(xì)介紹ThreadLocal的定義、用法及其優(yōu)點(diǎn)。

ThreadLocal是Java中一個(gè)用來實(shí)現(xiàn)線程封閉技術(shù)的類。它提供了一個(gè)本地線程變量,可以在多線程環(huán)境下使每個(gè)線程都擁有自己的變量副本。每個(gè)線程都可以獨(dú)立地改變自己的副本,而不會(huì)影響到其他線程的副本。ThreadLocal的實(shí)現(xiàn)是基于ThreadLocalMap的,每個(gè)ThreadLocal對(duì)象都對(duì)應(yīng)一個(gè)ThreadLocalMap,其中存儲(chǔ)了線程本地變量的值。

優(yōu)缺點(diǎn)

ThreadLocal的主要優(yōu)點(diǎn)是可以提高并發(fā)程序的性能和安全性,同時(shí)也存在一些缺點(diǎn)和使用場(chǎng)景需要注意。

優(yōu)點(diǎn):

  1. 提高并發(fā)性能:使用ThreadLocal可以避免多個(gè)線程之間的競(jìng)爭(zhēng),從而提高程序的并發(fā)性能。
  2. 保證線程安全:每個(gè)線程有自己獨(dú)立的變量副本,避免了線程安全問題。
  3. 簡(jiǎn)化代碼:使用ThreadLocal可以避免傳遞參數(shù)的繁瑣,簡(jiǎn)化代碼。

缺點(diǎn):

  1. 內(nèi)存泄漏:ThreadLocal變量副本的生命周期與線程的生命周期一樣長(zhǎng),如果線程長(zhǎng)時(shí)間存在,而ThreadLocal變量沒有及時(shí)清理,就會(huì)造成內(nèi)存泄漏。
  2. 增加資源開銷:每個(gè)線程都要?jiǎng)?chuàng)建一個(gè)獨(dú)立的變量副本,如果線程數(shù)很多,就會(huì)增加資源開銷。
  3. 不適用于共享變量:ThreadLocal適用于每個(gè)線程有獨(dú)立的變量副本的場(chǎng)景,不適用于共享變量的場(chǎng)景。

適用場(chǎng)景

  1. 線程安全的對(duì)象:ThreadLocal適用于需要在多個(gè)線程中使用的線程安全對(duì)象,例如SimpleDateFormat、Random等。
  2. 跨層傳遞參數(shù):ThreadLocal可以避免在方法之間傳遞參數(shù)的繁瑣,尤其在跨層傳遞參數(shù)的場(chǎng)景中,可以大大簡(jiǎn)化代碼。
  3. 線程局部變量:ThreadLocal可以用于在當(dāng)前線程中存儲(chǔ)和訪問局部變量,例如日志、請(qǐng)求信息等。

實(shí)現(xiàn)原理

首先通過一張圖看下ThreadLocal與線程的關(guān)系圖:

圖片圖片

  1. 每個(gè)Thread對(duì)象都有一個(gè)ThreadLocalMap類型的成員變量threadLocals,這個(gè)變量是一個(gè)鍵值對(duì)集合,用于存儲(chǔ)每個(gè)ThreadLocal對(duì)象對(duì)應(yīng)的值。
  2. 每個(gè)ThreadLocal對(duì)象都有一個(gè)唯一的ID,用于在ThreadLocalMap中作為鍵來存儲(chǔ)值。
  3. 當(dāng)一個(gè)線程第一次調(diào)用ThreadLocal對(duì)象的get()方法時(shí),它會(huì)先獲取當(dāng)前線程的ThreadLocalMap對(duì)象,然后以ThreadLocal對(duì)象的ID作為鍵,從ThreadLocalMap中獲取對(duì)應(yīng)的值。
  4. 如果ThreadLocalMap中不存在對(duì)應(yīng)的鍵值對(duì),則調(diào)用ThreadLocal對(duì)象的initialValue()方法來初始化一個(gè)值,并將其存儲(chǔ)到ThreadLocalMap中。
  5. 如果ThreadLocalMap對(duì)象的引用不再需要,那么需要手動(dòng)將其置為null,這樣可以避免內(nèi)存泄漏。

內(nèi)存泄漏

ThreadLocal變量副本的生命周期與線程的生命周期一樣長(zhǎng),如果線程長(zhǎng)時(shí)間存在,而ThreadLocal變量沒有及時(shí)清理,就會(huì)造成內(nèi)存泄漏。為了避免內(nèi)存泄漏,可以在使用ThreadLocal的地方及時(shí)清理ThreadLocal變量,例如在線程池中使用ThreadLocal時(shí),需要在線程結(jié)束時(shí)手動(dòng)清理ThreadLocal變量。

內(nèi)存泄漏出現(xiàn)的原因:

ThreadLocalMap中的Entry對(duì)象持有ThreadLocal對(duì)象的弱引用,但是ThreadLocalMap中的Entry對(duì)象是由ThreadLocal對(duì)象強(qiáng)引用的。
如果ThreadLocal對(duì)象沒有及時(shí)清理,在ThreadLocal對(duì)象被垃圾回收時(shí),ThreadLocalMap中的Entry對(duì)象仍然存在,從而導(dǎo)致內(nèi)存泄漏。

解決內(nèi)存泄漏的方法:

在使用ThreadLocal的代碼中及時(shí)清理ThreadLocal變量。通常情況下,我們可以使用ThreadLocal的remove()方法手動(dòng)清理ThreadLocal
變量,或者在使用完ThreadLocal變量后將其設(shè)置為null。

圖片圖片

通過上圖我們可以看到,在線程方法執(zhí)行過程中,ThreadLocal、ThreadLocalMap以及Thread之間的引用關(guān)系; Thread中存在一個(gè)屬性threadLocals指向了ThreadLocalMap,ThreadLocal實(shí)現(xiàn)線程級(jí)別的數(shù)據(jù)隔離主要是基于該對(duì)象;在ThreadLocal中是沒有存儲(chǔ)任何數(shù)據(jù),其更像一個(gè)線程與ThreadLocalMap間的協(xié)調(diào)器,數(shù)據(jù)存儲(chǔ)在ThreadLocalMap中,但是該Map的Key卻是ThreadLocal的弱引用;

一般情況下,線程執(zhí)行完成后,待線程銷毀,那么線程對(duì)應(yīng)的屬性threadLocals也會(huì)被銷毀;但是真實(shí)環(huán)境中對(duì)線程的使用大部分都是線程池,這樣在整個(gè)系統(tǒng)生命周期中, 線程都是有效的,直至線程池關(guān)閉。而將ThreadLocalMap的Key設(shè)置成弱引用時(shí),經(jīng)過GC后該Map的Key則變成了null,但是其Value卻一直存在,因此需要手動(dòng)將key為null 的數(shù)據(jù)進(jìn)行清理。

下面是一個(gè)示例演示如何避免ThreadLocal內(nèi)存泄漏:

public class MyThreadLocal {

    privatestatic ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void set(String value) {
        threadLocal.set(value);
    }

    public static String get() {
        return threadLocal.get();
    }

    public static void remove() {
        threadLocal.remove();
    }
}

publicclass MyRunnable implements Runnable {

    @Override
    public void run() {
        MyThreadLocal.set("hello");
        System.out.println(MyThreadLocal.get());
        // 在使用完ThreadLocal變量后,調(diào)用remove()方法清理ThreadLocal變量
        MyThreadLocal.remove();
    }
}

在上面的代碼中,MyThreadLocal類封裝了ThreadLocal變量的操作,MyRunnable類實(shí)現(xiàn)了Runnable接口,使用MyThreadLocal類來存儲(chǔ)和訪問 ThreadLocal變量。在MyRunnable的run()方法中,使用完ThreadLocal變量后,調(diào)用remove()方法清理ThreadLocal變量,避免了內(nèi)存泄漏的問題。

ThreadLocal一般會(huì)設(shè)置成static

主要是為了避免重復(fù)創(chuàng)建TSO(thread specific object,即與線程相關(guān)的變量。)我們知道,一個(gè)ThreadLocal實(shí)例對(duì)應(yīng)當(dāng)前線程中的一個(gè)TSO實(shí)例。如果把ThreadLocal聲明為某個(gè)類的實(shí)例變量(而不是靜態(tài)變量),那么每創(chuàng)建一個(gè)該類的實(shí)例就會(huì)導(dǎo)致一個(gè)新的TSO實(shí)例被創(chuàng)建。而這些被創(chuàng)建的TSO實(shí)例是同一個(gè)類的實(shí)例。同一個(gè)線程可能會(huì)訪問到同一個(gè)TSO(指類)的不同實(shí)例,這即便不會(huì)導(dǎo)致錯(cuò)誤,也會(huì)導(dǎo)致浪費(fèi)!

簡(jiǎn)單的說就是在ThreadLocalMap中,同一個(gè)線程是否有必要設(shè)置多個(gè)ThreadLocal來存儲(chǔ)線程變量?

示例

下面是一個(gè)簡(jiǎn)單的例子,演示了如何使用ThreadLocal來實(shí)現(xiàn)線程數(shù)據(jù)隔離:

public class ThreadLocalTest {
    
    privatestatic ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            threadLocal.set("Thread A");
            System.out.println("Thread A: " + threadLocal.get());
        }).start();

        new Thread(() -> {
            threadLocal.set("Thread B");
            System.out.println("Thread B: " + threadLocal.get());
        }).start();

        Thread.sleep(1000);

        System.out.println("Main: " + threadLocal.get());
    }
}

運(yùn)行結(jié)果如下:

Thread A: Thread A
Thread B: Thread B
Main: null

從輸出結(jié)果可以看出,每個(gè)線程都擁有自己的變量副本,互不影響。而在主線程中,由于沒有設(shè)置過變量副本,所以返回null。

結(jié)束語

ThreadLocal是幫助我們?cè)诙鄠€(gè)線程間實(shí)現(xiàn)線程對(duì)數(shù)據(jù)獨(dú)享,并不是用來解決線程間的數(shù)據(jù)共享問題。

責(zé)任編輯:武曉燕 來源: 一安未來
相關(guān)推薦

2024-11-18 16:15:00

2017-04-10 18:34:16

AndroidNotificatio

2024-08-29 08:28:17

2010-07-22 09:25:09

telnet命令

2010-03-09 17:19:01

Linux時(shí)鐘

2010-06-24 15:35:04

IPx協(xié)議

2010-01-06 17:12:57

Linux主要構(gòu)成

2009-07-06 09:17:51

2009-07-17 17:02:54

JRuby是什么

2010-06-28 18:52:49

UML關(guān)系符號(hào)

2021-11-23 09:09:27

Applicationandroid系統(tǒng)開發(fā)

2021-11-19 17:26:11

AppApplication方法

2009-10-19 15:07:17

Visual Basi

2011-04-12 15:00:48

Oracle碎片

2017-05-23 15:47:04

JavaScriptthis解析

2009-12-25 16:47:04

Linux Make規(guī)

2010-08-04 14:34:35

Flex編程模型

2010-03-08 17:27:56

Linux profi

2010-10-20 15:11:53

SQL Server作

2009-11-11 17:02:44

MPLS路由協(xié)議
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 久久久久免费 | 久久精品欧美一区二区三区麻豆 | 亚洲精品久久久一区二区三区 | 久久综合一区 | 国产精品视频观看 | 国产成人精品久久二区二区91 | av高清毛片 | 国产成人99久久亚洲综合精品 | 日韩91 | 亚洲精品久久久9婷婷中文字幕 | 国产精品美女久久久久aⅴ国产馆 | 91国自视频 | 中文字幕日本一区二区 | 午夜激情视频在线 | 亚洲精品视频免费观看 | 精品久久香蕉国产线看观看亚洲 | 性色av香蕉一区二区 | 久久精品色视频 | 国产中文字幕亚洲 | 九九综合 | 国产精品久久久久一区二区三区 | 天天操人人干 | 黄网站免费在线看 | 色婷婷国产精品综合在线观看 | 色爽女| 欧美网址在线观看 | 欧美日韩亚洲视频 | 爱操影视 | 国产精品久久久久久久久久久久久 | 国产精品亚洲一区二区三区在线 | 国产激情毛片 | 手机av在线 | 中文字幕在线播放第一页 | 午夜色婷婷| 精品少妇一区二区三区在线播放 | 99久久婷婷国产综合精品 | 日本在线播放一区二区 | 国产特级毛片aaaaaa喷潮 | 中文字幕亚洲免费 | www.99热.com| 在线视频一区二区 |