JAVA多线程提高三:线程范围内共享变量&ThreadLocal
今天我们学习的是如何在线程自己的范围内达到变量数据的共享,而各个线程之间又是互相独立开来,各自维护的,即我们说的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的更多相关文章
- JAVA多线程学习五:线程范围内共享变量&ThreadLocal
一.概念 可以将每个线程用到的数据与对应的线程号存放到一个map集合中,使用数据时从这个集合中根据线程号获取对应线程的数据,就可以实现线程范围内共享相同的变量. 二.代码 Runnable中的run( ...
- Java多线程——线程范围内共享变量
多个线程访问共享对象和数据的方式 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. package java_ ...
- Java多线程——线程范围内共享变量和ThreadLocal
多个线程访问共享对象和数据的方式 1.如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据,例如,买票系统就可以这么做. package java_ ...
- JAVA 并发编程-线程范围内共享变量(五)
线程范围内共享变量要实现的效果为: 多个对象间共享同一线程内的变量 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsi ...
- -1-5 java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait(),notify(),notifyAll()等方法都定义在Object类中
本文关键词: java 多线程 概念 进程 线程区别联系 java创建线程方式 线程组 线程池概念 线程安全 同步 同步代码块 Lock锁 sleep()和wait()方法的区别 为什么wait( ...
- Java多线程——进程和线程
Java多线程——进程和线程 摘要:本文主要解释在Java这门编程语言中,什么是进程,什么是线程,以及二者之间的关系. 部分内容来自以下博客: https://www.cnblogs.com/dolp ...
- Java多线程系列--“JUC线程池”06之 Callable和Future
概要 本章介绍线程池中的Callable和Future.Callable 和 Future 简介示例和源码分析(基于JDK1.7.0_40) 转载请注明出处:http://www.cnblogs.co ...
- Java多线程系列--“JUC线程池”02之 线程池原理(一)
概要 在上一章"Java多线程系列--“JUC线程池”01之 线程池架构"中,我们了解了线程池的架构.线程池的实现类是ThreadPoolExecutor类.本章,我们通过分析Th ...
- Java多线程系列--“JUC线程池”03之 线程池原理(二)
概要 在前面一章"Java多线程系列--“JUC线程池”02之 线程池原理(一)"中介绍了线程池的数据结构,本章会通过分析线程池的源码,对线程池进行说明.内容包括:线程池示例参考代 ...
随机推荐
- 寒假作业2:简化电梯设计elevator
Github仓库地址:hua-kui 寒假学习计划:学习计划 - 题目背景 一栋10层的大楼(楼层编号1-10),设有一台无限载重的电梯,初始时电梯停在1层.电梯移动1层的耗时为1,在某一层停靠的耗时 ...
- iOS- Autolayout自动布局
1.前言 •在iOS程序中,大部分视图控制器都包含了大量的代码用于设置UI布局,设置控件的水平或垂直位置,以确保组件在不同版本的iOS中都能得到合理的布局 •甚至有些程序员希望在不同的设备使用相同的视 ...
- C语言文法阅读与理解序
<指针>→* | * < 指针> <直接声明符> <标识符> | <直接声明>[]| <直接声明>[常量表达式] | < ...
- 【Leetcode】113Path Sum II
Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given su ...
- IDEA配置Java Web项目
IDEA部署maven tomcat的java web项目的关键配置:
- PHP qrcode 生成二维码
<?php /* 下载地址 : https://sourceforge.net/projects/phpqrcode/ 这里下载的文件名为 phpqrcode-2010100721_1.1.4 ...
- laravel连接多个不同数据库的单例类
在連接多個不同數據庫時,需要寫多個連接,爲了簡化該操作,可以使用該基類,不同的數據庫只要建立好相對應的類繼承該類,就可以使用ORM模型進行操作了. class singletonInstance { ...
- vue+postcss报错: variable '--primary-color' is undefined and used without a fallback
之前vue-cli3引入postcss的配置: https://www.cnblogs.com/XHappyness/p/7676680.html 发现这么一个问题,我再全局global.css中定义 ...
- 大型Java web项目分布式架构演进-分布式部署
http://blog.csdn.net/binyao02123202/article/details/32340283/ 知乎相关文章https://www.zhihu.com/question/2 ...
- BZOJ 1835 基站选址(DP+线段树)
# include <cstdio> # include <cstring> # include <cstdlib> # include <iostream& ...