ThreadLocal本地線程和同步機制的比較

ThreadLocal的設計
首先看看ThreadLocal的接口:
Object get() ; // 返回當前線程的線程局部變量副本 protected Object
initialValue(); // 返回該線程局部變量的當前線程的初始值                   
void set(Object value); // 設置當前線程的線程局部變量副本的值
  ThreadLocal3個方法,其中值得注意的是initialValue(),該方法是一個protected
的方法,顯然是爲了子類重寫而特地實現的。該方法返回當前線程在該線程局部變量的初始
值,這個方法是一個延遲調用方法,在一個線程第1次調用get()或者set(Object)時才執行
,而且僅執行1次。ThreadLocal中的確實實現直接返回一個null
protected Object initialValue() { return null; }
  ThreadLocal是如何作到爲每個線程維護變量的副本的呢?其實實現的思路很簡單,
ThreadLocal類中有一個Map,用於存儲每個線程的變量的副本。好比下面的示例實現:java

就至關於存Mapmysql

 這個是ThreadLocal的get方法的實現
 public T get() {
        Thread t = Thread.currentThread();//獲取當前線程
        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與其它同步機制的比較
  ThreadLocal和其它同步機制相比有什麼優點呢?ThreadLocal和其它全部的同步機制都
是爲了解決多線程中的對同一變量的訪問衝突,在普通的同步機制中,是經過對象加鎖來實
現多個線程對同一變量的安全訪問的。這時該變量是多個線程共享的,使用這種同步機制需
要很細緻地分析在何時對變量進行讀寫,何時須要鎖定某個對象,何時釋放該
對象的鎖等等不少。全部這些都是由於多個線程共享了資源形成的。ThreadLocal就從另外一
個角度來解決多線程的併發訪問,ThreadLocal會爲每個線程維護一個和該線程綁定的變
量的副本,從而隔離了多個線程的數據,每個線程都擁有本身的變量副本,從而也就沒有
必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時
,能夠把不安全的整個變量封裝進ThreadLocal,或者把該對象的特定於線程的狀態封裝進
ThreadLocal
  因爲ThreadLocal中能夠持有任何類型的對象,因此使用ThreadLocal get當前線程的值
是須要進行強制類型轉換。但隨着新的Java版本(1.5)將模版的引入,新的支持模版參數
ThreadLocal<T>類將從中受益。也能夠減小強制類型轉換,並將一些錯誤檢查提早到了編
譯期,將必定程度地簡化ThreadLocal的使用。
總結
    固然ThreadLocal並不能替代同步機制,二者面向的問題領域不一樣。同步機制是爲了同
步多個線程對相同資源的併發訪問,是爲了多個線程之間進行通訊的有效方式;而
ThreadLocal是隔離多個線程的數據共享,從根本上就不在多個線程之間共享資源(變量)
,這樣固然不須要對多個線程進行同步了。因此,若是你須要進行多個線程之間進行通訊,
 則使用同步機制;若是須要隔離多個線程之間的共享衝突,可使用ThreadLocal,這將極
大地簡化你的程序,使程序更加易讀、簡潔。web

ThreadLocal常見用途:
存放當前session用戶
存放一些context變量,好比webworkActionContext
存放session,好比Spring hibernate ormsessionsql


例子:用 ThreadLocal 實現每線程 Singleton
        線程局部變量常被用來描繪有狀態單子Singleton) 或線程安全的共享對象,或者是經過把不安全的整個變量封裝進 ThreadLocal,或者是經過把對象的特定於線程的狀態封裝進 ThreadLocal。例如,在與數據庫有緊密聯繫的應用程序中,程序的不少方法可能都須要訪問數據庫。在系統的每一個方法中都包含一個 Connection 做爲參數是不方便的 — 單子來訪問鏈接多是一個雖然更粗糙,但卻方便得多的技術。然而,多個線程不能安全地共享一個 JDBC Connection。如清單 所示,經過使用單子中的 ThreadLocal,咱們就能讓咱們的程序中的任何類容易地獲取每線程 Connection 的一個引用。這樣,咱們能夠認爲 ThreadLocal 容許咱們建立每線程單子。
數據庫

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;
//數據庫鏈接
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);// 指定鏈接類型
			conn = DriverManager.getConnection(url, user, password);// 獲取鏈接
		} catch (Exception e) {
			e.printStackTrace();
		}
		return conn;
	}

}

簡單的實現Mysql鏈接線程安全的一種方式緩存

理論上來講,ThreadLocal是的確是相對於每一個線程,每一個線程會有本身的ThreadLocal。可是上面已經講到,通常的應用服務器都會維護一套線程池。所以,不一樣用戶訪問,可能會接受到一樣的線程。所以,在作基於TheadLocal時,須要謹慎,避免出現ThreadLocal變量的緩存,致使其餘線程訪問到本線程變量。安全

相關文章
相關標籤/搜索