为什么需要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. ansible中的hostvars

    首先来看一个例子:假设我想得到主机IP为172.25.250.9的完全限定域名(FQDN),但是我无法登录该主机,那么就可以用本机里面的hostvars魔法变量(后面会分享我对魔法这个词的理解)这个字 ...

  2. Linux添加永久路由的方法

    通常我们使用route add -net添加临时路由.当系统重启,临时路由将丢失,重新配置路由带来了不必要的麻烦.可通过固化临时路由为永久路由的方法解决该问题. static-routes文件为路由固 ...

  3. 安装java环境与eclipse

    一.今天安装了java环境和eclipse 二.大道至简学了前三章(前两章)问题不大还好理解 第三章有些东西很懵 1.进入网址www.oracle.com,点击resource(资源) 点击softw ...

  4. Qt:QNetworkRequest

    0.说明 QNetworkRequest类代表被QNetworkAccessManager发送的请求. QNetworkReuqest是网络访问API的一部分,在其内部保留了在网络上发送一个reque ...

  5. 【spring源码系列】之【Bean的销毁】

    以"冬奥之光,多彩冰灯"为主题的第四十一届全国专业冰雕比赛在冰城哈尔滨市进入第二天,60名冰雕高手在哈尔滨冰灯艺术游园会园区展开激烈的竞技比拼. 冰雕艺术 1. 概述 Bean的销 ...

  6. SoapUI软件-测试Web Service接口

    一.新建项目 New SOAP Project Project Name填入项目名称:Initial WSDL中填入接口地址,或后缀为.wsdl的文件:OK: 添加后可在左侧看到接口详情: 二.测试接 ...

  7. 矩池云上TensorBoard/TensorBoardX配置说明

    Tensorflow用户使用TensorBoard 矩池云现在为带有Tensorflow的镜像默认开启了6006端口,那么只需要在租用后使用命令启动即可 tensorboard --logdir lo ...

  8. jmeter(二十八)利用beanshell进行多重断言

    在接口测试中,我们对返回结果的正确性判断一般是基于响应报文的返回内容进行断言.但有些时候,按照正常的业务逻辑来说,一个请求返回的内容是多种不同的. 比如:用户注册功能,注册成功是正常的返回messag ...

  9. dedeCMS自定义dede标签

    在include/taglib文件夹中新建文件hlh.lib.php,其中hlh也就是你标签的名字,function的名字也必须跟文件名对应,固定格式lib_标签名,如lib_hlh,本例子以调取文章 ...

  10. Dapr云原生应用开发系列7:工作流集成

    题记:这篇介绍一个很有意思的东西,Dapr和Logic Apps这样的工作流引擎集成. Dapr工作流 在1年多前,Dapr的孵化团队搞了一个很有意思的东西:把Dapr和Logic Apps集成起来, ...