博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java ThreadLocal的用法解析
阅读量:6770 次
发布时间:2019-06-26

本文共 2885 字,大约阅读时间需要 9 分钟。

hot3.png

简介

java中经常使用ThreadLocal作为处理高并发访问的可选手段,ThreadLocal并不是一个线程,而是”以线程为作用域“的一种面向对象的数据结构。其用法的也有着让人难以理解的怪异性。

代码实战

定义一个线程类,其中定义了一个ThreadLocal<Integer> 的对象

 class AutoIntegerThread extends Thread{	//静态局部变量(注意java中的静态变量的生命周期,共享性,唯一性)       private static ThreadLocal
 autoInteger = new ThreadLocal
(); //自增次数 private int runTimes; public AutoIntegerThread(int runTimes)  { this.runTimes = runTimes; } @Override public void run()  { //为了说明ThreadLocal以线程为作用域,这里不适用同步代码块 if(autoInteger.get()==null) { autoInteger.set(new Integer(0)); } for (int i = 0; i < runTimes; i++)  {        autoInteger.set(autoInteger.get()+1); //这里使用以下,保证完整打印一下 synchronized (autoInteger) { System.out.println(getName()+"==>"+autoInteger.get().intValue()); } } }  public  Integer getFinalInteger()  { return autoInteger.get(); }}

测试代码

public class TestThreadLocal {	  public static void main(String[] args)   {		         AutoIntegerThread ait_1 = new AutoIntegerThread(5);		         AutoIntegerThread ait_2 = new AutoIntegerThread(3);		         AutoIntegerThread ait_3 = new AutoIntegerThread(3);         ait_1.setName("ait_1");		         ait_2.setName("ait_3");         ait_3.setName("ait_2");		         ait_1.start();		         ait_2.start();		         ait_3.start();   }}

打印结果

ait_1==>1ait_2==>1ait_2==>2ait_2==>3ait_1==>2ait_3==>1ait_1==>3ait_3==>2ait_1==>4ait_3==>3ait_1==>5

 

有上面的代码和代码注释可知,符合java中的静态变量的描述,【静态变量的生命周期和应用程序的生命周期完全相同。静态变量具有共享性,唯一性,也就是说是单例】

是的,静态变量可以说是一个完整的单例,但由打印结果可知,似乎情况却违反了这种逻辑。

首先仔细想想,单例的好处是降低了内存的使用,从而提高程序的执行效率(这里不可过分理解,其实,当静态变量太多时反而也会影响内存的回收,因为他的生命周期决定了他和程序时“同寿的”,静态变量尽量少用的好,万事讲究一个“度”),另外单例的唯一性说明了他非常适合做“同步锁”。

其次,从结果来看,貌似谁也没影响谁。有人质疑是不是 private 的问题,建议java基础不熟练的话就不要问这样的问题了,因为private只决定访问权限,而不决定变量的创建。因此也就说明了,以线程为作用域。

 

if(autoInteger.get()==null){   autoInteger.set(new Integer(0));}

 

从这段代码来看,如果是List集合来说,只会运行一次,但程序似乎并没有这么做,而是分别在每个线程个执行了一次。

看看源代码

java.lang.ThreadLocal<T>

 

 public void set(T value) {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);    }    public T get() {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {                @SuppressWarnings("unchecked")                T result = (T)e.value;                return result;            }        }        return setInitialValue();    }

 

很显然,这个域作为map的key而存在,也就是说以“线程域”来创建和读取数据

而这个map的是属于Thread,看下面的源码

 ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }

 

 

然而,进一步证明了threadlocal使用线程域

java.lang.Thread

ThreadLocal.ThreadLocalMap threadLocals = null;

 

 static class ThreadLocalMap {....}

反正是个map,版面估计不足,不粘了,大家可以去看看。

总结:ThreadLocal通过“线程域”可以实现作用域的区分,并使得程序更加高效

 

 

 

 

 

 

 

转载于:https://my.oschina.net/ososchina/blog/337277

你可能感兴趣的文章
lamp-安装脚本-修订版1
查看>>
linux 之lvm 逻辑卷管理详解
查看>>
Linux挂载远程目录到本地及卸载
查看>>
什么是序列化?为什么要序列化?
查看>>
ubuntu下安装firefox和chromium需要的flash
查看>>
Fragment和Activity
查看>>
sed 实例
查看>>
UITableViewCell 复用
查看>>
iOS设置frame的简单方法
查看>>
复合型序列的分解预测
查看>>
CentOS 6.3 安装配置drbd8.3.13+heartbeat3.0.4
查看>>
linux 下动态链接库的制作与使用
查看>>
关于hadoop配置hosts文件的问题
查看>>
计算机操作系统发展历史
查看>>
人工智能和云计算是谁更聪明些?
查看>>
scp
查看>>
Harbor 安装配置问题
查看>>
python3 基础(5)-模块(1)-模块的导入、标准模块(标准库)
查看>>
ORACLE sql调优之记录一次trim函数引发的大表全表扫描
查看>>
puppet项目之crond与时间同步配置篇
查看>>