• 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 变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多
    个线程操作这个变量时,实际操作的是自己本地内存里面的变量,从而避免了线程安全问

  • 相关阅读:
    (转载)关于一些对location认识的误区
    Python内置数据结构--列表
    Maven
    Python基础语法
    安装ipython和jupyter
    Python环境安装
    Java多线程
    SpringMVC集成springfox-swagger2自动生成接口文档
    SpringMVC拦截器
    SpringMVC异常处理器
  • 原文地址:https://www.cnblogs.com/anyanpeng/p/14151474.html
Copyright © 2020-2023  润新知