Java线程上下文-ThreadLocal的那些事

本文介绍了Java中的ThreadLocal,用于线程间数据隔离,避免了对象间/方法间跨层传递的复杂性。ThreadLocal通过initialValue()、set(T value)和get()方法管理线程副本。然而,如果不正确使用可能导致内存泄漏,因为ThreadLocalMap中的Entry虽然键是弱引用,但值是强引用。为了避免内存泄漏,应当在不再使用ThreadLocal时手动清理其数据。
摘要由CSDN通过智能技术生成

一、概述

ThreadLocal: 通常被称作线程本地变量或者线程本地存储。其含义是ThreadLocal为变量在每个线程中都创建一个副本,则每个线程可以访问自身内部的副本变量。
概念总是抽象而且晦涩的,我们从两个例子说起。

1、对象间/方法间跨层传递

如下图,有个多层调用的情况,如果我们需要传递某个中间结果在这几层调用关系之间,应该怎么处理呢?
多层调用

  • 一种简单的思路是,把每个函数新增一个参数,然后依次传递下去。但是,如果参数过多,或者某一个函数为公共函数,不允许我们随意添加参数的话,那该怎么处理呢?
  • 另一种思路,设置一个单例类,实时保存该数据。实存实取。也能保证其在各个函数之间的传递。但是,如果是多线程操作怎么保证单例数据不被污染?
    假设,我们在A.fun1()之中将数据保存在单例类中,然后在之后的其他函数中操作该数据。如果是多线程的环境,如果同时有多个线程同时操作入口函数A.fun1(),则单例保存的数据则会被污染。
  • 还有一种思路,就是使用ThreadLocal为该数据在每个线程中都创建一个副本,则线程之间则不会互相影响。如下代码,通过ThreadLocal,我们可以使数据在对象间/方法间进行传递。
public class ThreadLocalDemo {
    private ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    private void fun1() {
        threadLocal.set(System.nanoTime());
        System.out.println("fun1:" + threadLocal.get());
        fun2();
    }

    private void fun2() {
        System.out.println("fun2:" + threadLocal.get());
        fun3();
    }

    private void fun3() {
        System.out.println("fun3:" + threadLocal.get());
        threadLocal.remove();
    }

    public static void main(String[] args) {
        ThreadLocalDemo demo = new ThreadLocalDemo();
        demo.fun1();
    }
}

2、线程间的数据隔离

如果需要将一个单线程的应用移植到到多线程的环境下,就需要将共享的一些全局变量转换为ThreadLocal对象;这相当于ThreadLocal为每个线程都创建了一个该全局变量的副本。保证了其线程安全性。

但是,TheadLocal并不是解决高并发下共享资源的方式。大多数情况下,ThreadLocal存储的是一个new的新对象。但是如果其存储一个对象的引用,也会面临资源竞争的情况。

  • 例子1:ThreadLocal与Synchronized区别
    好多人都说ThreadLocal和Synchroized一样,实现了线程同步。那我们看个例子。
    假设有一个static int a = 0;,共有5个线程对其进行++操作,保险起见,我们对++进行加锁(Sync)。这样在执行完之后,a == 5,毫无疑问。
    同样的,我们起初使用ThreadLocal保存a =
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值