【Java并发编程】线程本地存储模式ThreadLocal

我们知道多个线程同时读写同一共享变量会导致并发问题。

一种解决方案是使用 Immutability 模式,如果共享变量在初始化之后就不会改变,只能读取,那么无论多少个线程同时读这个共享变量都不会出现并发问题。比如说 Java 中的 Long、Integer、Short、Byte 等基本数据类型的包装类的实现。

另一种解决方案是突破共享变量,没有共享变量就不会有并发问题。那么如何避免共享呢?思路其实很简单,就是每个线程拥有自己的变量,彼此不共享,就不会有共享问题。

具体来说有两种方法:线程封闭和线程本地存储(ThreadLocal)。

线程封闭

方法里的局部变量,因为不会和其他线程共享,所以没有并发问题,叫做线程封闭,比较官方的解释是:仅在单线程内访问数据。由于不存在共享,所以即便不同步也不会有并发问题,性能杠杠的。

保护局部变量的调用栈结构

如上图所示,JVM 中每一个线程都会有一个 Java 虚拟机栈。Java 程序每调用一个方法都会入栈,每执行完一个方法都会出栈,且每一个方法都有一个栈帧。栈帧中存储了参数、局部变量和返回地址。由此可见,方法的局部变量是不可能和其它线程共享的。

局部变量可以避免线程共享,此外还有什么方法能避免线程共享么?有,那就是 Java 语言提供的线程本地存储(ThreadLocal)。

ThreadLock

SimpleDateFormat 不是线程安全的,如果想在并发场景下使用它可以将其设置为一个方法的局部变量,这样就会创建许多对象占用内存。或者使用 ThreadLock,不同线程调用 SafeDateFormat 会返回不同的 SimpleDateFormat 对象,但是由于在线程之间不共享,就和局部变量一样是安全的。

1
2
3
4
5
6
7
8
9
10
11
static class SafeDateFormat {
  // 定义 ThreadLocal 变量
  static final ThreadLocal<DateFormat>
    tl=ThreadLocal.withInitial(
    ()-> new SimpleDateFormat(
      "yyyy-MM-dd HH:mm:ss"));

  static DateFormat get(){
    return tl.get();
  }
}

接下来再看一下 ThreadLock 的代码实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Thread {
  // 内部持有 ThreadLocalMap
  ThreadLocal.ThreadLocalMap 
    threadLocals;
}
class ThreadLocal<T>{
  public T get() {
    // 首先获取线程持有的
    //ThreadLocalMap
    ThreadLocalMap map =
      Thread.currentThread()
        .threadLocals;
    // 在 ThreadLocalMap 中
    // 查找变量
    Entry e = 
      map.getEntry(this);
    return e.value;  
  }
  static class ThreadLocalMap{
    // 内部是数组而不是 Map
    Entry[] table;
    // 根据 ThreadLocal 查找 Entry
    Entry getEntry(ThreadLocal key){
      // 省略查找逻辑
    }
    //Entry 定义
    static class Entry extends
    WeakReference<ThreadLocal>{
      Object value;
    }
  }
}

在 Java 的实现方案中,ThreadLocal 仅仅是一个工具类,内部并不持有和线程有关的数据,所有和线程有关的数据都存储在 Thread 中,比如 Thread 内部持有当前线程的 ThreadLocalMap。

这样设计有一个好处就是能够避免内存泄露

SimpleDateFormat 的线程安全问题与 ThreadLocal

手撕面试题ThreadLocal!!!

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值