Java并发编程 II - 没有共享就没有伤害(ThreadLoacl)

Java并发编程 I - 并发问题的源头
Java并发编程 II - 没有共享就没有伤害(ThreadLoacl)
Java并发编程 III - 让共享数据只读(final关键字)
Java并发编程 IV - volatile关键字与Atomic类
Java并发编程 V - 并发的万能钥匙synchronized
Java并发编程 VI - 线程生命周期与线程间的协作
Java并发编程 VII - Lock

局部变量是线程安全的

并发问题都是由于共享数据的竞争造成的。

那为什么局部变量不会造成并发问题呢?

CPU找调用方法的参数和返回地址,是通过堆栈寄存器。CPU支持一种线性结构,因为与方法调用有关,所以也称为调用栈。每个方法在调用栈里都有自己的独立空间,称为栈帧。每个栈帧都有对应方法需要的参数和返回地址。当调用新方法时,会创建新的栈帧,并压入调用栈;当方法返回时,对应的栈帧就会被自动弹出。即,栈帧和方法同生共死。局部变量就是存放到调用栈中的

每个线程都有自己独立的调用栈。所以,Java方法里面的局部变量是不存在并发问题的。


ThreadLocal

ThreadLocal能够让数据线程唯一,防止数据共享。


ThreadLocal怎么用
		static ThreadLocal<Integer> tl = new ThreadLocal();

    public static void main(String[] args) throws InterruptedException {
        tl.set(100);

        new Thread(() -> {
            System.out.println("thread === " + tl.get());
        }).start();

        System.out.println("main ===  " + tl.get());
    }

/*
输出 -> 
main ===  100
thread === null
*/

ThreadLocal设计思想

1、Thread 内部持有 ThreadLocalMap<ThreadLocal(弱引用), T (强引用)>对象threadLocals


2、ThreadLocal内部

get() -> 获取当前thread对象 -> 获取threadLocals(并且判空,为空就为该thread创建threadLocals)-> map.get(this) 获取到value

set(T value) -> 获取当前thread对象 -> 获取threadLocals(并且判空,为空就为该thread创建threadLocals)-> map.set(this, value)

remove() -> 获取当前thread对象 -> 获取threadLocals -> map.remove(this)


3、为什么Java这样设计(防止内存泄漏)

ThreadLocal生命周期要比Thread要长,如果ThreadLocal一直引用这Thread的话,导致这个Thread一直不能被释放。而且 ThreadLocalMap 里对 ThreadLocal 的引用还是弱引用,所以只要 Thread 对象可以被回收,那么 ThreadLocalMap 就能被回收。


ThreadLocal 在线程池中的使用,存在内存泄漏的风险

原因就出在线程池中线程的存活时间太长,往往都是和程序同生共死的,这就意味着 Thread 持有的 ThreadLocalMap 一直都不会被回收,再加上 ThreadLocalMap 中的 Entry 对 ThreadLocal 是弱引用(WeakReference),所以只要 ThreadLocal 结束了自己的生命周期是可以被回收掉的。但是 Entry 中的 Value 却是被 Entry 强引用的,所以即便 Value 的生命周期结束了,Value 也是无法被回收的,从而导致内存泄露。

解决办法:

ExecutorService es;
ThreadLocal tl;
es.execute(()->{
  tl.set(obj);//ThreadLocal增加变量
  try {
    // 省略业务逻辑代码
  }finally {
    tl.remove();//手动清理ThreadLocal 
  }
});

避免共享变量的两种解决方案,使用局部变量会频繁创建对象,使用threadlocal也是针对线程创建新变量,都是针对线程维度,threadlocal并未体现出什么优势,为什么还要用threadlocal

回答:threadlocal=线程数,局部变量=调用量,差距太大了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值