1. 程式人生 > >Java8 ThreadLocal類原始碼 詳解

Java8 ThreadLocal類原始碼 詳解

JDK裡有一個ThreadLocal這麼一個類,其實起這個名字不是很貼近,這個類相當於給執行緒設定上了一個區域性變數。使得,不會因為多執行緒訪問同一個資源而產生多執行緒同步問題。

因為這個ThreadLocal類裡面放的是每個執行緒都擁有一個副本,執行緒之間彼此不會互相影響。

現在這裡筆者將會從原始碼的實現角度給大家講述一下ThreadLocal實現的原理。

首先我們來看一下set()這個方法的實現。

所有的講解筆者都將以註釋的形式給出。

 public void set(T value) {
     		//拿到當前執行緒物件
      	 Thread t = Thread.currentThread();
	 //拿到一個Map物件,好,那麼問題來了?這個是一個什麼樣的map物件呢??
	 //其實這個ThreadLocalMap物件是ThreadLocal類內部自己實現的一個類似於HashMap這樣一個類

        ThreadLocalMap map = getMap(t);
	//如果map非空,則將當前的ThreadLocal物件和這個set()方法的引數put到這個Map裡面去,
	//如果沒有將其建立。
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }



我們可以看到ThreadLocal這個類裡面確實定義了一個ThreadLocalMap類。裡面的實現和HashMap的差不多,筆者就不點進去看了。

再一個我們點進去get()方法裡面去看以下。

public T get() {
	//拿到當前的執行緒物件
        Thread t = Thread.currentThread();
	//拿到ThreadLocalMap物件,到了這裡我們進去getMap()方法裡面去看一下 
        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();
    }


相比,看到了前面的解釋,  各位讀者也很想進去看一看getMap的實現。

 ThreadLocalMap getMap(Thread t) {
     	//從這裡可以看出 ThreadLocalMap物件是由當前的執行緒物件持有的,
	//但是維護的工作是由ThreadLocal這個類來完成的。
      	 return t.threadLocals;
    }


//createMap方法在當前執行緒物件內部持有的那個ThreadLocalMap物件為空,會呼叫之
//從這裡我們也可以看出是ThreadLocal這個類在維護這個關係
void createMap(Thread t, T firstValue) {
	
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
寫到這裡我們可以下一個結論。

ThreadLocal底層是使用一個自己實現的Map來儲存使用者set()進來的值。   那個map的鍵,即為當前的ThreadLocal物件。

有的朋友可能會問了。現在ThreadLocal只有一個物件。那麼Map裡的值還不是會被其他執行緒所共享。

其實這個不是的,筆者剛開始也是這麼考慮的----------->這個Map裡儲存的應該是當前的Thread物件和值。而不應該是上面那種。

其實不是的。  因為那個ThreadLocal類自己實現的Map物件是每個執行緒物件內部自己持有一份。所以說,每個執行緒物件內的ThreadLocalMap物件是不一樣的。所以,裡面的資料是不會被其他執行緒所共享,都是自己用自己的。

這裡筆者寫了一個demo來證明每個執行緒持有的ThreadLocalMap物件是不同的。

package multiThread;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.CyclicBarrier;


class MyThread implements Runnable
{
    
    private CyclicBarrier cyclicBarrier;
    
    /**
     * 第一個執行緒所持有的ThreadLocalMap物件
     */
    static Object object1 = null;
    
    /**
     * 第二個執行緒所持有的ThreadLocalMap物件
     */
    static Object object2 = null;
    
    public MyThread(CyclicBarrier cyclicBarrier)
    {
        this.cyclicBarrier = cyclicBarrier;
    }
    
    @Override
    public void run()
    {
        ThreadLocal threadLocal = new ThreadLocal();
        
        Thread thread = Thread.currentThread();
        
        Class<?> clazz = ThreadLocal.class;
        
        Method createMap = null;
        
        try
        {
            Method[] methods = clazz.getDeclaredMethods();
            
            Method createMapMethod = null;
    
            /**
             * 通過反射拿到createMap方法的Method物件
             */
            for(Method method : methods)
            {
                if("createMap".equals( method.getName() ))
                {
                    createMapMethod = method;
                    
                }
            }
            
            System.out.println( createMapMethod );
            
            
            if(createMapMethod != null)
            {
                createMapMethod.setAccessible( true );
                createMapMethod.invoke( threadLocal, thread, "helloworld" );
            }
    
            /**
             * 通過執行getMap()方法拿到那個LocalThreadMap物件
             */
            Method getMap = clazz.getDeclaredMethod( "getMap", Thread.class );
            
            getMap.setAccessible( true );
            
            System.out.println( getMap.invoke( threadLocal, thread ) );
            
            if("thread1".equals( Thread.currentThread().getName() ))
            {
                object1 = getMap.invoke( threadLocal, thread );
            }
            if("thread2".equals( Thread.currentThread().getName() ))
            {
                object2 = getMap.invoke( threadLocal, thread );
            }
    
            /**
             * 等兩個執行緒都先拿到那個ThreadLocalMap物件才開始執行CyclicBarrier構造方法裡面的那個Runnable介面的匿名類裡的run方法,
             * 由最後一個完成的執行緒執行。
             */
            cyclicBarrier.await();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        
        
    }
}

public class ThreadLocalTest
{
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InterruptedException, NoSuchMethodException, InstantiationException, InvocationTargetException
    {
        CyclicBarrier cyclicBarrier = new CyclicBarrier( 2, new Runnable()
        {
            @Override
            public void run()
            {
                /**
                 * 判斷兩個執行緒物件內所持有的ThreadLocalMap是否為同一物件
                 */
                System.out.println(MyThread.object1 == MyThread.object2);
            }
        } );
    
        MyThread myThread = new MyThread( cyclicBarrier );
        
        Thread thread1 = new Thread( myThread, "thread1" );
        Thread thread2 = new Thread( myThread, "thread2" );
        thread1.start();
        thread2.start();
        
    }
}



相關推薦

Java8 ThreadLocal原始碼

JDK裡有一個ThreadLocal這麼一個類,其實起這個名字不是很貼近,這個類相當於給執行緒設定上了一個區域性變數。使得,不會因為多執行緒訪問同一個資源而產生多執行緒同步問題。 因為這個ThreadLocal類裡面放的是每個執行緒都擁有一個副本,執行緒之間彼此不會互相影響

java集合原始碼-LinkedList(4)-基於JDK8

LinkedList 裡面還有個具有新增功能的函式,上回學漏了,這回補上。 它就是linkBefore()------在一個非空節點前,插入資料 這裡打上個斷點 點選下一步。先把size除二  ,去比較。具體的這個node()方法,我們之前學過,這裡跳過。這個方法,其實就

java集合原始碼-ArrayList(2)

上次關於ArrayList的結構沒有做總結。這次還是補充在自己部落格裡面吧。 ArrayList繼承自一個抽象類。實現了四個介面。 AbstractList繼承自AbstractCollection。AbstractCollection繼承自Object。 ArrayL

java集合原始碼-ArrayList(5)

上次,測試了java集合類支援遍歷方式的效率比較,今天再通過斷電除錯,去ArrayList底層的迭代器做了什麼。 首先在迭代器這裡打上斷電,(在實際中變數ArrayList最後別用迭代器,因為他很慢) 可以看到這個iterator()方法返回值是一個迭代器,函式體是r

java集合原始碼-ArrayList(1)

       最近在瘋狂的補基礎 在java中 最重要的知識之一 非集合類莫屬。這次在學習java集合類原始碼,採用的是傳統的方法,斷點除錯和寫測試程式碼。由於是剛開始接觸java集合類原始碼。所以一開始只寫了兩句程式碼來測試,畢竟原始碼學習是很緩慢的過程。只能慢慢的啃。在閱

java Object原始碼 及nativ

Java程式碼 package java.lang;   publicclass Object {   /* 一個本地方法,具體是用C(C++)在DLL中實現的,然後通過JNI呼叫。*/  privatestaticnativevoid registerNativ

Java資料結構和算法系列3--ThreadLocal原理

1.ThreadLocal介紹 Java實現多執行緒的2種方式,繼承Thread類和實現Runnable介面。今天我們介紹下另外一種常用的多執行緒類ThreadLocal類。 ThreadLocal在維護變數時,為每個使用變數的執行緒提供了獨立的副本,所以每

openTSDB原始碼之Deferred簡單示例2

openTSDB原始碼詳解之Deferred類簡單示例2 1.示例2 1.1 程式碼 程式程式碼如下: public static void test2() { try { //注意這個時候由 dfd -> dfd List(lstDfd)。但是其型

openTSDB原始碼之Deferred程式碼簡單示例1

openTSDB原始碼詳解之Deferred類程式碼簡單示例1 1.示例1 1.1 程式碼 /** * simplest with only 1 defer * 最簡單的,僅僅只有1個defer */ public static void test

JDK原始碼之File

JDK原始碼詳解之File類 1. 類釋義 2. 類方法 listFiles() File[] listFiles() Returns an array of abstract pathnames denoting the files in the dir

Jdk原始碼之`ProcessBuilder()`

Jdk原始碼詳解之ProcessBuilder()類 1.ProcessBuilder類 2.方法簡介 構造器ProcessBuilder /** Constructs a process builder with the specif

java_集合體系之Collection框架相關抽象介面原始碼——02

java_集合體系之Collection框架相關抽象類介面詳解、原始碼——02 一:Collection相關介面、抽象類結構圖   二:Collection相關         1、介面簡介:                   Collection作為佇列形式儲

Hadoop原始碼之DBOutputFormat

Hadoop 原始碼詳解之 DBOutputFormat 類 1. 類釋義 A OutputFormat that sends the reduce output to a SQL table. 一種將Reduce 輸出到一個SQL表中的輸出格式。 DB

Hadoop原始碼之Mapper

Hadoop原始碼詳解之Mapper類 1. 類釋義 Maps input key/value pairs to a set of intermediate key/value pairs. 將輸入的鍵值對應成一系列的中間鍵值對 Maps are the

Hadoop原始碼之FileOutputFormat

Hadoop 原始碼詳解之FileOutputFormat 類 1. 類釋義 A base class for OutputFormats that read from FileSystems. 一個類從FileSystems讀取 用於OutputFormats 【實在翻

Hadoop 原始碼之FileInputFormat

Hadoop 原始碼詳解之FileInputFormat類【updating…】 1. 類釋義 A base class for file-based InputFormats. 針對基於檔案的 InputFormats 一個基類 FileInputFo

Hadoop原始碼之Job

Hadoop原始碼詳解之Job類 1. 原始碼 包:org.apache.hadoop.mapreduce 繼承的介面有:AutoCloseable,JobContext,org.apache.hadoop.mapreduce.MRJobConfig

Qt: 調色盤QPalette用法(附例項、原始碼

在實際的應用中,經常需要對某個控制元件的顏色外觀,如背景、前景色等,進行設定。Qt中提供的調色盤QPalette類就是專門用於管理控制元件的外觀顯示。QPalette類相當於對話方塊或控制元件的調色盤,管理著控制元件和窗體的所有顏色。每個窗體和控制元件都包含一個QPale

Java多執行緒之隔離技術ThreadLocal原始碼

本篇文章是對ThreadLocal和InheritableThreadLocal,TransmittableThreadLocal的原理和原始碼進行深入分析,並舉例講解,其中前兩個是JDK自帶的。原理相對比較簡單,其解決了單執行緒環境和在單執行緒中又建立執行緒(

OkHttp3原始碼(一Request)

           上次在哪篇部落格看到這句話,我們不重複造輪子不表示我們不需要知道輪子該怎麼造及如何更好的造,我覺得很有道理 對於用到專案的某個開源專案我們不應該只停留在會用的階段,廢話不多說,直接開始okhttp原始碼的學習之路         從上至下我們先從Re