今天我们学习的是如何在线程自己的范围内达到变量数据的共享,而各个线程之间又是互相独立开来,各自维护的,即我们说的ThreadLocal的作用。

一、概念

可以将每个线程用到的数据与对应的线程号存放到一个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;
}
}

参考资料:

《多线程视频》张孝祥

JAVA多线程提高三:线程范围内共享变量&ThreadLocal的更多相关文章

  1. JAVA多线程学习五:线程范围内共享变量&ThreadLocal

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

  2. Java多线程——线程范围内共享变量

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

  3. Java多线程——线程范围内共享变量和ThreadLocal

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

  4. JAVA 并发编程-线程范围内共享变量(五)

    线程范围内共享变量要实现的效果为: 多个对象间共享同一线程内的变量 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsi ...

  5. -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中

     本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁  sleep()和wait()方法的区别 为什么wait( ...

  6. Java多线程——进程和线程

    Java多线程——进程和线程 摘要:本文主要解释在Java这门编程语言中,什么是进程,什么是线程,以及二者之间的关系. 部分内容来自以下博客: https://www.cnblogs.com/dolp ...

  7. Java多线程系列--“JUC线程池”06之 Callable和Future

    概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...

  8. Java多线程系列--“JUC线程池”02之 线程池原理(一)

    概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...

  9. Java多线程系列--“JUC线程池”03之 线程池原理(二)

    概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...

随机推荐

  1. Mininet介绍及安装

    什么是Mininet Mininet是由一些虚拟的终端节点(end-hosts).交换机.路由器连接而成的一个网络仿真器,它采用轻量级的虚拟化技术使得系统可以和真实网络相媲美. Mininet可以很方 ...

  2. centos7环境下mysql安装

    1.去官网下载合适的yum源安装包 https://dev.mysql.com/downloads/repo/yum/ 2.yum 本地安装 命令:yum localinstall mysql57-c ...

  3. Java中的生产者、消费者问题

    Java中的生产者.消费者问题描述: 生产者-消费者(producer-consumer)问题, 也称作有界缓冲区(bounded-buffer)问题, 两个进程共享一个公共的固定大小的缓冲区(仓库) ...

  4. Notepad++如何多视图(分屏)显示

    Notepad++ v6.6.7 当需要同时查阅或者编辑多个文件时,正是多视图功能大显身手的时候. 可以在你想要在另一边预览操作的文件名字(在工具栏和文件内容之间)上,单击右键,如下图所示,选择移动到 ...

  5. 第二章 script元素

    <script>元素  async:可选.表示应该立即下载脚本,但不应妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本.只对外部脚本文件有效.  charset:可选.表示通过 ...

  6. eclipse取消validation验证

    点击按钮如下:window-Preferences-Validation.如图. 然后把build里面的都取消.即可.

  7. vue知识拓展

    组件 *组件里面如果要放数据:        data必须是函数的形式,函数必须返回一个对象(json),有的时候我们自己创建的组件需要使用到自己的数据,此外组建中也可以放入自己的其他的比如事件之类的 ...

  8. 最简单的Linux下apache+mysql+php安装

    转载:http://www.jb51.net/article/29843.htm ubuntu下需要先更新系统后 流程笔记: 1.打开终端,输入“sudo apt-get install apache ...

  9. Java Map 在put值时value值不被覆盖

    一.问题描述 最近在代码开发中遇到一个问题,在往Map中put文件路径值然后把Map放到List中去时,遇到问题是Map的后一个值总是把前一个值覆盖,导致最后Map中只有一个值. 二.解决办法(有如下 ...

  10. Django新手图文教程-转发

    转发自:http://www.cnblogs.com/Leo_wl/p/5824541.html 一.Django简介 百度百科:开放源代码的Web应用框架,由Python语言编写...... 重点: ...