为什么需要ThreadLocal

多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线程安全性。

而线程安全是指

当多个线程访问某个方法时,不管你通过怎样的调用方式或者说这些线程如何交替的执行,我们在主程序中不需要去做任何的同步,

这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类时线程安全的。

或者:

不同的线程可以访问相同的资源,而不会暴露出错误的行为或产生不可预知的结果。

 下面是线程不安全,相互影响:

public class UsuallyThreadTest {
static String localName = null; public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
localName ="quan";
System.out.println(localName+" "+Thread.currentThread().getName());
localName = null;
}
}); Thread thread2 = new Thread(new Runnable() {
public void run() {
System.out.println(localName+" after set localName= null "+Thread.currentThread().getName());
}
}); System.getenv();
// System.getProperty() thread1.start();
thread2.start();
}
/**
* quan Thread-0
* quan after set localName= null Thread-1
*
* 线程1的修改对线程2产生影响,不安全。
*/
}

ThreadLocal是什么

它提供线程本地变量,如果创建一乐ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个副本,

在实际多线程操作的时候,操作的是自己本地内存中的变量,从而规避了线程安全问题。

ThreadLocal例子

public class LearningforThreadlocal {

    static  ThreadLocal<String> localName = new ThreadLocal<String>();

    public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
localName.set("quan");
System.out.println(localName.get());
}
}); Thread thread2 = new Thread(new Runnable() {
public void run() {
System.out.println(localName.get()+"--->"+"after thread1 ,noremove");
localName.set("zhi");
System.out.println(localName.get());
localName.remove();
System.out.println("remove......::"+localName.get()+" in "+Thread.currentThread().getName()); }
}); // Thread thread3 = new Thread(new Runnable() {
// public void run() {
// System.out.println("no use set "+localName.get()+" in "+Thread.currentThread().getName());
// }
// }); Thread thread3 = new Thread(()->{
System.out.println("no use set "+localName.get()+" in "+Thread.currentThread().getName());
}); thread1.start();
thread2.start();
thread3.start();
} } /**
* re:
* quan
* no use set null in Thread-2
* null--->after thread1 ,noremove
* zhi
* remove......::null in Thread-1
*/

从上面可以看出,其实两个线程是不会相互影响的!!!!

ThreadLocal解析

set方法解析

/**
* set方法解析:
* public void set(T value) {
* Thread t = Thread.currentThread();//获取当前线程
* ThreadLocalMap map = getMap(t);//getMap方法如下面所示
* if (map != null)//如果不为空直接将当前线程中的threadLocals设置为键为当前ThreadLocal的引用,值为value
* map.set(this, value);
* else
* createMap(t, value);//否则创建threadLocals并设置键值对,createMap如下:
* }
*
* ThreadLocalMap getMap(Thread t) {
* return t.threadLocals;//返回当前线程中的变量threadLocals,第一次使用set方法是为null
* }
*
* void createMap(Thread t, T firstValue) {
* t.threadLocals = new ThreadLocalMap(this, firstValue);这里的createMap不仅建立了threadLocals,而且还设置了值
* }
*/

Get方法解析

/**
* get() 解析:
* public T get() {
* Thread t = Thread.currentThread();获取当前线程
* ThreadLocalMap map = getMap(t); 获取当前线ThreadLocals集合
* if (map != null) {
* ThreadLocalMap.Entry e = map.getEntry(this);
* //不为空直接获取集合中的值,this指的是哪个 ThreadLocal(例子localName)调用的引用
* if (e != null) {
* @SuppressWarnings("unchecked")
* T result = (T)e.value;获取ThreadLocal(例子localName)对应的值
* return result;
* }
* }
* return setInitialValue();
* }
*
* private T setInitialValue() {
* T value = initialValue();//内部方法,返回null
* Thread t = Thread.currentThread();
* ThreadLocalMap map = getMap(t);
* if (map != null)
* map.set(this, value);
* else
* createMap(t, value);
* return value;返回null
* }
*
*/

ThreadLocal和Thread的关系

/**
* 进入Thread内部可以知道有两个属性:
* ThreadLocal.ThreadLocalMap threadLocals = null;
* ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
* 由前缀知道都是ThreadLocal内部类ThreadLocalMap类型的变量
*
* ThreadLocal类型的本地变量是存放在具体的线程空间上,set方法将value添加到调用线程的threadLocals中,
* 当调用线程调用get方法时候能够从它的threadLocals中取出变量。
* 线程不断,变量就一直在threadlocals中,所以不用的时候使用remove
*

ThreadLocal无继承性

例子说明:

/**
* ThreadLocal不具有继承性
*/
public class ThreadLocalInherit {
static ThreadLocal<String> localName = new ThreadLocal<String>(); public static void main(String[] args) {
localName.set("DONE");//在main线程里面设置了localName的值
System.out.println(Thread.currentThread().getName()+"使用了:localName.set(\"DONE\")"); Thread thread = new Thread(new Runnable() {
public void run() {
System.out.println("子类"+localName.get());
}//子类去获取的时候
}); thread.start();
}
/**
* re:
* main使用了:localName.set("DONE")
* 子类null
*/ }

注意:InheritableThreadLocal类继承了ThreadLocal,扩展了ThreadLocal。实现了可以继承的关系

ThreadLocalMap与内存泄漏

/**
* 解析一下ThreadLocals的类型ThreadLocalMap
* 实际上是一个:private Entry[] table;
* Entry[] 是:
*
* static class Entry extends WeakReference<ThreadLocal<?>> {
* Object value;
* Entry(ThreadLocal<?> k, Object v) {构造函数,ThreadLocal的引用k被传进WeakReference的构造函数。
* super(k);
* value = v;
* }
* }
*---》所以ThreadLocalMap的key就是对ThreadLocal的弱引用
*
* 如果没有执行remove,有可能造成内存泄漏
*
* key弱引用在gc的时候没有其他强依赖,就会被gc掉。但是value不会。
* 可能会出现key为null,但是value还存在的情况。
* 所以我们使用后一定要用remove掉
*/

ThreadLocal只是一个工具类,他为用户提供get、set、remove接口操作实际存放本地变量的threadLocals(调用线程的成员变量),

threadLocals是一个ThreadLocalMap类型的变量,

java中的ThreadLocal-learning的更多相关文章

  1. Java中的ThreadLocal深入理解

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  2. 理解Java中的ThreadLocal

    提到ThreadLocal,有些Android或者Java程序员可能有所陌生,可能会提出种种问题,它是做什么的,是不是和线程有关,怎么使用呢?等等问题,本文将总结一下我对ThreadLocal的理解和 ...

  3. Java中的ThreadLocal详解

    一.ThreadLocal简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线 ...

  4. 谈谈Java中的ThreadLocal

    什么是ThreadLocal ThreadLocal一般称为线程本地变量,它是一种特殊的线程绑定机制,将变量与线程绑定在一起,为每一个线程维护一个独立的变量副本.通过ThreadLocal可以将对象的 ...

  5. 理解java中的ThreadLocal(转)

    一.对ThreadLocal概述 JDK API 写道: 该类提供了线程局部 (thread-local) 变量.这些变量不同于它们的普通对应物,因为访问某个变量(通过其 get 或 set 方法)的 ...

  6. 理解java中的ThreadLocal 专题

    ThreadLocal每一印象: public class IncrementWithStaticVariable{ private static int seqNum = 0; public int ...

  7. Java中的ThreadLocal

    关于 ThreadLocal,我们经常用它来解决多线程并发问题,那它究竟是如何做到的?今天就让我们来好好看一下. 从源码入手 首先,让我们看看 ThreadLocal 类中的介绍: This clas ...

  8. java 中的 ThreadLocal

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

  9. Java中的ThreadLocal使用

    ThreadLocal用于下面的场景: 1. 不允许多个线程同时访问的资源 2. 单个线程存活过程只使用一个实例 官方定义如下: This class provides thread-local va ...

  10. Java ThreadLocal Example(java中的ThreadLocal例子)

    Java ThreadLocal is used to create thread local variables. We know that all threads of an Object sha ...

随机推荐

  1. 使用Java的GUI技术实现 “ 贪吃蛇 ” 游戏

    详细教程: 使用Java的GUI技术实现 " 贪吃蛇 " 游戏_IT打工酱的博客-CSDN博客

  2. 深度测评,商业智能BI、报表工具谁更好用?

    在很多人入门数据分析师或者投身大数据行业的时候,必然会听到的两个词就是"报表工具"和"BI商业智能"."BI"一词已被更广泛地知晓,但提起B ...

  3. C语言中puts()和printf()区别

    puts的功能更加单一,只能输出字符串:printf的功能更加广,可以格式化数据,输出多种类型的数据. puts()函数用来向标准输出设备(屏幕)写字符串并换行. 调用方式为puts(string): ...

  4. C# 模式匹配完全指南

    前言 自从 2017 年 C# 7.0 版本开始引入声明模式和常数模式匹配开始,到 2022 年的 C# 11 为止,最后一个板块列表模式和切片模式匹配也已经补齐,当初计划的模式匹配内容已经基本全部完 ...

  5. Java多线程编程核心技术---多线程技能

    1.继承Thread /** * Copyright (C), 2018-2018, * FileName: MyThread * Author: 大象 * Date: 2018-06-08 22:3 ...

  6. 函数式编程 高阶函数 map&reduce filter sorted

    函数式编程 纯函数:没有变量的函数 对于纯函数而言:只要输入确定,那么输出就是确定的.纯函数是没有副作用的. 函数式编程:允许把函数本身作为参数传入另一个函数,还允许返回一个函数 高阶函数:一个函数的 ...

  7. c++刷leetcode记录

    #include<iostream> #include<sstream> #include<vector> std::vector<int> split ...

  8. Vue中组件的递归

    先来说下需求,就是一个表单,会有树形结构一样,会有子表单,表单显示什么内容是后台通过接口数据来确定的:这个时候就和树形结构一样,肯定会有子组件的递归:这次是自己第一次写递归,遇到了三个问题记录下: 1 ...

  9. 居然可以像玩游戏一样学Git

    工作中经常用到 git,但是用到的指令也都是比较初级的.简单的.当时学习的过程也是有点痛苦.各种概念理解起来要么靠想象,要么自己创建工程提交记录,然后执行指令,看具体效果.这样学下来是事倍功半. 在搜 ...

  10. JZ-062-二叉查找树的第 K 个结点

    二叉查找树的第 K 个结点 题目描述 给定一棵二叉搜索树,请找出其中的第k小的结点. 题目链接: 二叉查找树的第 K 个结点 代码 /** * 标题:二叉查找树的第 K 个结点 * 题目描述 * 给定 ...