现在的位置:主页 > 综合新闻 >

快速掌握并发编程---深入学习ThreadLocal

来源:电脑编程技巧与维护 【在线投稿】 栏目:综合新闻 时间:2020-11-03

【作者】网站采编

【关键词】

【摘要】生活中的ThreadLocal 考试题只有一套,老师把考试题打印出多份,发给每位考生,然后考生各自写各自的试卷。考生之间不能相互交头接耳(会当做作弊)。各自写出来地答案不会影响他

生活中的ThreadLocal

考试题只有一套,老师把考试题打印出多份,发给每位考生,然后考生各自写各自的试卷。考生之间不能相互交头接耳(会当做作弊)。各自写出来地答案不会影响他人的分数。

注意:考试题、考生、试卷。

用代码来实现:

public?class?ThreadLocalDemo?{????//线程共享变量?localVar????public?static?ThreadLocal<String>?localVar?=?new?ThreadLocal<>();????static?void?print(String?str)?{????????//打印当前线程中本地内存中本地变量的值????????System.out.println(str?+?\"?:\"?+?localVar.get());????????//清除本地内存中的本地变量????????localVar.remove();????}????public?static?void?main(String[]?args)?{????????Thread?t1?=?new?Thread(new?Runnable()?{????????????@Override????????????public?void?run()?{????????????????//设置线程1中本地变量的值????????????????localVar.set(\"全部写完\");????????????????String?threadName?=?Thread.currentThread().getName();????????????????//调用打印方法????????????????print(threadName);????????????}????????},?\"张三\");????????Thread?t2?=?new?Thread(new?Runnable()?{????????????@Override????????????public?void?run()?{????????????????//设置线程2中本地变量的值????????????????localVar.set(\"写了一半\");????????????????String?threadName?=?Thread.currentThread().getName();????????????????//调用打印方法????????????????print(threadName);????????????}????????},?\"李四\");????????Thread?t3?=?new?Thread(new?Runnable()?{????????????@Override????????????public?void?run()?{????????????????//设置线程2中本地变量的值????????????????localVar.set(\"完全没写\");????????????????String?threadName?=?Thread.currentThread().getName();????????????????//调用打印方法????????????????print(threadName);????????????}????????},?\"王二\");????????t1.start();????????t2.start();????????t3.start();????}}

输出

李四?:写了一半王二?:完全没写张三?:全部写完
背景

ThreadLocal:字面意思为线程本地或者本地线程。但是其实真正含义并非如此,真正的含义是线程本地变量(副本)。

是JDK1.2版本的时候引入的,本文是基于JDK1.8版本进行讲解的。

上面考试场景中的几个关键点我们这么可以这么理解:

考试题----共享变量,大家共享

试卷-----考试题的副本

考试----线程

ThreadLocal可以理解为每个线程想绑定自己的东西,相互不受干扰。比如上面的考试场景,考试题大家都是一样的。但是考试题进行复印出来后,每人一份,各自写写各自的,相互不受影响,这就正是ThreadLocal想要实现的功能。

当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

可以想想生活中还有没有类似的例子。肯定非常多,只要我们用心去体会。

下面我们就来看看ThreadLocal到底是如何实现的。

ThreadLocal设计原理

ThreadLocal名字中第一个单词Thread表示线程,Local表示本地,我们就理解为线程本地变量了。想了解更多Thread,可看:快速掌握并发编程---Thread常用方法

先看看ThreadLocal的整体

最关心的三个公有方法:set、get、remove

构造方法?public?ThreadLocal()?{?}

构造方法里没有任何逻辑处理,就是简单的创建一个实例。

set方法

源码为

public?void?set(T?value)?{????//获取当前线程????????Thread?t?=?Thread.currentThread();????//这是什么鬼?????????ThreadLocalMap?map?=?getMap(t);????????????if?(map?!=?null)????????????????????map.set(this,?value);???????????else????????createMap(t,?value);}

先看看ThreadLocalMap是个什么东东

ThreadLocalMap是ThreadLocal的静态内部类。

set方法整体为

ThreadLocalMap构造方法

//这个属性是ThreadLocal的,就是获取hashcode(这列很有学问,但是我们的目的不是他)private?final?int?threadLocalHashCode?=?nextHashCode();private?Entry[]?table;private?static?final?int?INITIAL_CAPACITY?=?16;//Entry是一个弱引用????????static?class?Entry?extends?WeakReference<ThreadLocal<?>>?{????Object?value;????Entry(ThreadLocal<?>?k,?Object?v)?{????????super(k);????????value?=?v;???????}?}ThreadLocalMap(ThreadLocal<?>?firstKey,?Object?firstValue)?{????//数组默认大小为16????table?=?new?Entry[INITIAL_CAPACITY];????//len?为2的n次方,以ThreadLocal的计算的哈希值按照Entry[]取模(为了更好的散列)????int?i?=?firstKey.threadLocalHashCode?&?(INITIAL_CAPACITY?-?1);????table[i]?=?new?Entry(firstKey,?firstValue);????size?=?1;????//设置阈值(扩容阈值)????setThreshold(INITIAL_CAPACITY);??}

文章来源:《电脑编程技巧与维护》 网址: http://www.dnbcjqywh.cn/zonghexinwen/2020/1103/610.html

上一篇:编程不用程序员!低代码是炒作还是趋势?
下一篇:把C++当作第一门编程语言好吗