中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

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

java.lang.ThreadLocal類怎么用

發布時間:2022-03-11 17:23:49 來源:億速云 閱讀:135 作者:iii 欄目:web開發

這篇“java.lang.ThreadLocal類怎么用”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“java.lang.ThreadLocal類怎么用”文章吧。

一、概述

ThreadLocal是什么呢?其實ThreadLocal并非是一個線程的本地實現版本,它并不是一個Thread,而是threadlocalvariable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是Java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。

從線程的角度看,每個線程都保持一個對其線程局部變量副本的隱式引用,只要線程是活動的并且 ThreadLocal 實例是可訪問的;在線程消失之后,其線程局部實例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用)。

通過ThreadLocal存取的數據,總是與當前線程相關,也就是說,JVM 為每個運行的線程,綁定了私有的本地實例存取空間,從而為多線程環境常出現的并發訪問問題提供了一種隔離機制。

ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。

概括起來說,對于多線程資源共享的問題,同步機制采用了“以時間換空間”的方式,而ThreadLocal采用了“以空間換時間”的方式。前者僅提供一份變量,讓不同的線程排隊訪問,而后者為每一個線程都提供了一份變量,因此可以同時訪問而互不影響。

二、API說明

ThreadLocal()

創建一個線程本地變量。

T get()

返回此線程局部變量的當前線程副本中的值,如果這是線程第一次調用該方法,則創建并初始化此副本。

protected T initialValue()

返回此線程局部變量的當前線程的初始值。最多在每次訪問線程來獲得每個線程局部變量時調用此方法一次,即線程第一次使用 get() 方法訪問變量的時候。如果線程先于 get 方法調用 set(T) 方法,則不會在線程中再調用 initialValue 方法。

若該實現只返回 null;如果程序員希望將線程局部變量初始化為 null 以外的某個值,則必須為 ThreadLocal 創建子類,并重寫此方法。通常,將使用匿名內部類。initialValue 的典型實現將調用一個適當的構造方法,并返回新構造的對象。

void remove()

移除此線程局部變量的值。這可能有助于減少線程局部變量的存儲需求。如果再次訪問此線程局部變量,那么在默認情況下它將擁有其 initialValue。

void set(T value)

將此線程局部變量的當前線程副本中的值設置為指定值。許多應用程序不需要這項功能,它們只依賴于 initialValue() 方法來設置線程局部變量的值。

在程序中一般都重寫initialValue方法,以給定一個特定的初始值。

三、典型實例

1、Hiberante的Session 工具類HibernateUtil

這個類是Hibernate官方文檔中HibernateUtil類,用于session管理。

public class HibernateUtil {

private static Log log = LogFactory.getLog(HibernateUtil.class);

private static final SessionFactory sessionFactory; //定義SessionFactory

static {

try {

// 通過默認配置文件hibernate.cfg.xml創建SessionFactory

sessionFactory = new Configuration().configure().buildSessionFactory();

} catch (Throwable ex) {

log.error("初始化SessionFactory失敗!", ex);

throw new ExceptionInInitializerError(ex);

}

}

//創建線程局部變量session,用來保存Hibernate的Session

public static final ThreadLocal session = new ThreadLocal();

/**

* 獲取當前線程中的Session

* @return Session

* @throws HibernateException

*/

public static Session currentSession() throws HibernateException {

Session s = (Session) session.get();

// 如果Session還沒有打開,則新開一個Session

if (s == null) {

s = sessionFactory.openSession();

session.set(s); //將新開的Session保存到線程局部變量中

}

return s;

}

public static void closeSession() throws HibernateException {

//獲取線程局部變量,并強制轉換為Session類型

Session s = (Session) session.get();

session.set(null);

if (s != null)

s.close();

}

}

在這個類中,由于沒有重寫ThreadLocal的initialValue()方法,則首次創建線程局部變量session其初始值為null,第一次調用currentSession()的時候,線程局部變量的get()方法也為null。因此,對session做了判斷,如果為null,則新開一個Session,并保存到線程局部變量session中,這一步非常的關鍵,這也是“public static final ThreadLocal session = new ThreadLocal()”所創建對象session能強制轉換為Hibernate Session對象的原因。

2、另外一個實例

創建一個Bean,通過不同的線程對象設置Bean屬性,保證各個線程Bean對象的獨立性。

/**

* Created by IntelliJ IDEA.

* User: leizhimin

* Date: 2007-11-23

* Time: 10:45:02

* 學生

*/

public class Student {

private int age = 0; //年齡

public int getAge() {

return this.age;

}

public void setAge(int age) {

this.age = age;

}

}

/**

* Created by IntelliJ IDEA.

* User: leizhimin

* Date: 2007-11-23

* Time: 10:53:33

* 多線程下測試程序

*/

public class ThreadLocalDemo implements Runnable {

//創建線程局部變量studentLocal,在后面你會發現用來保存Student對象

private final static ThreadLocal studentLocal = new ThreadLocal();

public static void main(String[] agrs) {

ThreadLocalDemo td = new ThreadLocalDemo();

Thread t1 = new Thread(td, "a");

Thread t2 = new Thread(td, "b");

t1.start();

t2.start();

}

public void run() {

accessStudent();

}

/**

* 示例業務方法,用來測試

*/

public void accessStudent() {

//獲取當前線程的名字

String currentThreadName = Thread.currentThread().getName();

System.out.println(currentThreadName + " is running!");

//產生一個隨機數并打印

Random random = new Random();

int age = random.nextInt(100);

System.out.println("thread " + currentThreadName + " set age to:" + age);

//獲取一個Student對象,并將隨機數年齡插入到對象屬性中

Student student = getStudent();

student.setAge(age);

System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());

try {

Thread.sleep(500);

}

catch (InterruptedException ex) {

ex.printStackTrace();

}

System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());

}

protected Student getStudent() {

//獲取本地線程變量并強制轉換為Student類型

Student student = (Student) studentLocal.get();

//線程首次執行此方法的時候,studentLocal.get()肯定為null

if (student == null) {

//創建一個Student對象,并保存到本地線程變量studentLocal中

student = new Student();

studentLocal.set(student);

}

return student;

}

}

運行結果:

a is running!

thread a set age to:76

b is running!

thread b set age to:27

thread a first read age is:76

thread b first read age is:27

thread a second read age is:76

thread b second read age is:27

可以看到a、b兩個線程age在不同時刻打印的值是完全相同的。這個程序通過妙用ThreadLocal,既實現多線程并發,游兼顧數據的安全性。

四、總結

ThreadLocal使用場合主要解決多線程中數據數據因并發產生不一致問題。ThreadLocal為每個線程的中并發訪問的數據提供一個副本,通過訪問副本來運行業務,這樣的結果是耗費了內存,單大大減少了線程同步所帶來性能消耗,也減少了線程并發控制的復雜度。

ThreadLocal不能使用原子類型,只能使用Object類型。ThreadLocal的使用比synchronized要簡單得多。

ThreadLocal和Synchonized都用于解決多線程并發訪問。但是ThreadLocal與synchronized有本質的區別。synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本,使得每個線程在某一時間訪問到的并不是同一個對象,這樣就隔離了多個線程對數據的數據共享。而Synchronized卻正好相反,它用于在多個線程間通信時能夠獲得數據共享。

Synchronized用于線程間的數據共享,而ThreadLocal則用于線程間的數據隔離。

當然ThreadLocal并不能替代synchronized,它們處理不同的問題域。Synchronized用于實現同步機制,比ThreadLocal更加復雜。

五、ThreadLocal使用的一般步驟

1、在多線程的類(如ThreadDemo類)中,創建一個ThreadLocal對象threadXxx,用來保存線程間需要隔離處理的對象xxx。

2、在ThreadDemo類中,創建一個獲取要隔離訪問的數據的方法getXxx(),在方法中判斷,若ThreadLocal對象為null時候,應該new()一個隔離訪問類型的對象,并強制轉換為要應用的類型。

3、在ThreadDemo類的run()方法中,通過getXxx()方法獲取要操作的數據,這樣可以保證每個線程對應一個數據對象,在任何時刻都操作的是這個對象。

以上就是關于“java.lang.ThreadLocal類怎么用”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。

向AI問一下細節

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

AI

仁布县| 诸城市| 华蓥市| 宁德市| 平遥县| 阿鲁科尔沁旗| 青铜峡市| 大港区| 龙陵县| 资阳市| 铜陵市| 普兰店市| 青海省| 清徐县| 九龙县| 长治县| 黔西| 郸城县| 蓝田县| 安福县| 石屏县| 喀喇沁旗| 罗平县| 永靖县| 沈阳市| 梁山县| 宜川县| 六枝特区| 台中县| 白沙| 浮山县| 霍山县| 呼玛县| 永安市| 江山市| 辉南县| 博乐市| 阜康市| 陇川县| 安吉县| 社会|