ThreadLocal的功能测试的代码,以及对照组的测试的代码

ThreadLocal会在每个线程内创建一个变量的副本对象,每个线程都是操作自己的那个变量

但是搜了一圈代码并没有发现好的代码示例,大部分都是讲原理和逻辑,有少部分写了代码的感觉自己都没搞懂,那个代码跑下来也不能证明ThreadLocal的功能

B站有up给出了工具类的ThreadLocal应用代码,感觉不错,但是比较复杂一些些。而且代码不完整

我找到了一个博主的代码,稍作修饰,感觉应该能够证明ThreadLocal的功能,并且我增加了一个对照组

原博如下:https://www.cnblogs.com/codechange/p/8652352.html

 

我的代码如下

package com.interview.bintest.ThreadLoca;


import java.util.ArrayList;
import java.util.List;

/**
 * 测试ThreadLocal的功能
 */
public class ThreadLocalTest {

    //首先创建一个全局静态变量ThreadLocal,这样无论创建多少个类对象,都只有一个ThreadLocal变量
    private  static ThreadLocal<List<String>> threadLocal = new ThreadLocal<>();

    //设置一个存储ThreadLocal数据的方法
    public void setThreadLocal(List<String> value) {

        threadLocal.set(value);
    }

    //设置一个获取ThreadLocal数据的方法,因为存储的是list集合,所以对集合也进行一下遍历
    public void getThreadLocal() {

        threadLocal.get().forEach(name -> System.out.println(Thread.currentThread().getName()+"###" + name ));
    }

    //写一个main方法
    public static void main(String[] args) throws InterruptedException {

        //创建一个包含ThreadLocal属性的类的实例
        final ThreadLocalTest localTest = new ThreadLocalTest();

        //创建第一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //第一个线程创建一个list集合作为值存入threadlocal
                List<String> str1 = new ArrayList<String>();
                //往第一个集合中存入字符串类型的数字
                str1.add("1");
                str1.add("2");
                str1.add("3");
                //将list集合存入threadlocal
                //因为只有一个localTest对象,也只有一个threadlocal,所以多个线程用的是一个类中相同的“threadlocal变量”
                localTest.setThreadLocal(str1);
                //提示已经存入成功
                System.out.println("线程t1存入成功");
                //存入之后线程睡3秒,保证多个线程都已经存入threadlocal再get()输出
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //遍历Threadlocal中的list
                localTest.getThreadLocal();
            }
        },"t1").start();

        //创建第二个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //和上面的线程相同,创建一个list集合存入
                List<String> str2 = new ArrayList<String>();
                //存入字符串类型的a和b
                str2.add("a");
                str2.add("b");
                //将list存入threadlocal
                //因为只有一个localTest对象,也只有一个threadlocal,所以多个线程用的是一个类中相同的“threadlocal变量”
                localTest.setThreadLocal(str2);
                //提示已经存入成功
                System.out.println("t2已经存入成功");
                //同样的线程睡3秒再输出
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                localTest.getThreadLocal();
            }
        },"t2").start();
    }

}

最后的输出结果为

线程t1存入成功
t2已经存入成功
t1###1
t1###2
t1###3
t2###a
t2###b

可以看到,用的同一个threadlocal的变量,但是里面的数据不共享

--------------------------------------------------------------对照组----------------------------------------------------------------------

我增加了一个对照组,使用的是HashMap,因为ThreadLocal底层用的是Entry数组,而HashMap底层用的是Node数组,是Entry的子类,两个是比较像的,而且ThreadLocal用于存储数据的那个内部类就叫做ThreadLocalMap

ThreadLocalMap的key值用的是当前线程的ThreadLocal对象,那我对照组就用当前线程名来作为key了

package com.interview.bintest.ThreadLoca;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

public class ThreadLocalControlTest {
    //首先创建一个全局静态变量HashMap,这样无论创建多少个类对象,都只有一个HashMap变量
    private static HashMap<String,List<String>> hashMap = new HashMap<>();

    //设置一个存储HashMap数据的方法
    public void putHashMap(String name,List<String> value) {

        hashMap.put(name,value);
    }

    //设置一个获取HashMap数据的方法,因为存储的是list集合,所以对集合也进行一下遍历
    public void getHashMap() {
        for(String name : hashMap.keySet()){
            System.out.println(Thread.currentThread().getName()+"###"+hashMap.get(name));
        }
    }

    //写一个main方法
    public static void main(String[] args) throws InterruptedException {

        //创建一个包含HashMap属性的类的实例
        final ThreadLocalControlTest localControlTest = new ThreadLocalControlTest();

        //创建第一个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //第一个线程创建一个list集合作为值存入threadlocal
                List<String> str1 = new ArrayList<String>();
                //往第一个集合中存入字符串类型的数字
                str1.add("1");
                str1.add("2");
                str1.add("3");
                //将list集合存入hashmap
                //因为只有一个localTest对象,也只有一个hashmap,所以多个线程用的是一个类中相同的“hashmap变量”
                localControlTest.putHashMap(Thread.currentThread().getName(),str1);
                //提示已经存入成功
                System.out.println("线程t1存入成功");
                //存入之后线程睡3秒,保证多个线程都已经存入threadlocal再get()输出
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //遍历Threadlocal中的list
                localControlTest.getHashMap();
            }
        },"t1").start();

        //创建第二个线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                //和上面的线程相同,创建一个list集合存入
                List<String> str2 = new ArrayList<String>();
                //存入字符串类型的a和b
                str2.add("a");
                str2.add("b");
                //将list存入hashmap
                //因为只有一个localTest对象,也只有一个hashmap,所以多个线程用的是一个类中相同的“hashmap变量”
                localControlTest.putHashMap(Thread.currentThread().getName(),str2);
                //提示已经存入成功
                System.out.println("t2已经存入成功");
                //同样的线程睡3秒再输出
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                localControlTest.getHashMap();
            }
        },"t2").start();
    }

}

最终输出结果如下

线程t1存入成功
t2已经存入成功
t1###[1, 2, 3]
t1###[a, b]
t2###[1, 2, 3]
t2###[a, b]

t1和t2输出的一模一样

 

tips:其实还可以在主线程中再输出一次存储数据的threadlocal和hashmap,这样也可以证实结论,因为一共有3个线程,主线程也可以把静态变量进行输出,对比效果也很明显,限于时间问题,我就不做测试了,有兴趣的可以自己测试 

 

综上所述,ThreadLocal里的变量各个线程之间互不干扰的结论得到证实

 

posted @ 2021-03-12 23:36  人菜话多帅瓜皮  阅读(175)  评论(0编辑  收藏  举报