编程语言
首页 > 编程语言> > Java并发编程之ThreadLocal

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