线程范围的共享变量

多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象

public class ThreadScopeSharaData {private static  int data = 0 ;public static void main(String[] args) {for(int i = 0 ;i<2 ;i++){new Thread(new Runnable(){@Overridepublic void run() {data = new Random().nextInt();System.out.println(Thread.currentThread().getName()+ " put random data:"+data);new A().get() ;new B().get() ;}}).start() ;}}static class A {public int get(){System.out.println("A from " + Thread.currentThread().getName()+ " get data :" + data);return data ;}}static class B{public int get(){System.out.println("B from " + Thread.currentThread().getName()+ " get data :" + data);return data ;}}
}

模块A ,B都需要访问static的变量data 在线程0中会随机生成一个data值 假设为10 那么此时模块A和模块B在线程0中得到的data的值为10 ;在线程1中 假设会为data赋值为20 那么在当前线程下

模块A和模块B得到data的值应该为20

看程序执行的结果:

Thread-0 put random data:-2009009251
Thread-1 put random data:-2009009251
A from Thread-0 get data :-2009009251
A from Thread-1 get data :-2009009251
B from Thread-0 get data :-2009009251
B from Thread-1 get data :-2009009251
Thread-0 put random data:-2045829602
Thread-1 put random data:-1842611697
A from Thread-0 get data :-1842611697
A from Thread-1 get data :-1842611697
B from Thread-0 get data :-1842611697
B from Thread-1 get data :-1842611697

会出现两种情况
1.由于线程执行速度,新的随机值将就的随机值覆盖 data 值一样
2.data 值不一样,但 A、B线程都

1.使用Map实现线程范围内数据的共享

可是将data数据和当前允许的线程绑定在一块,在模块A和模块B去获取数据data的时候 是通过当前所属的线程去取得data的结果就行了。
声明一个Map集合 集合的Key为Thread 存储当前所属线程 Value 保存data的值,代码如下:

public class ThreadScopeSharaData {private static Map<Thread, Integer> threadData = new HashMap<>();public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " put random 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);}}
}
Thread-0 put random data:-123490895
Thread-1 put random data:-1060992440
A from Thread-0 get data:-123490895
A from Thread-1 get data:-1060992440
B from Thread-0 get data:-123490895
B from Thread-1 get data:-1060992440

2.ThreadLocal实现线程范围内数据的共享

(1)订单处理包含一系列操作:减少库存量、增加一条流水台账、修改总账,这几个操作要在同一个事务中完成,通常也即同一个线程中进行处理,如果累加公司应收款的操作失败了,则应该把前面的操作回滚,否则,提交所有操作,这要求这些操作使用相同的数据库连接对象,而这些操作的代码分别位于不同的模块类中。
(2)银行转账包含一系列操作: 把转出帐户的余额减少,把转入帐户的余额增加,这两个操作要在同一个事务中完成,它们必须使用相同的数据库连接对象,转入和转出操作的代码分别是两个不同的帐户对象的方法。
(3)例如Strut2的ActionContext,同一段代码被不同的线程调用运行时,该代码操作的数据是每个线程各自的状态和数据,对于不同的线程来说,getContext方法拿到的对象都不相同,对同一个线程来说,不管调用getContext方法多少次和在哪个模块中getContext方法,拿到的都是同一个。
4.实验案例:定义一个全局共享的ThreadLocal变量,然后启动多个线程向该ThreadLocal变量中存储一个随机值,接着各个线程调用另外其他多个类的方法,这多个类的方法中读取这个ThreadLocal变量的值,就可以看到多个类在同一个线程中共享同一份数据。
5.实现对ThreadLocal变量的封装,让外界不要直接操作ThreadLocal变量。
(1)对基本类型的数据的封装,这种应用相对很少见。
(2)对对象类型的数据的封装,比较常见,即让某个类针对不同线程分别创建一个独立的实例对象。

public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " put random data:" + data);threadLocal.set(data);new A().get();new B().get();}}).start();}}static class A {public void get() {int data = threadLocal.get();System.out.println("A from " + Thread.currentThread().getName() + " get data:" + data);}}static class B {public void get() {int data = threadLocal.get();System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);}}
}
Thread-0 put random data:-2015900409
Thread-1 put random data:-645411160
A from Thread-0 get data:-2015900409
A from Thread-1 get data:-645411160
B from Thread-0 get data:-2015900409
B from Thread-1 get data:-645411160

优化

public class ThreadLocalTest {private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();//private static ThreadLocal<MyThreadScopeData> myThreadScopeDataThreadLocal = new ThreadLocal<>();public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {int data = new Random().nextInt();System.out.println(Thread.currentThread().getName() + " put random data:" + data);threadLocal.set(data);//                    MyThreadScopeData myThreadScopeData = new MyThreadScopeData();
//                    myThreadScopeData.setName("name" + data);
//                    myThreadScopeData.setAge(data);
//                    myThreadScopeDataThreadLocal.set(myThreadScopeData);//获取与当前线程绑定的实例并设置值  MyThreadScopeData.getThreadInstance().setName("name" + data);MyThreadScopeData.getThreadInstance().setAge(data);new A().get();new B().get();}}).start();}}static class A {public void get() {int data = threadLocal.get();//            MyThreadScopeData myData = myThreadScopeDataThreadLocal.get();
//
//
//            System.out.println("A from " + Thread.currentThread().getName()
//                    + " getMyData: " + myData.getName() + "," + myData.getAge());MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();System.out.println("A from " + Thread.currentThread().getName()+ " getMyData: " + myData.getName() + "," + myData.getAge());}}static class B {public void get() {int data = threadLocal.get();//System.out.println("B from " + Thread.currentThread().getName() + " get data:" + data);MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();System.out.println("B from " + Thread.currentThread().getName()+ " getMyData: " + myData.getName() + "," + myData.getAge());}}
}//一个绑定当前线程的类
class MyThreadScopeData {private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<>();private String name;private int age;private MyThreadScopeData() {}//定义一个静态方法,返回各线程自己的实例//这里不必用同步,因为每个线程都要创建自己的实例,所以没有线程安全问题。public static MyThreadScopeData getThreadInstance() {//获取当前线程绑定的实例MyThreadScopeData instance = map.get();if (instance == null) {instance = new MyThreadScopeData();map.set(instance);}return instance;}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;}}
Thread-1 put random data:-1041517189
Thread-0 put random data:-98835751
A from Thread-1 getMyData: name-1041517189,-1041517189
A from Thread-0 getMyData: name-98835751,-98835751
B from Thread-1 getMyData: name-1041517189,-1041517189
B from Thread-0 getMyData: name-98835751,-98835751

实例:

设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1,写出程序。
1、如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做。

public class SellTicket {//卖票系统,多个窗口的处理逻辑是相同的public static void main(String[] args) {Ticket t = new Ticket();new Thread(t).start();new Thread(t).start();}
}/*** 将属性和处理逻辑,封装在一个类中** @author yang*/
class Ticket implements Runnable {private int ticket = 10;public synchronized void run() {while (ticket > 0) {ticket--;System.out.println("当前票数为:" + ticket);}}
}

2、如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,例如,设计2个线程。一个线程对j增加1,另外一个线程对j减1,银行存取款系统。

public class MultiThreadShareData {private int j;public static void main(String[] args) {MultiThreadShareData multiThreadShareData = new MultiThreadShareData();for(int i=0;i<2;i++){new Thread(multiThreadShareData.new ShareData1()).start();//增加new Thread(multiThreadShareData.new ShareData2()).start();//减少}}//自增private synchronized void Inc(){j++;System.out.println(Thread.currentThread().getName()+" inc "+j);}//自减private synchronized void Dec(){j--;System.out.println(Thread.currentThread().getName()+" dec "+j);}class ShareData1 implements Runnable {public void run() {for(int i=0;i<5;i++){Inc();}}}class ShareData2 implements Runnable {public void run() {for(int i=0;i<5;i++){Dec();}}}
}
Thread-0 inc 1
Thread-0 inc 2
Thread-0 inc 3
Thread-0 inc 4
Thread-0 inc 5
Thread-1 dec 4
Thread-1 dec 3
Thread-2 inc 4
Thread-2 inc 5
Thread-2 inc 6
Thread-2 inc 7
Thread-2 inc 8
Thread-1 dec 7
Thread-1 dec 6
Thread-1 dec 5
Thread-3 dec 4
Thread-3 dec 3
Thread-3 dec 2
Thread-3 dec 1
Thread-3 dec 0

Java多线程多个线程之间共享数据相关推荐

  1. Java高并发编程:多个线程之间共享数据的方式探讨

    内容摘要 多个线程之间共享数据,按照每个线程执行代码是否相同,我们可以采取不同的处理方式,这里通过简单的卖票示例说明了当每个线程执行相同代码的情况,对于多个线程执行不同代码的情况,处理方式比较灵活,这 ...

  2. 如何在两个线程之间共享数据

    两个线程之间共享数据的方式 Java 里面进行多线程通信的主要方式就是共享内存的方式,共享内存主要的关注点有两个:可见 性和有序性原子性.Java 内存模型(JMM)解决了可见性和有序性的问题,而锁解 ...

  3. java 多线程 共享数据_JAVA多线程提高四:多个线程之间共享数据的方式

    多个线程访问共享对象和数据的方式 如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. 如果每个线程执行的代码不同,这 ...

  4. JAVA 并发编程-多个线程之间共享数据(六)

    多线程共享数据的方式: 1,如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,卖票系统就可以这么做. 2,如果每个线程执行的代码不同,这时 ...

  5. Java多线程(Thread)间通信和共享数据

    多线程间如何通信和共享数据,肯定好多小伙伴都不知道, 或者很久之前知道,现在已经忘却,现在我和大家一起复习一下. 一.线程间通信 1.线程间通信:A执行完,B才执行 /*** 线程间通信:A执行完,B ...

  6. java 线程间变量共享_多线程:(五)多个线程之间共享数据

    简单的总结一下多线程共享数据的方式.其实,最重要的,是一个思想,一个面向对象的编程思想的建立. 说两点: 一.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中 ...

  7. python—多线程之线程之间共享数据(Queue)

    一.Queue理解 从一个线程向另一个线程发送数据最安全的方式可能就是使用queue库中的队列了.创建一个被多个线程共享的Queue对象,这些线程通过使用put()和get()操作来向队列中添加或者删 ...

  8. 线程的创建 验证线程之间共享数据 守护线程 线程进程效率对比 锁 死锁 递归锁...

    线程(from threading import Thread):CPU调度的最小单位 线程的两种创建方式:方式一: 1 from threading import Thread 2 def f1(i ...

  9. java 连接两个arraylist,java – 在两个线程之间共享一个ArrayList?

    既然你已经使用了动词'push'和'poll',那么你似乎在寻找一个不是列表的队列. 因此,我认为您正在寻找记录为here的ConcurrentLinkedQueue. 它允许您让UserReques ...

最新文章

  1. Kernel oops panic 调试 (未完待续)
  2. 股票实时行情数据大全
  3. Replation requires the actual server name ... Replication.Utilies
  4. opencv学习笔记8:类型转换
  5. keil c语言 位域,联合体位域在keil c遇到的问题怎样解决?
  6. 小白的springboot之路(十)、全局异常处理
  7. Windows Phone 8初学者开发—第18部分:在页面间导航
  8. python库--pandas--Series
  9. 管理感悟:站在理的一边,不中立
  10. Rust : future库
  11. Cadence Allegro 高亮功能的使用技巧图文教程
  12. 【新书推荐】【2018.07】计算电磁学的MATLAB仿真(第四版)
  13. STM32 HAL库实现US微秒延时函数
  14. 剑指21.调整数组顺序使奇数位于偶数前面 python leetcode
  15. python尼姆游戏_python实现聪明的尼姆游戏(人机对战)
  16. 详解FC交换机基础知识
  17. 如何重新设置苹果id密码_苹果ID密码忘了怎么办?
  18. rot13初学者和python的实现
  19. z-index使用以及失效的处理方法
  20. 【FFmpeg】tbr tbn tbc

热门文章

  1. 数学建模算法与应用_《数学建模算法与应用》笔记【1】
  2. TensorBoard 1.15.0 at http://DESKTOP-DV74NQ2:6006/ 打开html后无法展示解决方案
  3. matplotlib的学习
  4. Linux入门(1)_VMware和系统分区和系统安装和远程登陆管理
  5. 虹软人脸识别SDK - Java服务端的那些事
  6. 第二十:如何把Jenkins+Allure2生成的报告发送邮件(重点超详细)
  7. python for语句_从零开始py个thon3:循环语句(1)
  8. linux sudo输入密码无法获得锁,Linux系统提示无法获得锁/var/lib/dpkg/lock怎么办?
  9. 若依集成jsencrypt实现密码加密传输方式
  10. [Ext JS]treelist实现tooltip