Java线程范围变量——ThreadLocal的模拟和解释

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
数据可视化DataV,5个大屏 1个月
简介:

一、测试代码

public class XY_ThreadData
{
 private static Integer data = 0;
 private static Map<Thread, Integer> map = new HashMap<Thread, Integer>();
 private static ThreadLocal<Integer> local = new ThreadLocal<Integer>();

 public static void setData(Integer value)
 {
  data = value;
 }

 public static Integer getData()
 {
  System.out.println("ThreadName:" + Thread.currentThread() + " data value:" + data);
  return data;
 }

 public static void setMapData(Integer value)
 {
  map.put(Thread.currentThread(), value);
 }

 public static Integer getMapData()
 {
  Object obj = map.get(Thread.currentThread());
  System.out.println("ThreadName:" + Thread.currentThread() + "map value:" + obj);
  return Integer.parseInt(obj.toString());
 }

 public static void setThreadLocalData(Integer value)
 {
  local.set(value);
 }

 public static Integer getThreadLocalData()
 {
  Object obj = local.get();
  System.out.println("ThreadName:" + Thread.currentThread() + "threadlocal value:" + obj);
  return Integer.parseInt(obj.toString());
 }
}

public class XY_ThreadData_Test
{
 public static void main(String[] args)
 {
  for (int i = 0; i < 10; i++)
  {
   new Thread(new Runnable() {
    public void run()
    {
     final int value = new Random().nextInt(); // 每个线程自己创建的变量   
     XY_ThreadData.setData(value);
     XY_ThreadData.getData();
    }
   }).start();
  }

 }
}
ThreadName:Thread[Thread-3,5,main] data value:1046062244
ThreadName:Thread[Thread-6,5,main] data value:-879673875
ThreadName:Thread[Thread-2,5,main] data value:-125397465
ThreadName:Thread[Thread-4,5,main] data value:-1546413071
ThreadName:Thread[Thread-0,5,main] data value:754770101
ThreadName:Thread[Thread-8,5,main] data value:-1666786926
ThreadName:Thread[Thread-5,5,main] data value:-1666786926
ThreadName:Thread[Thread-9,5,main] data value:1046062244
ThreadName:Thread[Thread-1,5,main] data value:269410746
ThreadName:Thread[Thread-7,5,main] data value:269410746
分析:可以看到以下两个线程中data的值时一样的,没有做到各个线程变量独一份
ThreadName:Thread[Thread-8,5,main] data value:-1666786926
ThreadName:Thread[Thread-5,5,main] data value:-1666786926


public class XY_ThreadData_Test
{
 public static void main(String[] args)
 {
  for (int i = 0; i < 10; i++)
  {
   new Thread(new Runnable() {
    public void run()
    {
     final int value = new Random().nextInt();   
     XY_ThreadData.setMapData(value);
     XY_ThreadData.getMapData();
    }
   }).start();
  }

 }
}
ThreadName:Thread[Thread-0,5,main]map value:-1138167111
ThreadName:Thread[Thread-4,5,main]map value:-1545929782
ThreadName:Thread[Thread-6,5,main]map value:-1612385717
ThreadName:Thread[Thread-3,5,main]map value:-1390594683
ThreadName:Thread[Thread-8,5,main]map value:518506934
ThreadName:Thread[Thread-2,5,main]map value:1583239372
ThreadName:Thread[Thread-5,5,main]map value:995578601
ThreadName:Thread[Thread-1,5,main]map value:-916627474
ThreadName:Thread[Thread-7,5,main]map value:-960206804
ThreadName:Thread[Thread-9,5,main]map value:-1187504747
分析:模拟线程变量独一份,无重复


public class XY_ThreadData_Test
{
 public static void main(String[] args)
 {
  for (int i = 0; i < 10; i++)
  {
   new Thread(new Runnable() {
    public void run()
    {
     final int value = new Random().nextInt();
     XY_ThreadData.setThreadLocalData(value);
     XY_ThreadData.getThreadLocalData();
    }
   }).start();
  }

 }
}
ThreadName:Thread[Thread-1,5,main]threadlocal value:935024745
ThreadName:Thread[Thread-4,5,main]threadlocal value:1207176846
ThreadName:Thread[Thread-7,5,main]threadlocal value:-1503260374
ThreadName:Thread[Thread-9,5,main]threadlocal value:-1538563684
ThreadName:Thread[Thread-6,5,main]threadlocal value:955259906
ThreadName:Thread[Thread-8,5,main]threadlocal value:894428541
ThreadName:Thread[Thread-3,5,main]threadlocal value:730986356
ThreadName:Thread[Thread-2,5,main]threadlocal value:-540225655
ThreadName:Thread[Thread-5,5,main]threadlocal value:-2003809947
ThreadName:Thread[Thread-0,5,main]threadlocal value:1917431015
分析:线程变量独一份,无重复

 

二、ThreadLocal分析

要点1
ThreadLocal不是用来解决共享对象的多线程访问问题的,一般情况下通过ThreadLocal.set()到线程中的对象是该线程自己使用的对象,其他线程是不需要访问的,也访问不到的。各个线程中访问的是不同的对象。

 

要点2
说ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new对象的操作来创建的对象,每个线程创建一个,不是什么对象的拷贝或副本。通ThreadLocal.set()将这个新创建的对象的引用保存到各线程的自己的一个map中,每个线程都有这样一个map,执行ThreadLocal.get()时,各线程从自己的map中取出放进去的对象,因此取出来的是各自自己线程中的对象,ThreadLocal实例是作为map的key来使用的。

 

要点3
如果ThreadLocal.set()进去的东西本来就是多个线程共享的同一个对象,那么多个线程的ThreadLocal.get()取得的还是这个共享对象本身,还是有并发访问问题。


更多关于ThreadLocal信息请参看:http://www.iteye.com/topic/103804

相关实践学习
Github实时数据分析与可视化
基于Github Archive公开数据集,将项目、行为等20+种事件类型数据实时采集至Hologres进行分析,并搭建可视化大屏。
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
13天前
|
存储 Java
java基础(7)变量以及变量的分类
Java变量是内存中存储数据的基本单元,包含数据类型、名称和字面值。变量的数据类型决定了分配的内存空间大小。变量声明格式为“数据类型 变量名;”,变量名应符合标识符命名规范。变量可以重新赋值,但数据类型需一致。变量可以一行声明多个,作用域决定了变量的可用范围。变量分为局部变量和成员变量,局部变量定义在方法体内,成员变量定义在方法体外、类体内。
28 2
|
13天前
|
算法 安全 Java
JAVA并发编程系列(12)ThreadLocal就是这么简单|建议收藏
很多人都以为TreadLocal很难很深奥,尤其被问到ThreadLocal数据结构、以及如何发生的内存泄漏问题,候选人容易谈虎色变。 日常大家用这个的很少,甚至很多近10年资深研发人员,都没有用过ThreadLocal。本文由浅入深、并且才有通俗易懂方式全面分析ThreadLocal的应用场景、数据结构、内存泄漏问题。降低大家学习啃骨头的心理压力,希望可以帮助大家彻底掌握并应用这个核心技术到工作当中。
|
1月前
|
存储 Java 开发者
【Java新纪元启航】JDK 22:解锁未命名变量与模式,让代码更简洁,思维更自由!
【9月更文挑战第7天】JDK 22带来的未命名变量与模式匹配的结合,是Java编程语言发展历程中的一个重要里程碑。它不仅简化了代码,提高了开发效率,更重要的是,它激发了我们对Java编程的新思考,让我们有机会以更加自由、更加创造性的方式解决问题。随着Java生态系统的不断演进,我们有理由相信,未来的Java将更加灵活、更加强大,为开发者们提供更加广阔的舞台。让我们携手并进,共同迎接Java新纪元的到来!
50 11
|
1月前
|
存储 Java 程序员
优化Java多线程应用:是创建Thread对象直接调用start()方法?还是用个变量调用?
这篇文章探讨了Java中两种创建和启动线程的方法,并分析了它们的区别。作者建议直接调用 `Thread` 对象的 `start()` 方法,而非保持强引用,以避免内存泄漏、简化线程生命周期管理,并减少不必要的线程控制。文章详细解释了这种方法在使用 `ThreadLocal` 时的优势,并提供了代码示例。作者洛小豆,文章来源于稀土掘金。
|
1月前
|
存储 Ubuntu Linux
C语言 多线程编程(1) 初识线程和条件变量
本文档详细介绍了多线程的概念、相关命令及线程的操作方法。首先解释了线程的定义及其与进程的关系,接着对比了线程与进程的区别。随后介绍了如何在 Linux 系统中使用 `pidstat`、`top` 和 `ps` 命令查看线程信息。文档还探讨了多进程和多线程模式各自的优缺点及适用场景,并详细讲解了如何使用 POSIX 线程库创建、退出、等待和取消线程。此外,还介绍了线程分离的概念和方法,并提供了多个示例代码帮助理解。最后,深入探讨了线程间的通讯机制、互斥锁和条件变量的使用,通过具体示例展示了如何实现生产者与消费者的同步模型。
|
2月前
|
存储 安全 Java
Java 中的 ThreadLocal 变量
【8月更文挑战第22天】
36 4
|
24天前
|
JavaScript 前端开发 Java
通过JUnit5访问Java静态、私有、保护变量和方法
在《通过Gtest访问C++静态、私有、保护变量和方法》一文中介绍了如何通过Gtest访问C++静态、私有、保护变量和方法,本文介绍如何通过Junit5访问Java静态、私有、保护变量和方法。
19 0
|
2月前
|
存储 安全 Java
在 Java 中如何声明 ArrayList 变量
【8月更文挑战第23天】
47 0
|
2月前
|
存储 监控 Java
Java多线程优化:提高线程池性能的技巧与实践
Java多线程优化:提高线程池性能的技巧与实践
65 1
|
9天前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
下一篇
无影云桌面