微前端架构如何改变企业的开发模式与效率提升
576
2022-09-25
ThreadLocal深入理解 修订版
本文是传智博客多线程视频的学习笔记
ThreadLocal是一个和线程安全相关的类。
它能干什么? 能保证在一个线程内,某个变量的全局共享。
说的很模糊,咱们看一个图
线程1里面的数据,应该在线程1范围内的模块a,b,c都能访问。 线程2里面的数据,应该在线程3范围内的模块a,b,c都能访问。 且线程1,2之间数据不会混淆。 那它有什么用呢? 举个例子,银行的转账包含两步,存款和取款,时候如果在存款取款中间出了问题,就得回滚;如果一切正常等整个交易完成了再commit,而调用commit的对象是Connection。那你说,如果多个线程共用一个Connection会发生什么问题?
一个非线程安全的例子
在我们讲述ThreadLocal之前,我们先看一个例子。
import java.util.Random;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class ThreadScopeDataShare { static private int data = 0; public static void main(String[] args) { ExecutorService threadPool = Executors.newCachedThreadPool(); for (int i = 0; i < 2; i++) { threadPool.execute(new Runnable() { @Override public void run() { int data2= new Random().nextInt(100); System.out.println(Thread.currentThread().getName()+" put "+data2); data=data2; try { Thread.sleep(1000); //为什么要睡1秒 大家懂吗? } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } new A().get(); new B().get(); } }); } threadPool.shutdown(); } public static int getData() { return data; }}class A { public int get() { int data = ThreadScopeDataShare.getData(); System.out .println("a "+Thread.currentThread().getName() + " getdata " + data); return data; }}class B { public int get() { int data = ThreadScopeDataShare.getData(); System.out .println("b "+Thread.currentThread().getName() + " getdata " + data); return data; }}
在我们设想中,应该是线程1放的数据,在线程1中,模块A与模块B取得的数据应该是一致的。同理,线程2里面放的数据,工作再线程2下的模块A模块B取得的数据也应该是一致的。 可是上面的代码的运行结果却是: pool-1-thread-1 put 90 pool-1-thread-2 put 78 a pool-1-thread-2 getdata 78 b pool-1-thread-2 getdata 78 a pool-1-thread-1 getdata 78 b pool-1-thread-1 getdata 78
改进版
我们新建一个map,key是当前线程,value是我们要保存的数据。 那么就可以保证每个线程的各个模块取得的数据都是一致的。
public class ThreadScopeShareData3 { private static Map
运行结果
pool-1-thread-1 put 2 pool-1-thread-2 put 99 A from pool-1-thread-2 get data :99 A from pool-1-thread-1 get data :2 B from pool-1-thread-1 get data :2 B from pool-1-thread-2 get data :99
ThreadLocal的简单介绍
早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。 当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。 我们先看应用再讲原理,然后再讲一个实际的应用。 第一个应用
public class ThreadLocalTest { private static ThreadLocal
Thread-0 has put data :67 A from Thread-0 get data :67 B from Thread-0 get data :67 Thread-1 has put data :221 A from Thread-1 get data :221 B from Thread-1 get data :221 完全符合我们的要求。 这里有个问题: 如果一个线程能要共享多个变量怎么做? private static ThreadLocal
如果变量没有关系,那就包装成一个map。
(当然一个线程如果要共享多个变量,那么分别设置为x,y也是可以的)
这样可以不?
import java.util.Random;public class ThreadLocalTest3 { private static ThreadLocal
可以,不过对用户来说暴露了ThreadLocal的应用,我们希望在调用的时候,ThreadLocal对用户是透明的。 换句话说,我们得把ThreadLocal包装起来。
import java.util.Random;public class ThreadLocalTest2 { public static void main(String[] args) { for(int i=0;i<2;i++){ new Thread(new Runnable(){ @Override public void run() { int data = new Random().nextInt(500); MyThreadScopeData.getThreadInstance().setName("name" + data); MyThreadScopeData.getThreadInstance().setAge(data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out.println("A from " + Thread.currentThread().getName() + " getMyData: " + myData.getName() + "," + myData.getAge()); } } //省略Class B}class MyThreadScopeData{ private MyThreadScopeData(){} public static MyThreadScopeData getThreadInstance(){ MyThreadScopeData instance = map.get(); if(instance == null){ instance = new MyThreadScopeData(); map.set(instance); } return instance; } private static ThreadLocal
关于上面的单例模式可以参考
现在重头戏来了,看看ThreadLocal实现的原理。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~