ThreadLocal介绍
并发程序最关键的一方面就是数据共享。当你创建了一个实现了Runable
ThreadLocal为每个使用它的线程提供单独的线程局部变量副本,每个线程都只能看到与自己关联的值,而不知道其他线程可能正在使用或者修改它们自己的副本。
ThreadLocal采用空间换时间的方式来解决线程安全问题。ThreadLocal会把共享变量复制一份到本地线程内存中,然后在自己的线程内对变量副本进行操作,各个线程只操作自己的变量副本而不影响其他线程的变量副本。
ThreadLocal 使用
代码一:
/** * @author Aaron * @Date 2019/4/16 21:42 **/ public class ThreadLocalBean { private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 10; } }; public Integer get(){ return threadLocal.get(); } public void set(){ threadLocal.set(get() + 10); } public static void main(String[] args) { ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); System.out.println(threadLocal.get()); } }
代码二:
/** * @author Aaron * @Date 2019/4/15 16:40 **/ public class ThreadLocalDemo { public static void main(String[] args) { ThreadLocalBean bean = new ThreadLocalBean(); TempThread tempThread1 = new TempThread(bean); TempThread tempThread2 = new TempThread(bean); Thread thread1 = new Thread(tempThread1 , "thread1"); Thread thread2 = new Thread(tempThread2 , "thread2"); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("bean value:"+bean.get()); } static class TempThread implements Runnable{ ThreadLocalBean bean; public TempThread(ThreadLocalBean bean){ this.bean = bean; } @Override public void run() { for (int i = 0; i < 5; i++) { bean.set(); } System.out.println(Thread.currentThread().getName()+"---"+bean.get()); } } } 运行结果 thread2---60 thread1---60 bean value:10
从运行结果我们发现,在thread2和thread1分别调用同一个ThreadLocalBean 的set()方法,两者的运行结果相同并且互不影响,同时这两线程对bean的操作也没有影响到bean的ThreadLocal里的值。
ThreadLocal使用场景
当你在做一个电商应用的时候,你有一个需求是为每个用户访问controller时生成一个唯一的事务ID,并且为了登录需要把这个事务ID传给业务逻辑层。一个解决方案就是把事务ID传给所有业务方法,这样的话代码就是变得冗余也没必要这样。
为了解决这个,你可以使用ThreadLocal局部变量。你可以在controller 或者预处理拦截器中生成一个事务ID,然后把它设置到ThreadLocal变量里面,之后不管什么方法调用controller里面方法,它们都能够从ThreadLocal获取到事务ID。这样controller将会处理更多的请求,并且每个请求在框架层面都是互相隔离的,事务id对每个线程都是惟一的,并且可以从线程的所有执行路径访问它