Java Concurrency <ThreadLocal>
Java中的ThreadLocal类允许您创建只能由同一个线程读取和写入的变量。 因此,即使两个线程正在执行相同的代码,并且代码对ThreadLocal变量进行了引用,那么两个线程也看不到彼此的ThreadLocal变量。
- 创建一个ThreadLocal
private ThreadLocal myThreadLocal = new ThreadLocal();
您可以看到,您实例化了一个新的ThreadLocal对象。 这只需要每个线程完成一次。 即使不同的线程执行访问ThreadLococal的相同代码,每个线程都将只看到自己的ThreadLocal实例。 即使两个不同的线程在同一个ThreadLocal对象上设置不同的值,它们也看不到对方的值。
- 访问ThreadLocal
myThreadLocal.set("A thread local value");
- 读取数据
String threadLocalValue = (String) myThreadLocal.get();
- 泛型
private ThreadLocal<String> myThreadLocal = new ThreadLocal<String>();
- 初始化ThreadLocal的值
private ThreadLocal myThreadLocal = new ThreadLocal<String>() {
@Override protected String initialValue() {
return "This is the initial value";
}
};
DEMO
public class ThreadLocalExample {
public static class MyRunnable implements Runnable {
private ThreadLocal<Integer> threadLocal =
new ThreadLocal<Integer>();
@Override
public void run() {
threadLocal.set( (int) (Math.random() * 100D) );
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println(threadLocal.get());
}
}
public static void main(String[] args) {
MyRunnable sharedRunnableInstance = new MyRunnable();
Thread thread1 = new Thread(sharedRunnableInstance);
Thread thread2 = new Thread(sharedRunnableInstance);
thread1.start();
thread2.start();
thread1.join(); //wait for thread 1 to terminate
thread2.join(); //wait for thread 2 to terminate
}
}
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本.线程隔离的秘密,就在于ThreadLocalMap这个类。ThreadLocalMap是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取(对比Map对象来理解),每个线程中都有一个独立的ThreadLocalMap副本,它所存储的值,只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本,从而实现了变量访问在不同线程中的隔离。因为每个线程的变量都是自己特有的,完全不会有并发错误。还有一点就是,ThreadLocalMap存储的键值对中的键是this对象指向的ThreadLocal对象,而值就是你所设置的对象了
- InheritableThreadLocal
InheritableThreadLocal类是ThreadLocal的一个子类。 InheritableThreadLocal不是每个线程在ThreadLocal中具有自己的值,而是授予对线程和该线程创建的所有子线程的值的访问权限。
网友评论