ThreadLocal使用总结

一、ThreadLocal基本使用

1.1使用场景

不同的线程对全局变量进行修改,使用ThreadLocal后会为每个线程创建一个副本,而不会影响其他线程的副本,确保了线程的安全

  private static ThreadLocal<Integer> localvariable=ThreadLocal.withInitial(()->1);
    public static void main(String[] args) {
        Thread threadOne=new Thread(new Runnable() {
            @Override
            public void run() {
                Integer integer = localvariable.get();
                localvariable.set(++integer);
                System.out.println("线程1: "+localvariable.get());
            }
        });
        Thread threadTwo=new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2: "+localvariable.get());
            }
        });
        System.out.println("主线程: "+localvariable.get());
        threadOne.start();
        threadTwo.start();
    }

运行结果:

主线程: 1
线程1: 2
线程2: 1

线程1的修改没有影响到线程2的读取,保证了线程的安全

场景二

类似于全局变量,但是不想被多个线程进行共享

    private static Integer count=0;
    private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
    public static void main(String[] args) {
        for(int i=0;i<10;i++){
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    System.out.println(count);
                }
            };
            fixedThreadPool.execute(runnable);
        }
        count++;
    }

像如上代码,本来是想所有线程都输出初始的count,当主线程累加后,剩下的线程输出的值就变成了1

以上代码执行的结果:

0
0
0
0
1
1
1
1
1
1

那么我们可以用ThreadLocal将原始的全局变量进行保存然后传参给其他的线程,这样就获取的是原始的全局变量

 private static Integer count=0;
    private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
    private static ThreadLocal<Integer> local=new ThreadLocal();
    public static void main(String[] args) {
        local.set(count);
        for(int i=0;i<10;i++){
            Integer localCount = local.get();
            Runnable runnable = new Runnable(){
                @Override
                public void run() {
                    System.out.println(localCount);
                }
            };
            fixedThreadPool.execute(runnable);
        }
        count++;
    }

0
0
0
0
0
0
0
0
0
0

1.2 原理分析

threadLocals = null;
inheritableThreadLocals = null;

Thread类中有一个threadLocals和一个inheritableThreadLocals,他们都是ThreadLocalMap 类型的变量,默认都为null

当第一次调用set方法的时候创建

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

将每个线程的本地变量存放在threadLocals变量中,如果调用线程一直不终止,那么这个本地变量会一直存放在调用线程的ThreadLocals变量里面,所以当不使用本地变量是可以通过调用ThreadLocal变量的remove方法,从当前线程的threadLocals

里面删除该本地变量。

ThreadLocal 是JDK 包提供的,它提供了线程本地变量,也就是如果你创建了一个
ThreadLocal 变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多
个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免了线程安全问

原文地址:https://www.cnblogs.com/anyanpeng/p/14151474.html