为什么需要ThreadLocal

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

而线程安全是指

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

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

或者:

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

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

  1. public class UsuallyThreadTest {
  2. static String localName = null;
  3.  
  4. public static void main(String[] args) {
  5. Thread thread1 = new Thread(new Runnable() {
  6. public void run() {
  7. localName ="quan";
  8. System.out.println(localName+" "+Thread.currentThread().getName());
  9. localName = null;
  10. }
  11. });
  12.  
  13. Thread thread2 = new Thread(new Runnable() {
  14. public void run() {
  15. System.out.println(localName+" after set localName= null "+Thread.currentThread().getName());
  16. }
  17. });
  18.  
  19. System.getenv();
  20. // System.getProperty()
  21.  
  22. thread1.start();
  23. thread2.start();
  24. }
  25. /**
  26. * quan Thread-0
  27. * quan after set localName= null Thread-1
  28. *
  29. * 线程1的修改对线程2产生影响,不安全。
  30. */
  31. }

ThreadLocal是什么

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

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

ThreadLocal例子

  1. public class LearningforThreadlocal {
  2.  
  3. static ThreadLocal<String> localName = new ThreadLocal<String>();
  4.  
  5. public static void main(String[] args) {
  6. Thread thread1 = new Thread(new Runnable() {
  7. public void run() {
  8. localName.set("quan");
  9. System.out.println(localName.get());
  10. }
  11. });
  12.  
  13. Thread thread2 = new Thread(new Runnable() {
  14. public void run() {
  15. System.out.println(localName.get()+"--->"+"after thread1 ,noremove");
  16. localName.set("zhi");
  17. System.out.println(localName.get());
  18. localName.remove();
  19. System.out.println("remove......::"+localName.get()+" in "+Thread.currentThread().getName());
  20.  
  21. }
  22. });
  23.  
  24. // Thread thread3 = new Thread(new Runnable() {
  25. // public void run() {
  26. // System.out.println("no use set "+localName.get()+" in "+Thread.currentThread().getName());
  27. // }
  28. // });
  29.  
  30. Thread thread3 = new Thread(()->{
  31. System.out.println("no use set "+localName.get()+" in "+Thread.currentThread().getName());
  32. });
  33.  
  34. thread1.start();
  35. thread2.start();
  36. thread3.start();
  37. }
  38.  
  39. }
  40.  
  41. /**
  42. * re:
  43. * quan
  44. * no use set null in Thread-2
  45. * null--->after thread1 ,noremove
  46. * zhi
  47. * remove......::null in Thread-1
  48. */

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

ThreadLocal解析

set方法解析

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

Get方法解析

  1. /**
  2. * get() 解析:
  3. * public T get() {
  4. * Thread t = Thread.currentThread();获取当前线程
  5. * ThreadLocalMap map = getMap(t); 获取当前线ThreadLocals集合
  6. * if (map != null) {
  7. * ThreadLocalMap.Entry e = map.getEntry(this);
  8. * //不为空直接获取集合中的值,this指的是哪个 ThreadLocal(例子localName)调用的引用
  9. * if (e != null) {
  10. * @SuppressWarnings("unchecked")
  11. * T result = (T)e.value;获取ThreadLocal(例子localName)对应的值
  12. * return result;
  13. * }
  14. * }
  15. * return setInitialValue();
  16. * }
  17. *
  18. * private T setInitialValue() {
  19. * T value = initialValue();//内部方法,返回null
  20. * Thread t = Thread.currentThread();
  21. * ThreadLocalMap map = getMap(t);
  22. * if (map != null)
  23. * map.set(this, value);
  24. * else
  25. * createMap(t, value);
  26. * return value;返回null
  27. * }
  28. *
  29. */

ThreadLocal和Thread的关系

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

ThreadLocal无继承性

例子说明:

  1. /**
  2. * ThreadLocal不具有继承性
  3. */
  4. public class ThreadLocalInherit {
  5. static ThreadLocal<String> localName = new ThreadLocal<String>();
  6.  
  7. public static void main(String[] args) {
  8. localName.set("DONE");//在main线程里面设置了localName的值
  9. System.out.println(Thread.currentThread().getName()+"使用了:localName.set(\"DONE\")");
  10.  
  11. Thread thread = new Thread(new Runnable() {
  12. public void run() {
  13. System.out.println("子类"+localName.get());
  14. }//子类去获取的时候
  15. });
  16.  
  17. thread.start();
  18. }
  19. /**
  20. * re:
  21. * main使用了:localName.set("DONE")
  22. * 子类null
  23. */
  24.  
  25. }

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

ThreadLocalMap与内存泄漏

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

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. PentestBox在win10里打不开工具 显示无系统命令的解决方法

    PentestBox详细安装过程:http://www.cnblogs.com/ESHLkangi/p/8336398.html 在使用PentestBox的时候出现了打不开工具的问题,最后看到一个大 ...

  2. linux安装ngixn

    卸载ngxin(第一次安装请略过) 1.检查nginx是否启动,是否安装ngxin 检查是否安装nginx命令 rpm -qa|grep nginx 检查nginx是否启动命令: pa -ef|gre ...

  3. 【C++ 调试】增量链接 Incremental Linking

    概述: Incremental Linking翻译成中文就是"增量链接",是一个链接的参数选项,作用就是为了提高链接速度的.什么意思呢?不选用增量链接时,每次修改或新增代码后进行链 ...

  4. Java课程设计---数据库工具类

    接下来看看传统的查询方式(一个完整的查询) package com.java.mysql; import java.sql.Connection; import java.sql.DriverMana ...

  5. 聊聊第一个开源项目(内网穿透) - CProxy

    文章首发:聊聊第一个开源项目 - CProxy 作者:会玩code 初衷 最近在学C++,想写个项目练练手.对网络比较感兴趣,之前使用过ngrok(GO版本的内网穿透项目),看了部分源码,想把自己的一 ...

  6. AndroidMainifest.xml文件属性

    1 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 2 package=" ...

  7. parquet和orc选型以及压缩格式

    Hive表压缩功能 除了直接配置MapReduce压缩功能外,Hive的ORC表和Parquet表直接支持表的压缩属性. 但支持的压缩格式有限,ORC表支持None.Zlib.Snappy压缩,默认为 ...

  8. 六、Java方法

    Java方法 何为方法 System.out.println(),那么它是什么呢? ​ System是一个类,out是一个对象,println()是一个方法 Java方法是语句的集合,它们在一起执行的 ...

  9. 进制转换伪代码转python

    运行结果如图 代码如下 a=input("请输入一个十进制数:", ) print("二进制结果为:",bin(int(a))) print("八进制 ...

  10. k8s集群StatefulSets的Pod优雅调度问题思考?

    k8s集群StatefulSets的Pod优雅调度问题思考 考点之你能解释一下为什么k8s的 StatefulSets 需要VolumeClaimTemplate嘛? 考点之简单描述一下Statefu ...