ThreadLocal详解

作者: 李亚楠0219 | 来源:发表于2017-06-14 15:18 被阅读110次

ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。
这个类有什么作用,或者说为什么要有这么一个类呢?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用变量的一个新的副本。
我们使用如下代码进行测试:

public class TestNum {  
    //通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值  
    private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {  
        public Integer initialValue() {  
            return 0;  
        }  
    };  
    // 获取下一个序列值  
    public int getNextNum() {  
        seqNum.set(seqNum.get() + 1);  
        return seqNum.get();  
    }  
    //主要看这里
    public static void main(String[] args) {
        //变量
        TestNum sn = new TestNum();  
        // 3个线程共享同一个变量sn,各自产生序列号  
        TestClient t1 = new TestClient(sn);  
        TestClient t2 = new TestClient(sn);  
        TestClient t3 = new TestClient(sn);  
        t1.start();  
        t2.start();  
        t3.start();  
    }  
    private static class TestClient extends Thread {  
        private TestNum sn;  
        public TestClient(TestNum sn) {  
            this.sn = sn;  
        }  
        public void run() {  
            for (int i = 0; i < 3; i++) {  
                //每个线程打出3个序列值  
                System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn["  
                         + sn.getNextNum() + "]");  
            }  
        }  
    }  
}  

输出结果:

thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-2] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-2] --> sn[3]

由上可见,三个线程公用同一个变量,但是对变量的操作却互不影响,那么这种机制是如何实现的?
以上代码在getNextNum中使用了ThreadLocal的set方法,我们查看ThreadLocal中set方法的实现:

 public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

set方法首先获取当前线程,然后查看当前线程的threadLocals变量是否为空,若为空,则调用createMap为其(线程)创建一个新的threadLocals变量,否则为其赋值,从以上分析中,我们可以看出,在用户使用ThreadLocal中的set方法是,他会根据线程的不同,采用不同的副本。
事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。

相关文章

  • ThreadLocal和InheritableThreadLoc

    ThreadLocal详解 - 简书 InheritableThreadLocal详解 - 简书 ThreadLo...

  • InheritableThreadLocal详解

    1、简介 在上一篇 ThreadLocal详解 中,我们详细介绍了ThreadLocal原理及设计,从源码层面上分...

  • ThreadLocal 详解

    ThreadLocal 详解 1. 前言 ThreadLocal是java线程中的局部变量,变量作用域仅在当前线程...

  • ThreadLocal详解

    1、简介 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Th...

  • ThreadLocal详解

    ThreadLocal之前我认为就是内部维护了一个ThreadLocalMap其中key为当前线程(Thread....

  • ThreadLocal详解

    介绍 顾名思义这个类提供线程局部变量每个线程(通过其get或set方法)都有自己独立初始化的变量副本 Thread...

  • ThreadLocal 详解

    ThreadLocal,我们一般称之为线程的局部变量,或者是线程的本地变量。很多人认为他与多线程的同步机制相关,其...

  • ThreadLocal详解

    ThreadLocal在java.lang包中,其主要作用是提供一个和线程绑定的变量环境,即通过ThreadLoc...

  • ThreadLocal详解

    ThreadLocal说明 ThreadLocal是一个线程内部的数据存储类,使用它来保存数据,只有当前的线程才可...

  • ThreadLocal详解

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。 这个玩意有什么用处,或者说为什么要有这么一个...

网友评论

本文标题:ThreadLocal详解

本文链接:https://www.haomeiwen.com/subject/smisqxtx.html