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);
    }


Java8 ThreadLocal类源码 详解_第1张图片

我们可以看到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;
    }

Java8 ThreadLocal类源码 详解_第2张图片



//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();
        
    }
}



你可能感兴趣的:(Java)