Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65717
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 15:04
个人简介

记录,分享

文章分类

全部博文(43)

文章存档

2017年(24)

2015年(1)

2014年(18)

我的朋友

分类: Java

2017-03-16 12:16:50

ThreadLocal是为了使每个线程保存一份属于自己的数据。


先看一个使用ThreadLocal的实例。


package org.springframework.aop.framework;

import org.springframework.core.NamedThreadLocal;

publicabstractclass AopContext {

privatestaticfinal ThreadLocal<< span>Object> currentProxy =new NamedThreadLocal<< span>Object>("Current AOP proxy");

publicstatic Object currentProxy() throws IllegalStateException {
        Object proxy 
= currentProxy.get();
if (proxy ==null) {
thrownew IllegalStateException(
"Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available.");
        }
return proxy;
    }

static Object setCurrentProxy(Object proxy) {
        Object old 
= currentProxy.get();
if (proxy !=null) {
            currentProxy.set(proxy);
        }
else {
            currentProxy.remove();
        }
return old;
    }

}


上例展示的是spring框架中获取当前线程的代理对象的方法,AopContext.currentProxy(),在本线程的程序调用栈中只要调用AopContext的静态方法就可以获取本线程相关的代理对象。如果不用ThreadLocal,那么这个代理对象在创建后,就要一层层传递下去,才能在后面获取到并使用。
通过这个例子,我们可以知道[b]ThreadLocal主要是提供了一种保持对象的方法以及避免了对象在程序调用中传递的简便访问方法。ThreadLocal与共享数据和同步没有明显关系。[/b]

下面看看相关的源码以了解具体的结构。

publicclass Thread implements Runnable {
// ThreadLocalMap是一个以ThreadLocal为key,Object为值的map,由ThreadLocal维护
        ThreadLocal.ThreadLocalMap threadLocals =null;
}


从Thread的源码中可以得知,是每一个Thread持有一个自己的map,并不是一个ThreadLocal持有一个map。


publicclass ThreadLocal<< span>T> {

public T get() {
// 获取当前线程
        Thread t = Thread.currentThread();
// 获取当前线程的threadLocals变量
        ThreadLocalMap map = getMap(t);
// 从当前线程的threadLocals变量中取得本threadLocal为key的值
if (map !=null) {
            ThreadLocalMap.Entry e 
= map.getEntry(this);
if (e !=null)
return (T)e.value;
        }
return setInitialValue();
    }

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


publicvoid set(T value) {
// 获取当前线程
        Thread t = Thread.currentThread();
// 获取当前线程的threadLocals变量
        ThreadLocalMap map = getMap(t);
// 以本threadLocal为key的保存值到当前线程的threadLocals变量中去
if (map !=null)
            map.set(
this, value);
else
            createMap(t, value);
    }

     ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
    }

void createMap(Thread t, T firstValue) {
        t.threadLocals 
=new ThreadLocalMap(this, firstValue);
    }
}


使用ThreadLocal过程: 对于每一个需要线程保存自身实例的变量,需要定义一个静态的ThreadLocal实例。然后将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象。
此外,每个线程保存的自身数据并不是通过备份或复制的,而是new创建出来的。

通过ThreadLocal各个线程只能获取自身对应的数据,不能访问其他线程的数据,但是如果两个线程在set时引用了同一个数据,仍然存在同步问题。

阅读(536) | 评论(0) | 转发(0) |
0

上一篇:JUC - SynchronousQueue

下一篇:classpath详解

给主人留下些什么吧!~~