Java种ThreadLocal实现

ThreadLocal其实就是为共享变量在每个线程种创建一个副本,然后可以每一个线程可以访问自己的副本变量。

ThreadLocal使用
没有使用threadlocal前:

package threadlocal;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

/**
 * @program: JavaBasic
 * @description: ThreadLocal使用
 * @author: GSY
 * @create: 2020-04-13 10:47
 **/
public class ThreadLocalDemo {

    public static Integer num = 0;

    public static void main(String[] args){

        Thread[] threads = new Thread[5];
        for (int i = 0; i<threads.length;i++){
            threads[i] = new Thread(()->{

                num +=5;
                System.out.println(Thread.currentThread().getName()+":"+num);
            },"Thread--"+i);
        }

        for (int i = 0 ;i <threads.length ; i++){
            threads[i].start();
        }
    }
}

运行结果:
结果1
结果2
这里每一个线程拿到的都不是一个确定的值,它是随机取到的,当我们想要每一个线程都有一个只属于自己的确定的值这时就不可以实现

使用ThreadLocal

package threadlocal;

import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;

/**
 * @program: JavaBasic
 * @description: ThreadLocal使用
 * @author: GSY
 * @create: 2020-04-13 10:47
 **/
public class ThreadLocalDemo {

    public static Integer num = 0;

    private static ThreadLocal<Integer> numlocal = new ThreadLocal<Integer>(){
        protected Integer initialValue(){
            return 0;
        }
    };

    public static void main(String[] args){

        Thread[] threads = new Thread[5];
        for (int i = 0; i<threads.length;i++){
            threads[i] = new Thread(()->{

                int x = numlocal.get().intValue();
               // num +=5;
                x +=5;
                numlocal.set(x);
                System.out.println(Thread.currentThread().getName()+":"+numlocal.get());
            },"Thread--"+i);
        }

        for (int i = 0 ;i <threads.length ; i++){
            threads[i].start();
        }
    }
}

运行结果:
在这里插入图片描述
这时就是每个线程的值都是相互不影响的

ThreadLocal常用方法:
get()方法:获取与当前线程关联的ThreadLocal值。
set(T value)方法:设置与当前线程关联的ThreadLocal值。
initialValue()方法:设置与当前线程关联的ThreadLocal初始值。
remove()将当前线程局部变量的值删除,目的是为了减少内存的占用。

当调用get()方法的时候,若是与当前线程关联的ThreadLocal值已经被设置过,则不会调用initialValue()方法;否则,会调用initialValue()方法来进行初始值的设置。通常initialValue()方法只会被调用一次,除非调用了remove()方法之后又调用get()方法,此时,与当前线程关联的ThreadLocal值处于没有设置过的状态(其状态体现在源码中,就是线程的ThreadLocalMap对象是否为null),initialValue()方法仍会被调用。

get()方法的实现
源码

 public T get() {
        Thread t = Thread.currentThread();
        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();
    }

get()方法开始先得到当前线程的对象t;
然后使用getMap()方法获取线程对应的ThreadLocalMap对象

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

threadLocals是属于Thread的,初始值为null
在这里插入图片描述

   ThreadLocal.ThreadLocalMap threadLocals = null;

这里先判断map是不是空的,通过key来拿到对应的value;
如果value不为null的话就返回。
如果map是空的时候,就调用setInitialValue()方法;然后这时就对ThreadLocalMap进行初始化,然后key就为ThreadLocal实例本身,然后value就为initialValue()方法初始化的值,如果你没有重写这个方法的话,这里的值就是0;

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

在这里插入图片描述

set()方法实现

 public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

实现set()方法的时候也是先获得ThreadLocalMap对象;
如果map部位null的话,给map里面添加值,key就是当前的ThreadLocal对象,然后value是调用这个方法时候的参数。
如果map为null,调用createMap()方法实例化ThreadLocalMap

 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

在这里插入图片描述

发布了34 篇原创文章 · 获赞 15 · 访问量 3211

猜你喜欢

转载自blog.csdn.net/weixin_43404016/article/details/105484257