日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ThreadLocal小记

發(fā)布時間:2025/7/25 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ThreadLocal小记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

API:

public class ThreadLocal<T> extends Object

該類提供了線程局部 (thread-local) 變量。

這些變量不同于它們的普通相應(yīng)物。由于訪問某個變量(通過其 get 或 set 方法)的每一個線程都有自己的局部變量,它獨立于變量的初始化副本。ThreadLocal 實例一般是類中的 private static 字段,它們希望將狀態(tài)與某一個線程(比如,用戶 ID 或事務(wù) ID)相關(guān)聯(lián)


每一個線程都保持對其線程局部變量副本的隱式引用,僅僅要線程是活動的而且 ThreadLocal 實例是可訪問的。在線程消失之后。其線程局部實例的全部副本都會被垃圾回收(除非存在對這些副本的其它引用)。


Method:

initialValue

protected T initialValue()
返回此線程局部變量的當(dāng)前線程的“初始值”。

線程第一次使用 get() 方法訪問變量時將調(diào)用此方法,但假設(shè)線程之前調(diào)用了 set(T) 方法。則不會對該線程再調(diào)用 initialValue 方法。

通常,此方法對每一個線程最多調(diào)用一次。但假設(shè)在調(diào)用get() 后又調(diào)用了 remove(),則可能再次調(diào)用此方法。

該實現(xiàn)返回 null;假設(shè)程序猿希望線程局部變量具有 null 以外的值。則必須為 ThreadLocal 創(chuàng)建子類。并重寫此方法。通常將使用匿名內(nèi)部類完畢此操作。

返回:
返回此線程局部變量的初始值


get

public T get()
返回此線程局部變量的當(dāng)前線程副本中的值。假設(shè)變量沒實用于當(dāng)前線程的值,則先將其初始化為調(diào)用 initialValue() 方法返回的值。
返回:
此線程局部變量的當(dāng)前線程的值


set

public void set(T?value)
將此線程局部變量的當(dāng)前線程副本中的值設(shè)置為指定值。大部分子類不須要重寫此方法,它們僅僅依靠 initialValue() 方法來設(shè)置線程局部變量的值。
參數(shù):
value - 存儲在此線程局部變量的當(dāng)前線程副本中的值。


remove

public void remove() 移除此線程局部變量當(dāng)前線程的值。

假設(shè)此線程局部變量隨后被當(dāng)前線程 讀取,且這期間當(dāng)前線程沒有 設(shè)置其值。則將調(diào)用其 initialValue() 方法又一次初始化其值。

這將導(dǎo)致在當(dāng)前線程多次調(diào)用 initialValue 方法。


例1:

package com.example;import java.util.Date; import java.util.concurrent.TimeUnit;public class SafeTask implements Runnable{private static ThreadLocal<Date> startDate= new ThreadLocal<Date>() {protected Date initialValue(){return new Date();}};@Overridepublic void run() {System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());try {TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));} catch (InterruptedException e) {e.printStackTrace();}System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());}public static void main(String[] args) {SafeTask task=new SafeTask();for (int i=0; i<3; i++){Thread thread=new Thread(task);thread.start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}}
執(zhí)行結(jié)果:

Starting Thread: 15 : Mon Nov 17 13:36:33 CST 2014 Starting Thread: 17 : Mon Nov 17 13:36:35 CST 2014 Thread Finished: 17 : Mon Nov 17 13:36:35 CST 2014 Starting Thread: 18 : Mon Nov 17 13:36:37 CST 2014 Thread Finished: 15 : Mon Nov 17 13:36:33 CST 2014 Thread Finished: 18 : Mon Nov 17 13:36:37 CST 2014

從結(jié)果,能夠看到,三個線程各自存儲和訪問各自維護(hù)的startDate局部變量。


解析:

ThreadLocal有一個內(nèi)部靜態(tài)類ThreadLocalMap來管理線程中的變量。能夠簡單的將其理解成一個Map。

而Map中存放的指的方式是:用當(dāng)前的線程來做為KEY。線程相應(yīng)的變量值作為VALUE。

當(dāng)某一線程要獲取當(dāng)前變量的值時,就使用ThreadLocal.get()方法。通過線程自身作為KEY,去ThreadLocalMap中查找相應(yīng)的值。

這樣就能夠解釋“每一個線程都保持對其線程局部變量副本的隱式引用”。

而為了使每一個線程都能夠使用該變量的副本使用,ThreadLocal 實例一般是類中的 private static 字段”。



為了更好的理解ThreadLocal這樣的機制,請看以下的樣例。

例2:

package com.example;import java.util.Date; import java.util.concurrent.TimeUnit;public class SafeTask implements Runnable{private static ThreadLocal<Date> startDate = new ThreadLocal<Date>();@Overridepublic void run() {startDate = new ThreadLocal<Date>();startDate.set(new Date());System.out.printf("Thread: %s new startDate.\n", Thread.currentThread().getId());System.out.printf("Starting Thread: %s : %s\n",Thread.currentThread().getId(),startDate.get());try {TimeUnit.SECONDS.sleep( (int)Math.rint(Math.random()*10));} catch (InterruptedException e) {e.printStackTrace();}System.out.printf("Thread Finished: %s : %s\n",Thread.currentThread().getId(),startDate.get());}public static void main(String[] args) {SafeTask task=new SafeTask();for (int i=0; i<3; i++){Thread thread=new Thread(task);thread.start();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}}
運行結(jié)果:

Thread: 15 new startDate. Starting Thread: 15 : Mon Nov 17 13:55:16 CST 2014 Thread: 17 new startDate. Starting Thread: 17 : Mon Nov 17 13:55:18 CST 2014 Thread Finished: 15 : null Thread Finished: 17 : Mon Nov 17 13:55:18 CST 2014 Thread: 18 new startDate. Starting Thread: 18 : Mon Nov 17 13:55:20 CST 2014 Thread Finished: 18 : Mon Nov 17 13:55:20 CST 2014
為什么例2的結(jié)果中會出現(xiàn)null呢?

原因就在于,代碼在線程中又一次創(chuàng)建來ThreadLocal

startDate = new ThreadLocal<Date>();這樣做,就導(dǎo)致了startDate指向了新的ThreadLocal對象。那么之前存放在當(dāng)中的副本就丟失了,所以才會出現(xiàn)null的情況。


通過以上的樣例,我們就能理解為什么ThreadLocal 實例一般是類中的 private static 字段

我們須要明確。每一個線程中變量的副本,是通過線程的KEY和變量的VALUE存放在ThreadLocalMap中,而不是說。為每一個線程建立ThreadLocal。

就類而言,他實際僅僅維護(hù)和管理著一個ThreadLocal。


PS:代碼部分截取來自《Java 7 Concurrency Cookbook》

轉(zhuǎn)載于:https://www.cnblogs.com/blfshiye/p/5278715.html

總結(jié)

以上是生活随笔為你收集整理的ThreadLocal小记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。