欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

Java中ThreadLocal的原理是什么及怎么使用

這篇文章主要介紹“Java中ThreadLocal的原理是什么及怎么使用”,在日常操作中,相信很多人在Java中ThreadLocal的原理是什么及怎么使用問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Java中ThreadLocal的原理是什么及怎么使用”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

創(chuàng)新互聯(lián)專注于大渡口企業(yè)網(wǎng)站建設(shè),響應(yīng)式網(wǎng)站建設(shè),商城系統(tǒng)網(wǎng)站開發(fā)。大渡口網(wǎng)站建設(shè)公司,為大渡口等地區(qū)提供建站服務(wù)。全流程定制網(wǎng)站,專業(yè)設(shè)計(jì),全程項(xiàng)目跟蹤,創(chuàng)新互聯(lián)專業(yè)和態(tài)度為您提供的服務(wù)

用法

  • 隔離各個線程間的數(shù)據(jù)

  • 避免線程內(nèi)每個方法都進(jìn)行傳參,線程內(nèi)的所有方法都可以直接獲取到ThreadLocal中管理的對象。

package com.example.test1.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class AsyncTest {

    // 使用threadlocal管理
    private static final ThreadLocal<SimpleDateFormat> dateFormatLocal =
            ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

    // 不用threadlocal進(jìn)行管理,用于對比
    SimpleDateFormat dateFormat = new SimpleDateFormat();

    // 線程名稱以task開頭
    @Async("taskExecutor")
    public void formatDateSync(String format, Date date) throws InterruptedException {
        SimpleDateFormat simpleDateFormat = dateFormatLocal.get();
        simpleDateFormat.applyPattern(format);
        
        // 所有方法都可以直接使用這個變量,而不用根據(jù)形參傳入
        doSomething();
        
        Thread.sleep(1000);
        System.out.println("sync " + Thread.currentThread().getName() +  " | " + simpleDateFormat.format(date));
        
        // 線程執(zhí)行完畢,清除數(shù)據(jù)
        dateFormatLocal.remove();
    }

    // 線程名稱以task2開頭
    @Async("taskExecutor2")
    public void formatDate(String format, Date date) throws InterruptedException {
        dateFormat.applyPattern(format);
        Thread.sleep(1000);
        System.out.println("normal " + Thread.currentThread().getName() +  " | " + dateFormat.format(date));
    }
}

使用junit進(jìn)行測試:

@Test
void test2() throws InterruptedException {
for(int index = 1; index <= 10; ++index){
String format = index + "-yyyy-MM-dd";
Date time = new Date();
asyncTest.formatDate(format, time);
}

for(int index = 1; index <= 10; ++index){
String format = index + "-yyyy-MM-dd";
Date time = new Date();
asyncTest.formatDateSync(format, time);
}
}

結(jié)果如下,可以看到?jīng)]有被 ThreadLocal 管理的變量已經(jīng)無法匹配正確的format。

sync task--10 | 10-2023-04-11
sync task--9 | 9-2023-04-11
normal task2-3 | 2-2023-04-11
normal task2-5 | 2-2023-04-11
normal task2-10 | 2-2023-04-11
normal task2-6 | 2-2023-04-11
sync task--1 | 1-2023-04-11
normal task2-7 | 2-2023-04-11
normal task2-8 | 2-2023-04-11
normal task2-9 | 2-2023-04-11
sync task--6 | 6-2023-04-11
sync task--3 | 3-2023-04-11
sync task--2 | 2-2023-04-11
sync task--7 | 7-2023-04-11
sync task--4 | 4-2023-04-11
sync task--8 | 8-2023-04-11
normal task2-4 | 2-2023-04-11
normal task2-1 | 2-2023-04-11
sync task--5 | 5-2023-04-11
normal task2-2 | 2-2023-04-11

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

ThreadLocal中獲取數(shù)據(jù)的過程:

先獲取對應(yīng)的線程。

通過 getMap(t)拿到線程中的 ThreadLocalMap

ThreadLocalMap 是一個重新實(shí)現(xiàn)的散列表,基于兩個元素實(shí)現(xiàn)散列:

  • 用戶定義的ThreadLocal對象,例如:dateFormatLocal。

  • 封裝了valueEntry對象。

通過map.getEntry(this)方法,根據(jù)當(dāng)前的 threadlocal對象在散列表中獲得對應(yīng)的Entry

如果是第一次使用get(), 則使用 setInitialValue()調(diào)用用戶重寫的initialValue()方法創(chuàng)建map并使用用戶指定的值初始化。

在這種設(shè)計(jì)方式下,線程死去的時候,線程共享變量ThreadLocalMap會被銷毀。

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

注意 Entry對象是弱引用:

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    // k: ThreadLocal, v: value
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

弱引用的常見用法是:

WeakReference<RoleDTO> weakReference = new WeakReference<>(new RoleDTO());

因此,在Entry中,k 代表ThreadLocal對象,它是弱引用。v代表ThreadLocal管理的那個value,是強(qiáng)引用。

內(nèi)存泄漏

內(nèi)存泄漏是指無用對象(不再使用的對象)持續(xù)占有內(nèi)存或無用對象的內(nèi)存得不到及時釋放,從而造成內(nèi)存空間的浪費(fèi)稱為內(nèi)存泄漏。隨著垃圾回收器活動的增加以及內(nèi)存占用的不斷增加,程序性能會逐漸表現(xiàn)出來下降,極端情況下,會引發(fā)OutOfMemoryError導(dǎo)致程序崩潰。

內(nèi)存泄漏問題主要在線程池中出現(xiàn),因?yàn)榫€程池中的線程是不斷執(zhí)行的,從任務(wù)隊(duì)列中不斷獲取新的任務(wù)執(zhí)行。但是任務(wù)中可能有ThreadLocal對象,這些對象的ThreadLocal會保存在線程的ThreadLocalMap中,因此ThreadLocalMap會越來越大。

但是ThreadLocal是由任務(wù)(worker)傳入的,一個任務(wù)執(zhí)行結(jié)束后,對應(yīng)的ThreadLocal對象會被銷毀。線程中的關(guān)系是: Thread -> ThreadLoalMap -> Entry<ThreadLocal, Object>ThreadLocal由于是弱引用會,在GC的時候會被銷毀,這會導(dǎo)致 ThreadLoalMap中存在Entry<null, Object>

使用remove()

由于線程池中的線程一直在運(yùn)行,如果不對ThreadLoalMap進(jìn)行清理,那Entry<null, Object>會一直占用內(nèi)存。remove()方法會清除key==nullEntry

使用static修飾

ThreadLocal設(shè)置成static可以避免一個線程類多次傳入線程池后重復(fù)創(chuàng)建Entry。例如,有一個用戶定義的線程

public class Test implements Runnable{
    private static ThreadLocal<Integer> local = new ThreadLocal<>();
    @Override
    public void run() {
        // do something
    }
}

使用線程池處理10個任務(wù)。那么線程池中每個用來處理任務(wù)的線程的Thread.ThreadLocalMap中都會保存一個Entry<local, Integer>,由于添加了static關(guān)鍵字,所有每個線程中的Entry中的local變量引用的都是同一個變量。這時就算發(fā)生內(nèi)存泄漏,所有的Test類也只有一個local對象,不會導(dǎo)致內(nèi)存占用過多。

@Test
void contextLoads() {
   Runnable runnable = () -> {
      System.out.println(Thread.currentThread().getName());
   };

   for(int index = 1; index <= 10; ++index){
      taskExecutor2.submit(new com.example.test1.service.Test());
   }
}

到此,關(guān)于“Java中ThreadLocal的原理是什么及怎么使用”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

分享題目:Java中ThreadLocal的原理是什么及怎么使用
標(biāo)題路徑:http://chinadenli.net/article20/ieghjo.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站企業(yè)網(wǎng)站制作、網(wǎng)站制作、外貿(mào)網(wǎng)站建設(shè)企業(yè)建站、全網(wǎng)營銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

微信小程序開發(fā)
欧美日韩一级aa大片| 麻豆一区二区三区精品视频| 国产白丝粉嫩av在线免费观看 | 在线观看视频日韩成人| 国产成人亚洲精品青草天美| 在线观看国产成人av天堂野外| 高清国产日韩欧美熟女| 99久只有精品免费视频播放| 亚洲国产综合久久天堂| 国产成人亚洲欧美二区综| 91精品欧美综合在ⅹ| 激情亚洲一区国产精品久久| 亚洲视频一区自拍偷拍另类| 精品日韩中文字幕视频在线| 亚洲一区二区三区一区| 激情中文字幕在线观看| 国产超薄黑色肉色丝袜| 国产av熟女一区二区三区蜜桃| 欧美整片精品日韩综合| 日本高清一道一二三区四五区| 国产高清在线不卡一区| 好吊妞视频只有这里有精品| 欧美日韩成人在线一区| 欧美老太太性生活大片| 日本黄色高清视频久久| 精品国产亚洲av久一区二区三区| 日韩中文字幕有码午夜美女| 色综合伊人天天综合网中文| 午夜激情视频一区二区| 精品综合欧美一区二区三区| 日韩欧美综合在线播放| 一本久道久久综合中文字幕| 九九九热在线免费视频| 欧美一区二区不卡专区| 中文字幕精品少妇人妻| 好东西一起分享老鸭窝| 国产精品久久男人的天堂| 一本久道久久综合中文字幕| 欧美一区二区口爆吞精| 亚洲av日韩一区二区三区四区| 九九蜜桃视频香蕉视频|