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

简介:

一、测试代码

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

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
7月前
|
存储 缓存 安全
除了变量,final还能修饰哪些Java元素
在Java中,final关键字不仅可以修饰变量,还可以用于修饰类、方法和参数。修饰类时,该类不能被继承;修饰方法时,方法不能被重写;修饰参数时,参数在方法体内不能被修改。
85 3
|
3月前
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
54 12
|
2月前
|
存储 Java
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
前言 下面,跟上主播的节奏,马上开始ThreadLocal源码的阅读( ̄▽ ̄)" 内部结构 如下图所示,我们可以知道,每个线程,都有自己的threadLocals字段,指向ThreadLocalMap
417 81
【源码】【Java并发】【ThreadLocal】适合中学者体质的ThreadLocal源码阅读
|
1月前
|
存储 安全 Java
深入探究Java中ThreadLocal的工作原理和用途
总结起来,ThreadLocal是Java多线程编程中一个非常有用的工具,通过为每个线程分配独立的变量副本,实现线程隔离,避免资
53 9
|
2月前
|
存储 缓存 安全
【Java并发】【ThreadLocal】适合初学体质的ThreadLocal
ThreadLocal 是 Java 中用于实现线程本地存储(Thread-Local Storage)的核心类,它允许每个线程拥有自己独立的变量副本,从而在多线程环境中实现线程隔离,避免共享变量带来的线程安全问题。
87 9
【Java并发】【ThreadLocal】适合初学体质的ThreadLocal
|
3月前
|
存储 设计模式 Java
重学Java基础篇—ThreadLocal深度解析与最佳实践
ThreadLocal 是一种实现线程隔离的机制,为每个线程创建独立变量副本,适用于数据库连接管理、用户会话信息存储等场景。
119 5
|
3月前
|
存储 传感器 缓存
java变量与数据类型:整型、浮点型与字符类型
### Java数据类型全景表简介 本文详细介绍了Java的基本数据类型和引用数据类型,涵盖每种类型的存储空间、默认值、取值范围及使用场景。特别强调了`byte`、`int`、`long`、`float`、`double`等基本类型在不同应用场景中的选择与优化,如文件流处理、金融计算等。引用数据类型部分则解析了`String`、数组、类对象、接口和枚举的内存分配机制。
107 15
|
5月前
|
Java Linux iOS开发
如何配置 Java 环境变量:设置 JAVA_HOME 和 PATH
本文详细介绍如何在Windows和Linux/macOS系统上配置Java环境变量。
6167 12
|
7月前
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
7月前
|
存储 监控 安全
深入理解ThreadLocal:线程局部变量的机制与应用
在Java的多线程编程中,`ThreadLocal`变量提供了一种线程安全的解决方案,允许每个线程拥有自己的变量副本,从而避免了线程间的数据竞争。本文将深入探讨`ThreadLocal`的工作原理、使用方法以及在实际开发中的应用场景。
164 2