Java并发编程之ThreadLocal
作者:互联网
我们知道,在多线程访问一个共享变量的时候特别容易出现并发问题。我们为了保证线程安全,我们就可以将变量声明为ThreadLocal变量。
什么是ThreadLocal变量
如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多线程操作这个变量时,实际上操作的是自己本地内存中的变量,从而避免了线程安全问题。就比如说,我们去森林里摘果子,一开始大家共用一个果筐,就会出现一些问题。后来我们每个人都拥有自己的果筐,摘果子拿果子都在自己的果筐中操作,就不会出现问题了。
如何使用ThreadLocal变量
Talk is cheap,show me the code.进入代码环节
public class ThreadLocalTest { static ThreadLocal<String> localVariable = new ThreadLocal<>(); static void print(String str) { System.out.println(str + ":" + localVariable.get()); } public static void main(String[] args) { Thread threadOne = new Thread(new Runnable() { @Override public void run() { localVariable.set("threadOne local variable"); print("threadOne"); System.out.println("threadOne remove after" + ":" + localVariable.get()); } }); Thread threadTwo = new Thread(new Runnable() { @Override public void run() { //localVariable.set("threadTwo local variable"); print("threadTwo"); System.out.println("threadTwo remove after" + ":" + localVariable.get()); } }); threadOne.start(); threadTwo.start(); } }
程序的运行结果如下
threadOne:threadOne local variable
threadTwo:null
threadOne remove after:threadOne local variable
threadTwo remove after:null
我们可以看出,我们设置了一个ThreadLocal类型的变量localVariable,并在线程一中对其进行赋值,在线程二中并没有对其赋值。在我们的执行结果中,这种差异性就得到了体现。
如果我们想要移除本地内存的ThreadLocal变量,可以使用remove()方法。
ThreadLocal的实现原理
我们可以先看一看Thread的源码。
public class Thread implements Runnable {
.//ThreadLocal values pertaining to this thread. This map is maintained by the ThreadLocal class.
ThreadLocal.ThreadLocalMap threadLocals = null;
//InheritableThreadLocal values pertaining to this thread. This map is maintained by the InheritableThreadLocal class.
ThreadLocalMap inheritableThreadLocals = null;
......
}
从代码中我们可以知道,Thread类中有一个threadLocals和一个inheritableThreadLocals,他们都是ThreadLocalMap类型的变量。ThreadLocalMap就是一个定制化的Hashmap,在默认情况下,每个线程中的这两个变量都为null,只有在第一次调用ThreadLocal的set和get方法时才会创建它们。
其实每个线程的本地变量并不是存储在ThreadLocal实例里面,而是存储在调用线程的threadLocals中。也就是说ThreadLocal存放在具体的线程空间中,ThreadLocal通过set、get方法把value的值存取到线程的threadLocals中。
ThreadLocal 内存泄露问题
ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会 key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现key为null的Entry。假如我们不做任何措施的话,value 永远无法被GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后 最好手动调用remove()方法。
本篇文章我们介绍了ThreadLocal的用途、操作、原理以及需要注意的问题等等。希望对你有所帮助。
标签:Java,变量,Thread,编程,remove,ThreadLocal,线程,threadOne 来源: https://www.cnblogs.com/jiangtunan/p/11104716.html