ThreadLocal的两种实现方式

ThreadLocal的两种实现方式
1.一个ThreadLocal对象内部有一个map,然后在每一个线程中获取值的时候,根据当前线程作为key到map中去获取对应的值
因为ThreadLocal中的值在每个线程中有一个副本,所以这种方式也非常的合适
但是缺点在于,多个线程会一起竞争同一个ThreadLocal对象的map,就会出现竞争,要想避免竞争,就要进行加锁
还有一个需要注意的点就是,如果我们的ThreadLocal的生命周期比Thread长,这种情况下要注意内存的泄漏问题

2.一个ThreadLocal对象中没有任何的map,而是将Map放到了Thread对象中,每个线程获取值的时候,以ThreadLocal做为key到map中去获取
这种方式跟上面是反着过来的,这样有什么好处呢?每个线程访问ThreadLocal的时候,不会出现竞争问题,每个线程访问的是当前线程自己内部的map
避免了加锁

目前的ThreadLocal就是使用的第二种方式实现的,下面我们自己来尝试一下实现这两种方式

第一种

public class CustomThreadLocal<T> {
	// 没有使用软引用,重点不在这里
    private Map<Thread, T> map = new HashMap<>();

    public T get() {
        Thread thread = Thread.currentThread();
        synchronized (map) {
            return map.get(thread);
        }
    }

    public void set(T t) {
        Thread thread = Thread.currentThread();
        synchronized (map) {
            map.put(thread, t);
        }
    }

    /**
     * 注意每次ThreadLocal使用结束之后一定要记得进行remove,否则会出现内存泄漏
     *
     * @param t
     */
    public void remove(T t) {
        synchronized (map) {
            map.remove(t);
        }
    }


    public T initValue() {
        return null;
    }
}

第二种

自定义的Thread类

public class CustomThread extends Thread {

    /**
     * 注意,Thread类内部其实已经有了一个map,但是我们不能访问
     * 所以这里我们自己定义一个map来实现,主要是为了展示思想
     */
    private Map<CustomThreadLocal, Object> map = new HashMap<>();

    public CustomThread(Runnable target) {
        super(target);
    }

    Object getValue(CustomThreadLocal local) {
        return map.get(local);
    }

    void set(CustomThreadLocal local, Object value) {
        map.put(local, value);
    }

    void remove(CustomThreadLocal local) {
        map.remove(local);
    }

}
public class CustomThreadLocal<T> {

    public T get() {
        Thread t = Thread.currentThread();
        if (t instanceof CustomThread) {
            CustomThread thread = (CustomThread) t;
            T value = (T) thread.getValue(this);
            if (value == null) {
                value = initValue();
                set(value);
            }
            return value;
        }
        return null;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        if (t instanceof CustomThread) {
            CustomThread thread = (CustomThread) t;
            thread.set(this, value);
        }
    }
	
	/**
	* remove方法非常的重要,在每次使用完Thread对象之后都应该去调用该方法
	*/
    public void remove() {
        Thread t = Thread.currentThread();
        if (t instanceof CustomThread) {
            CustomThread thread = (CustomThread) t;
            thread.remove(this);
        }
    }

    public T initValue() {
        return null;
    }
}

ThreadLocal的一个使用场景:ThreadContext

在很多时候我们需要在做大量的任务处理的时候,可能会遇到很多地方都需要使用同一个对象的这种情况但是有了ThreadLocal之后,我们有了一种更加优雅的实现方式,每次使用的时候直接向ThreadLocal取而不用在方法之间传来传去

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值