ThreadLocal的使用及实现原理

1、介绍

概念:ThreadLocal叫做线程本地变量,当某个线程访问该变量的时候,会在当前线程内部创建一个该变量的副本,在当前线程中对该变量的操作(增删改查)都是针对的副本变量,不会对其它线程造成影响。

作用:使共享变量在多线程间隔离操作,相互不影响,达到线程隔离的效果。

在这里插入图片描述

2、和synchronized异同

synchronizedThreadLocal都是为了解决并发编程中可能出现的线程安全问题,二者采取的完全相反的解决方式,应用场景不同。

synchronized是采用锁机制,使操作共享变量的代码块或方法在同一时间段只能被一个线程访问。

ThreadLocal是采用隔离机制,直接将要操作的共享变量复制到线程私有,使每个线程访问到的不是同一个变量。

3、使用示例

/**
 * 代码
 */
public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Content content = new Content();
        new Thread(()->{
            System.out.println("线程名称:"+Thread.currentThread().getName());
            System.out.println(content.getLocalVal().get());
            content.getLocalVal().set("aaa");
            System.out.println(content.getLocalVal().get());
        }).start();

        TimeUnit.SECONDS.sleep(3);

        System.out.println("线程名称:"+Thread.currentThread().getName());
        System.out.println(content.getLocalVal().get());
        content.getLocalVal().set("bbb");
        System.out.println(content.getLocalVal().get());
    }
}

class Content {
    private ThreadLocal<String> localVal = new ThreadLocal<>();

    public ThreadLocal<String> getLocalVal() {
        return localVal;
    }
}


/**
 * 运行结果
 * 
 * 线程名称:Thread-0
 * null
 * aaa
 * 线程名称:main
 * null
 * bbb
 */
//可以看到,Thread-0线程对变量localVal的操作,并没有影响到主线程的操作。

4、实现原理

每个线程内部都有一个ThreadLocalMap对象,其中的键为ThreadLocal,值就是我们设置的value,查看源码。

ThreadLocal.set()源码

/**
 * Sets the current thread's copy of this thread-local variable
 * to the specified value.  Most subclasses will have no need to
 * override this method, relying solely on the {@link #initialValue}
 * method to set the values of thread-locals.
 *
 * @param value the value to be stored in the current thread's copy of
 *        this thread-local.
 */
public void set(T value) {
    //获取当前线程。
	Thread t = Thread.currentThread();
    //获取当前线程的ThreadLocalMap对象。
	ThreadLocalMap map = getMap(t);
	if (map != null)
        //如果当前线程的ThreadLocalMap对象不为null,将value设置到当前线程。
		map.set(this, value);
	else
        //若ThreadLocalMap为null,则创建ThreadLocalMap对象并赋值。
		createMap(t, value);
}

ThreadLocal.get()源码

/**
 * Returns the value in the current thread's copy of this
 * thread-local variable.  If the variable has no value for the
 * current thread, it is first initialized to the value returned
 * by an invocation of the {@link #initialValue} method.
 *
 * @return the current thread's value of this thread-local
 */
public T get() {
    //获取当前线程。
	Thread t = Thread.currentThread();
    //获取当前线程的ThreadLocalMap对象。
	ThreadLocalMap map = getMap(t);
	if (map != null) {
        //根据当前线程获取ThreadLocalMap的value。
		ThreadLocalMap.Entry e = map.getEntry(this);
		if (e != null) {
			@SuppressWarnings("unchecked")
			T result = (T)e.value;
			return result;
		}
	}
	return setInitialValue();
}

5、注意事项

在使用完ThreadLocal时,及时调用它的remove()方法,避免内存泄露风险。

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Content content = new Content();
        new Thread(()->{
            System.out.println("线程名称:"+Thread.currentThread().getName());
            System.out.println(content.getLocalVal().get());
            content.getLocalVal().set("aaa");
            System.out.println(content.getLocalVal().get());

            content.getLocalVal().remove();
        }).start();

        TimeUnit.SECONDS.sleep(3);

        System.out.println("线程名称:"+Thread.currentThread().getName());
        System.out.println(content.getLocalVal().get());
        content.getLocalVal().set("bbb");
        System.out.println(content.getLocalVal().get());

        content.getLocalVal().remove();
    }
}

class Content {
    private ThreadLocal<String> localVal = new ThreadLocal<>();

    public ThreadLocal<String> getLocalVal() {
        return localVal;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值