java中的ThreadLocal本地線程與同步機(jī)制有什么不同

本篇文章為大家展示了java 中的ThreadLocal本地線程與同步機(jī)制有什么不同,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

讓客戶(hù)滿(mǎn)意是我們工作的目標(biāo),不斷超越客戶(hù)的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶(hù),將通過(guò)不懈努力成為客戶(hù)在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:域名與空間、網(wǎng)站空間、營(yíng)銷(xiāo)軟件、網(wǎng)站建設(shè)、長(zhǎng)樂(lè)網(wǎng)站維護(hù)、網(wǎng)站推廣。

ThreadLocal的設(shè)計(jì)

首先看看ThreadLocal的接口:

Object get() ; // 返回當(dāng)前線程的線程局部變量副本 protected Object
initialValue(); // 返回該線程局部變量的當(dāng)前線程的初始值          
void set(Object value); // 設(shè)置當(dāng)前線程的線程局部變量副本的值

ThreadLocal有3個(gè)方法,其中值得注意的是initialValue(),該方法是一個(gè)protected的方法,顯然是為了子類(lèi)重寫(xiě)而特意實(shí)現(xiàn)的。該方法返回當(dāng)前線程在該線程局部變量的初始值,這個(gè)方法是一個(gè)延遲調(diào)用方法,在一個(gè)線程第1次調(diào)用get()或者set(Object)時(shí)才執(zhí)行,并且僅執(zhí)行1次。ThreadLocal中的確實(shí)實(shí)現(xiàn)直接返回一個(gè)null:

protected Object initialValue() { return null; }

ThreadLocal是如何做到為每一個(gè)線程維護(hù)變量的副本的呢?其實(shí)實(shí)現(xiàn)的思路很簡(jiǎn)單,在ThreadLocal類(lèi)中有一個(gè)Map,用于存儲(chǔ)每一個(gè)線程的變量的副本。

比如下面的示例實(shí)現(xiàn):就相當(dāng)于存Map 這個(gè)是ThreadLocal的get方法的實(shí)現(xiàn)
 

public T get() {
    Thread t = Thread.currentThread();//獲取當(dāng)前線程
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      ThreadLocalMap.Entry e = map.getEntry(this);
      if (e != null)
        return (T)e.value;
    }
    return setInitialValue();
  }
  
  
   ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
  }

ThreadLocal與其它同步機(jī)制的比較

ThreadLocal和其它同步機(jī)制相比有什么優(yōu)勢(shì)呢?ThreadLocal和其它所有的同步機(jī)制都是為了解決多線程中的對(duì)同一變量的訪問(wèn)沖突,在普通的同步機(jī)制中,是通過(guò)對(duì)象加鎖來(lái)實(shí)現(xiàn)多個(gè)線程對(duì)同一變量的安全訪問(wèn)的。這時(shí)該變量是多個(gè)線程共享的,使用這種同步機(jī)制需要很細(xì)致地分析在什么時(shí)候?qū)ψ兞窟M(jìn)行讀寫(xiě),什么時(shí)候需要鎖定某個(gè)對(duì)象,什么時(shí)候釋放該對(duì)象的鎖等等很多。所有這些都是因?yàn)槎鄠€(gè)線程共享了資源造成的。ThreadLocal就從另一個(gè)角度來(lái)解決多線程的并發(fā)訪問(wèn),ThreadLocal會(huì)為每一個(gè)線程維護(hù)一個(gè)和該線程綁定的變量的副本,從而隔離了多個(gè)線程的數(shù)據(jù),每一個(gè)線程都擁有自己的變量副本,從而也就沒(méi)有必要對(duì)該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對(duì)象,在編寫(xiě)多線程代碼時(shí),可以把不安全的整個(gè)變量封裝進(jìn)ThreadLocal,或者把該對(duì)象的特定于線程的狀態(tài)封裝進(jìn)ThreadLocal。

由于ThreadLocal中可以持有任何類(lèi)型的對(duì)象,所以使用ThreadLocal get當(dāng)前線程的值是需要進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換。但隨著新的Java版本(1.5)將模版的引入,新的支持模版參數(shù)的ThreadLocal<T>類(lèi)將從中受益。也可以減少?gòu)?qiáng)制類(lèi)型轉(zhuǎn)換,并將一些錯(cuò)誤檢查提前到了編譯期,將一定程度地簡(jiǎn)化ThreadLocal的使用。

總結(jié)

    當(dāng)然ThreadLocal并不能替代同步機(jī)制,兩者面向的問(wèn)題領(lǐng)域不同。同步機(jī)制是為了同步多個(gè)線程對(duì)相同資源的并發(fā)訪問(wèn),是為了多個(gè)線程之間進(jìn)行通信的有效方式;而ThreadLocal是隔離多個(gè)線程的數(shù)據(jù)共享,從根本上就不在多個(gè)線程之間共享資源(變量),這樣當(dāng)然不需要對(duì)多個(gè)線程進(jìn)行同步了。所以,如果你需要進(jìn)行多個(gè)線程之間進(jìn)行通信, 則使用同步機(jī)制;如果需要隔離多個(gè)線程之間的共享沖突,可以使用ThreadLocal,這將極大地簡(jiǎn)化你的程序,使程序更加易讀、簡(jiǎn)潔。

ThreadLocal常見(jiàn)用途:

存放當(dāng)前session用戶(hù)
存放一些context變量,比如webwork的ActionContext
存放session,比如Spring hibernate orm的session

例子:用 ThreadLocal 實(shí)現(xiàn)每線程 Singleton

       線程局部變量常被用來(lái)描繪有狀態(tài)“單子”(Singleton) 或線程安全的共享對(duì)象,或者是通過(guò)把不安全的整個(gè)變量封裝進(jìn) ThreadLocal,或者是通過(guò)把對(duì)象的特定于線程的狀態(tài)封裝進(jìn) ThreadLocal。例如,在與數(shù)據(jù)庫(kù)有緊密聯(lián)系的應(yīng)用程序中,程序的很多方法可能都需要訪問(wèn)數(shù)據(jù)庫(kù)。在系統(tǒng)的每個(gè)方法中都包含一個(gè) Connection 作為參數(shù)是不方便的 — 用“單子”來(lái)訪問(wèn)連接可能是一個(gè)雖然更粗糙,但卻方便得多的技術(shù)。然而,多個(gè)線程不能安全地共享一個(gè) JDBC Connection。如清單 3 所示,通過(guò)使用“單子”中的 ThreadLocal,我們就能讓我們的程序中的任何類(lèi)容易地獲取每線程 Connection 的一個(gè)引用。這樣,我們可以認(rèn)為 ThreadLocal 允許我們創(chuàng)建每線程單子。

package org.heinrich.app.connection;

import java.sql.Connection;

public class ConnectionUtils {
 
 
 private final static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
 
 
 public Connection getConnection(){
 Connection connection = threadLocal.get();
 if(connection ==null){
  connection = new DBHelper().getConn();
  threadLocal.set(connection);
 }
 
 return connection;
 }
 
 

}

package org.heinrich.app.connection;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
//數(shù)據(jù)庫(kù)連接
public class DBHelper {
 public static final String url = "jdbc:MySQL://localhost:3306/fk_test";
 public static final String name = "com.mysql.jdbc.Driver";
 public static final String user = "root";
 public static final String password = "root";

 public Connection conn = null;

 public Connection getConn() {
 try {
  Class.forName(name);// 指定連接類(lèi)型
  conn = DriverManager.getConnection(url, user, password);// 獲取連接
 } catch (Exception e) {
  e.printStackTrace();
 }
 return conn;
 }

}

簡(jiǎn)單的實(shí)現(xiàn)Mysql連接線程安全的一種方式

理論上來(lái)說(shuō),ThreadLocal是的確是相對(duì)于每個(gè)線程,每個(gè)線程會(huì)有自己的ThreadLocal。但是上面已經(jīng)講到,一般的應(yīng)用服務(wù)器都會(huì)維護(hù)一套線程池。因此,不同用戶(hù)訪問(wèn),可能會(huì)接受到同樣的線程。因此,在做基于TheadLocal時(shí),需要謹(jǐn)慎,避免出現(xiàn)ThreadLocal變量的緩存,導(dǎo)致其他線程訪問(wèn)到本線程變量。

上述內(nèi)容就是java 中的ThreadLocal本地線程與同步機(jī)制有什么不同,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。

名稱(chēng)欄目:java中的ThreadLocal本地線程與同步機(jī)制有什么不同
本文鏈接:http://muchs.cn/article42/ihishc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站營(yíng)銷(xiāo)、軟件開(kāi)發(fā)靜態(tài)網(wǎng)站、虛擬主機(jī)、定制開(kāi)發(fā)自適應(yīng)網(wǎng)站

廣告

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

外貿(mào)網(wǎng)站制作