首页
学习
活动
专区
圈层
工具
发布

并发编程讲解(二)

● ThreadLocal介绍

ThreadLocal叫做线程本地变量,也有些地方叫做线程本地存储,ThreadLocal 的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。

● Thread与ThreadLocal源码的解析

代码语言:javascript
复制
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
代码语言:javascript
复制
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

我们以set方法为例子,当线程第一次调用ThreadLocal的set方法时候会创建Thread对象里面的threadLocals成员。也就是说ThreadLocal的每次set和get操作,都是对Thread的threadLocals进行操作,ThreadLocals类似于threadLocals变量的管理者

threadLocals类似一个特殊的Map,它的key就是threadLocal的实例,而value就是我们设置的value值。

● ThreadLocal使用注意事项

在一个操作系统中,线程和进程是有数量上限的。在操作系统中,确定线程和进程唯一性的唯一条件就是线程进程 ID。操作系统在回收线程或进程的时候,不是一定杀死线程或进程,在繁忙的时候对线程或进程栈数据的操作,可能重复使用线程或进程。

使用ThreadLocal的时候,一定注意回收资源问题,每个线程结束之前,将当前线程保存的线程变量一定要删除 ,调用ThreadLocal.remove(),要不会发生泄露。run方法的finally代码块。

在并发量高的时候,可能有内存溢出

● ThreadLocal使用实例

代码语言:javascript
复制
public class Test_ThreadLocal {

    volatile static String name = "zhangsan";
    static ThreadLocal<String> tl = new ThreadLocal<>();

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                name = "lisi";
                tl.set("wangwu");
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 等待前一条线程运行结束
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(name);
                System.out.println(tl.get());
            }
        }).start();

    }

}

运行结果是:lisi 和 null。

就是说虽然第二条线程的打印在第一条线程set之后,当时它在ThreadLocad容器中取不到相关的值。

下一篇
举报
领券