线程范围内共享数据
2017-12-04 01:04
246 查看
1.线程范围内共享数据示意图
2.ThreadLocal实现线程范围的共享变量
用于实现线程内的数据共享,即对于相同的程序代码,多个模块在同一个线程中运行时要共享一份数据,而在另外线程中运行时又共享另外一份数据我们可以先用所学知识来写一个
public class ThreadScopeShareData { private static int data = 0; public static void main(String[] args) { for(int i=0;i<6;i++) { new Thread(new Runnable() { @Override public void run() { data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data: " + data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ System.out.println("A from " + Thread.currentThread().getName()+" get data: " + data); } } static class B{ public void get(){ System.out.println("B from " + Thread.currentThread().getName()+" get data: " + data); } } }
如果光像上面这样写的话,那毫无疑问,肯定是有问题的,如下图所示并没有实现线程共享
此时,或许很多人就会想到用Map,key为当前线程,value为当前共享的值,这是一个好的思路
public class ThreadScopeShareData { private static Map<Thread,Integer> threadData = new HashMap<Thread,Integer>(); public static void main(String[] args) { for(int i=0;i<6;i++) { new Thread(new Runnable() { @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data: " + data); threadData.put(Thread.currentThread(),data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("A from " + Thread.currentThread().getName()+" get data: " + data); } } static class B{ public void get(){ int data = threadData.get(Thread.currentThread()); System.out.println("B from " + Thread.currentThread().getName()+" get data: " + data); } } }
此时就实现线程内共享数据了
其实对于ThreadLocal来说,它就是一个Map,它的key已经默认为Thread,而你只需要设定它的value值即可使用
用ThreadLocal实现如下
public class ThreadScopeShareData { private static ThreadLocal<Integer> threadData = new ThreadLocal<Integer>(); public static void main(String[] args) { for(int i=0;i<6;i++) { new Thread(new Runnable() { @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data: " + data); threadData.set(data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = threadData.get(); System.out.println("A from " + Thread.currentThread().getName()+" get data: " + data); } } static class B{ public void get(){ int data = threadData.get(); System.out.println("B from " + Thread.currentThread().getName()+" get data: " + data); } } }
3.ThreadLocal的应用场景
A.订单处理包含一系列操作
减少库存量,增加一条流水台账,修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中B.银行转账包含一系列操作
把转出账户的月减少,把转入账户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的账户对象的方法C.例如Struts2的ActionContext
同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个4.对ThreadLocal的封装
实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量对基本类型的数据的封装,这种应用相对很少见
对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象
总结
一个ThreadLocal代表一个变量,故其中里只能放一个数据,你有两个变量都要线程范围内共享,则要定义两个ThreadLocal对象.如果有一百个变量要线程共享呢?请先定义一个对象来装这一百个变量,然后在ThreadLocal中存储这一对象
你首先就会想要把这一百个数据封装成一个对象
public class ThreadLocalTest { private static ThreadLocal<Integer> x = new ThreadLocal<Integer>(); private static ThreadLocal<MyThreadScopeData> myThreadScopeDataThreadLocal = new ThreadLocal<MyThreadScopeData>(); public static void main(String[] args) { for (int i = 0; i < 3; i++){ new Thread(new Runnable() { @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data: " + data); x.set(data); MyThreadScopeData myData = new MyThreadScopeData(); myData.setName("name"+data); myData.setAge(data); myThreadScopeDataThreadLocal.set(myData); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = x.get(); System.out.println("A from " + Thread.currentThread().getName()+" get data: " + data); MyThreadScopeData myData = myThreadScopeDataThreadLocal.get(); System.out.println("A from " + Thread.currentThread().getName() +" getData:" + myData.getName()+", " + myData.getAge()); } } static class B{ public void get(){ int data = x.get(); System.out.println("B from " + Thread.currentThread().getName()+" get data: " + data); MyThreadScopeData myData = myThreadScopeDataThreadLocal.get(); System.out.println("B from " + Thread.currentThread().getName() +" getData:" + myData.getName()+", " + myData.getAge()); } } } class MyThreadScopeData{ private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
不过思路挺乱的呀,下面有更加优雅的方式
巧妙的采用单例模式
public class ThreadLocalTest { private static ThreadLocal<Integer> x = new ThreadLocal<Integer>(); private static ThreadLocal<MyThreadScopeData> myThreadScopeDataThreadLocal = new ThreadLocal<MyThreadScopeData>(); public static void main(String[] args) { for (int i = 0; i < 3; i++){ new Thread(new Runnable() { @Override public void run() { int data = new Random().nextInt(); System.out.println(Thread.currentThread().getName() + " has put data: " + data); x.set(data); MyThreadScopeData.getThreadInstance().setName("name"+data);//拿到个与本线程有关的实例对象 MyThreadScopeData.getThreadInstance().setAge(data); new A().get(); new B().get(); } }).start(); } } static class A{ public void get(){ int data = x.get(); System.out.println("A from " + Thread.currentThread().getName()+" get data: " + data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out.println("A from " + Thread.currentThread().getName() +" getData:" + myData.getName()+", " + myData.getAge()); } } static class B{ public void get(){ int data = x.get(); System.out.println("B from " + Thread.currentThread().getName()+" get data: " + data); MyThreadScopeData myData = MyThreadScopeData.getThreadInstance(); System.out.println("B from " + Thread.currentThread().getName() +" getData:" + myData.getName()+", " + myData.getAge()); } } } class MyThreadScopeData{//线程数据共享实例设计 private MyThreadScopeData(){} public static /*synchronized*/ MyThreadScopeData getThreadInstance(){//单例模式 MyThreadScopeData instance = map.get();//此时不需要加互斥 if(instance==null){ instance = new MyThreadScopeData(); map.set(instance); } return instance; //饥汉模式如果在多线程模式下,必须方法上加上互斥 /*if(instance == null){ instance = new MyThreadScopeData(); } return instance;*/ } private static MyThreadScopeData instance = new MyThreadScopeData();//别人还没调用instance,它就已经new出来了 //private static MyThreadScopeData instance = null;饥汉模式 private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
相关文章推荐
- 线程局部范围内数据共享
- 黑马程序员-线程范围内数据共享
- java多线程:4、线程范围内的数据共享_公共变量
- 多线程(三) 实现线程范围内模块之间共享数据及线程间数据独立(ThreadLocal)
- 多线程_线程范围内数据共享
- 多线程并发库高级应用 之 线程范围内共享数据
- Java基础——线程范围内的共享数据概念和作用
- java线程范围内的数据共享
- 线程范围内共享数据(二)
- 【多线程】-线程范围内共享数据的两种方式
- 线程范围内共享数据
- 多线程(四) 实现线程范围内模块之间共享数据及线程间数据独立(Map集合)
- 线程范围内共享数据(一)
- ThreadLocal实现:java线程范围内的共享数据,线程外独立
- Java基础——ThreadLocal实现线程范围内的数据共享
- Java并发05---线程范围内的共享数据
- 多线程(四) 实现线程范围内模块之间共享数据及线程间数据独立(Map集合)
- Java中如何实现单个线程范围内的数据共享
- 线程范围内共享数据
- 多线程之线程范围内的数据共享ThreadLocal