一、概念

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

二、代码

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

public class ThreadScopeShareData {

    private static Map<Thread, Integer> threadData = new HashMap<Thread, Integer>();
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();
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

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

代码:

public class ThreadLocalTest {  

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
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(100);
System.out.println(Thread.currentThread().getName()+" has put data: "+data);
//往local里面设置值
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()+" has get data: "+data);
}
} static class B{
public void get(){
int data =threadLocal.get();
System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
}
}
}

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

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

public class ThreadLocalTest {  

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
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(100);
System.out.println(Thread.currentThread().getName()+" has put data: "+data);
//往local里面设置值
threadLocal.set(data);
//获取自己线程的MyThreadLocalScopeDate实例对象
MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
myData.setName("name"+data);
myData.setAge(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()+" has get data: "+data);
MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
System.out.println("A from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
}
} static class B{
public void get(){
int data =threadLocal.get();
System.out.println("B from "+Thread.currentThread().getName()+" has get data: "+data);
MyThreadLocalScopeDate myData = MyThreadLocalScopeDate.getThreadInstance();
System.out.println("B from "+Thread.currentThread().getName()+" has get MyThreadLocalScopeDate name: "+myData.getName()+" , age: "+myData.getAge());
}
}
} class MyThreadLocalScopeDate{//单例模式 private MyThreadLocalScopeDate(){};//构造方法私有化
private static ThreadLocal<MyThreadLocalScopeDate> map = new ThreadLocal<MyThreadLocalScopeDate>();//封装MyThreadLocalScopeDate是线程实现范围内共享 //思考AB两个线程过来的情况 自己分析 AB都需要的自己的对象 没有关系 所以不需要同步 如果有关系就需要同步了
public static /*synchronized*/MyThreadLocalScopeDate getThreadInstance(){
MyThreadLocalScopeDate instance =map.get();
if(instance==null){
instance = new MyThreadLocalScopeDate();
map.set(instance);
}
return instance;
} 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;
}
}

出处: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. 排列组合 "n个球放入m个盒子m"问题 总结

    求,盒子都可以分成是否不能区分,和能区分,还能分成是否能有空箱子,所以一共是8种情况,我们现在来一一讨论. 1.球同,盒不同,无空箱 C(n-1,m-1), n>=m0, n<m 使用插板 ...

  2. 美和易思 MOOT去鼠标检测,快进,倍速,自动下一章

    F12 放到 console 直接运行即可 或者油猴添加新脚本 核心去除网页绑定焦点事件代码: if (!-[1,] && !window.XMLHttpRequest || navi ...

  3. 编写Java程序,使用JFrame创建一个窗体

    返回本章节 返回作业目录 需求说明: 使用JFrame创建一个窗体 实现思路: 使用JFrame创建窗体的思路 定义一个窗体对象f,窗体名称为"一个简单窗口" 设置窗体左上角与显示 ...

  4. 04.python哈希表

    python哈希表 集合Set 集合,简称集.由任意个元素构成的集体.高级语言都实现了这个非常重要的数据结构类型. Python中,它是可变的.无序的.不重复的元素的集合. 初始化 set() -&g ...

  5. 【PowerShell】格式化输出字符串

    1 '{0:d4}' -f 10 2 '数字的补零';{} 3 '{0:f4}' -f 10 4 '保留小数位数';{} 5 '{0:p2}' -f 0.4567 6 '转换为百分比';{} 7 '{ ...

  6. PowerShell 管道符之Select的使用方法【二】

    这次讲解Select中的第二个方法:String 在我们的ISE编辑器中输入如下命令 Select-String - 可以了解到,原来这是正则表达式,它提供了一些额外的正则方法.具体如何使用,可以自行 ...

  7. spring security 动态 修改当前登录用户的 权限

    1.前言 spring security 可以获取当前登录的用户信息,同时提供了接口 来修改权限列表信息 , 使用这个方法 ,可以动态的修改当前登录用户权限. 那么问题来了... 如果我是管理员 ,如 ...

  8. 公网ip定位原理-心得

    1.前言 正在做一个根据公网ip来定位到大体的位置,一般是精确到城市或地区, 如果想要精确到街道和地图一一对应,那得使用GPS才可以,这里不讨论. 2.科普 公网也就是外网,由运营商的机房服务器自动给 ...

  9. antd中的form表单 initialValue导致数据不更新问题

    初步理解 : initialValue就是所谓的defaultValue,只会在第一次赋值的时候改变,却又有一些不同,因为 initialValue又会因其他改动而改变. 然而当获取的数据重新上来要渲 ...

  10. 解决ubuntu 18.04(桌面版)搜狗输入法不能正常使用的问题

    ubuntu下搜狗输入法的配置文件在~/.config目录下,一般有三个目录SogouPY.SogouPY.users.sogou-qimpanel 执行命令 $ cd ~/.config $ rm ...