一、概念

可以将每个线程用到的数据与对应的线程号存放到一个map集合中,使用数据时从这个集合中根据线程号获取对应线程的数据,就可以实现线程范围内共享相同的变量。

二、代码

Runnable中的run()方法里面执行Thread.currentThread()都会对应当前Runnable对应的线程,因此A、B中对应的Thread.currentThread()对应所在的Runnable对应的线程

  1. public class ThreadScopeShareData {
  2.  
  3. private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
  4. public static void main(String[] args) {
  5. for(int i=0;i<2;i++){
  6. new Thread(new Runnable(){
  7. @Override
  8. public void run() {
  9. int data = new Random().nextInt();
  10. System.out.println(Thread.currentThread().getName()
  11. + " has put data :" + data);
  12. threadData.put(Thread.currentThread(), data);
  13. new A().get();
  14. new B().get();
  15. }
  16. }).start();
  17. }
  18. }
  19.  
  20. static class A{
  21. public void get(){
  22. int data = threadData.get(Thread.currentThread());
  23. System.out.println("A from " + Thread.currentThread().getName()
  24. + " get data :" + data);
  25. }
  26. }
  27.  
  28. static class B{
  29. public void get(){
  30. int data = threadData.get(Thread.currentThread());
  31. System.out.println("B from " + Thread.currentThread().getName()
  32. + " get data :" + data);
  33. }
  34. }
  35. }

三、ThreadLocal

JDK1.5提供了ThreadLocal类来方便实现线程范围内的数据共享,它的作用就相当于前面中的Map(内部并不是Map),也就是让每个线程拥有自己的值
一个ThreadLocal对象只能记录一个线程内部的一个共享变量,需要记录多个共享数据,可以创建多个ThreadLocal对象,或者将这些数据进行封装,将封装后的数据对象存入ThreadLocal对象中。
线程结束后也可以自动释放相关的ThreadLocal变量,也可以调用ThreadLocal.remove()方法用来更快释放内存。

代码:

  1. public class ThreadLocalTest {
  2.  
  3. private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
  4. public static void main(String[] args) {
  5.  
  6. //启动两个线程
  7. for (int i = 0; i < 2; i++) {
  8. new Thread(new Runnable() {
  9. @Override
  10. public void run() {
  11. //创建每个线程私有的变量
  12. int data = new Random().nextInt(100);
  13. System.out.println(Thread.currentThread().getName()+" has put data: "+data);
  14. //往local里面设置值
  15. threadLocal.set(data);
  16. new A().get();
  17. new B().get();
  18. }
  19. }).start();
  20. }
  21. }
  22.  
  23. static class A{
  24. public void get(){
  25. int data =threadLocal.get();
  26. System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);
  27. }
  28. }
  29.  
  30. static class B{
  31. public void get(){
  32. int data =threadLocal.get();
  33. System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
  34. }
  35. }
  36. }

假设需要保存不止一个值,可以把其他属性的值打包成一个类,然后将该类设置成ThreadLocal的值。

下面代码中,在类MyThreadLocalScopeDate里面定义了一个静态变量Map,用来保存所有线程创建的MyThreadLocalScopeDate,并使用单例使得不管多少线程都只创建一个MyThreadLocalScopeDate对象。

  1. public class ThreadLocalTest {
  2.  
  3. private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
  4. public static void main(String[] args) {
  5.  
  6. //启动两个线程
  7. for (int i = 0; i < 2; i++) {
  8. new Thread(new Runnable() {
  9. @Override
  10. public void run() {
  11. //创建每个线程私有的变量
  12. int data = new Random().nextInt(100);
  13. System.out.println(Thread.currentThread().getName()+" has put data: "+data);
  14. //往local里面设置值
  15. threadLocal.set(data);
  16. //获取自己线程的MyThreadLocalScopeDate实例对象
  17. MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
  18. myData.setName("name"+data);
  19. myData.setAge(data);
  20. new A().get();
  21. new B().get();
  22. }
  23. }).start();
  24. }
  25. }
  26.  
  27. static class A{
  28. public void get(){
  29. int data =threadLocal.get();
  30. System.out.println("A from "+Thread.currentThread().getName()+" has get data: "+data);
  31. MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
  32. System.out.println("A from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
  33. }
  34. }
  35.  
  36. static class B{
  37. public void get(){
  38. int data =threadLocal.get();
  39. System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
  40. MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
  41. System.out.println("B from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
  42. }
  43. }
  44. }
  45.  
  46. class MyThreadLocalScopeDate{//单例模式
  47.  
  48. private MyThreadLocalScopeDate(){};//构造方法私有化
  49. private static ThreadLocal<MyThreadLocalScopeDate> map = new ThreadLocal<MyThreadLocalScopeDate>();//封装MyThreadLocalScopeDate是线程实现范围内共享
  50.  
  51. //思考AB两个线程过来的情况 自己分析 AB都需要的自己的对象 没有关系 所以不需要同步 如果有关系就需要同步了
  52. public static /*synchronized*/MyThreadLocalScopeDate getThreadInstance(){
  53. MyThreadLocalScopeDate instance =map.get();
  54. if(instance==null){
  55. instance = new MyThreadLocalScopeDate();
  56. map.set(instance);
  57. }
  58. return instance;
  59. }
  60.  
  61. private String name;
  62. private int age;
  63. public String getName() {
  64. return name;
  65. }
  66. public void setName(String name) {
  67. this.name = name;
  68. }
  69. public int getAge() {
  70. return age;
  71. }
  72. public void setAge(int age) {
  73. this.age = age;
  74. }
  75. }

出处:https://www.cnblogs.com/pony1223/p/9251641.html

JAVA多线程学习五:线程范围内共享变量&ThreadLocal的更多相关文章

  1. JAVA多线程提高三:线程范围内共享变量&ThreadLocal

    今天我们学习的是如何在线程自己的范围内达到变量数据的共享,而各个线程之间又是互相独立开来,各自维护的,即我们说的ThreadLocal的作用. 一.概念 可以将每个线程用到的数据与对应的线程号存放到一 ...

  2. Java多线程学习篇——线程的开启

    随着开发项目中业务功能的增加,必然某些功能会涉及到线程以及并发编程的知识点.笔者就在现在的公司接触到了很多软硬件结合和socket通讯的项目了,很多的功能运用到了串口通讯编程,串口通讯编程的安卓端就是 ...

  3. JAVA多线程学习七-线程池

    为什么用线程池 1.创建/销毁线程伴随着系统开销,过于频繁的创建/销毁线程,会很大程度上影响处理效率 例如: 记创建线程消耗时间T1,执行任务消耗时间T2,销毁线程消耗时间T3 如果T1+T3> ...

  4. Java多线程学习之线程的取消与中断机制

    任务和线程的启动很容易.在大多数情况下我们都会让他们运行直到结束,或是让他们自行停止.但是,有时我们希望提前结束任务或是线程,可能是因为用户请求取消,或是线程在规定时间内没有结束,或是出现了一些问题迫 ...

  5. JAVA多线程学习十一-线程锁技术

    前面我们讲到了synchronized:那么这节就来将lock的功效. 一.locks相关类 锁相关的类都在包java.util.concurrent.locks下,有以下类和接口: |---Abst ...

  6. Java多线程学习总结--线程概述及创建线程的方式(1)

    在Java开发中,多线程是很常用的,用得好的话,可以提高程序的性能. 首先先来看一下线程和进程的区别: 1,一个应用程序就是一个进程,一个进程中有一个或多个线程.一个进程至少要有一个主线程.线程可以看 ...

  7. Java多线程学习之线程池源码详解

    0.使用线程池的必要性 在生产环境中,如果为每个任务分配一个线程,会造成许多问题: 线程生命周期的开销非常高.线程的创建和销毁都要付出代价.比如,线程的创建需要时间,延迟处理请求.如果请求的到达率非常 ...

  8. Java多线程学习(三)---线程的生命周期

    线程生命周期 摘要: 当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态.在线程的生命周期中,它要经过新建(New).就绪(Runnable).运行(Running).阻塞 ...

  9. Java多线程学习(二)---线程创建方式

    线程创建方式 摘要: 1. 通过继承Thread类来创建并启动多线程的方式 2. 通过实现Runnable接口来创建并启动线程的方式 3. 通过实现Callable接口来创建并启动线程的方式 4. 总 ...

随机推荐

  1. Inverse/Implicit Function Theorem

    目录 4.1 The Inverse Function Theorem The Implicit Function Theorem 4.3 Curves and Surfaces 4.4 The Mo ...

  2. Towards Deep Learning Models Resistant to Adversarial Attacks

    目录 概 主要内容 Note Madry A, Makelov A, Schmidt L, et al. Towards Deep Learning Models Resistant to Adver ...

  3. Least Angle Regression

    目录 引 一些基本的假设 LARS算法 算法 与别的方法结合 LARS与LASSO的关系 LARS 与 Stagewise 代码 Efron B, Hastie T, Johnstone I M, e ...

  4. 三角网格上的寻路算法Part.1—Dijkstra算法

    背景 最近在研究中产生了这样的需求:在三角网格(Mesh)表示的地形图上给出两个点,求得这两个点之间的地面距离,这条距离又叫做"测地线距离(Geodesic)".计算三角网格模型表 ...

  5. [数据结构]FHQ-Treap

    前言(个人评价FHQ-Treap) 这是一个巨佬(名叫范浩强)在冬令营交流的时候提出的数据结构(FHQ:\(\text{你干嘛非要旋转呢?Think Functional!}\))(可以看出FHQ大佬 ...

  6. LC 只出现一次的数字

    Given a non-empty array of integers nums, every element appears twice except for one. Find that sing ...

  7. spring boot 打包war后 部署到外部 tomcat 的具体正确操作【包括修改端口 与 去除请求路径的工程名】

    1.前言 工程做好了,总不能放在idea运行吧?不然怎么把项目放到云服务器呢?[这一篇随笔不讲解发布的云服务器的操作,在其他随笔有详细记载.] 解决的方案是把springboot 工程 打包成war文 ...

  8. Lucene8.5.x全文检索工具

    本文的资源展示: hotword:是热词的文本,比如不是词语的中文,但是是什么人名或者公司名称的词语,需要分词成一个词语的将需要的加入hotword.dic stopword:无意义的词放入的词典,或 ...

  9. Java使用poi实现Word添加水印(仅支持后缀为.docx格式)

    最近要做电子合同,客户提出为了安全性要将合同中都添加水印,这个之前在网上看到过,貌似使用POI很好加.去网上一搜发现,清一色的只有一篇文章,并且这段代码是用不了的:在文章下边的评论里也发现都说用不了, ...

  10. 【C++】自定义数据类型

    自定义数据类型 标签:c++ 目录 自定义数据类型 一.结构体 定义方法: 特点: 成员访问方式: 初始化: 结构数组 指针和动态内存分配: 结构变量作为函数参数: 二.联合 定义方法: 特点: 举例 ...