java threadlocal 并发_Java并发编程之ThreadLocal

我们知道,在多线程访问一个共享变量的时候特别容易出现并发问题。我们为了保证线程安全,我们就可以将变量声明为ThreadLocal变量。

什么是ThreadLocal变量

如果你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多线程操作这个变量时,实际上操作的是自己本地内存中的变量,从而避免了线程安全问题。就比如说,我们去森林里摘果子,一开始大家共用一个果筐,就会出现一些问题。后来我们每个人都拥有自己的果筐,摘果子拿果子都在自己的果筐中操作,就不会出现问题了。

如何使用ThreadLocal变量

Talk is cheap,show me the code.进入代码环节

public class ThreadLocalTest {

static ThreadLocal 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的用途、操作、原理以及需要注意的问题等等。希望对你有所帮助。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值