关于 ThreadLocal
关于ThreadLocal
java提供了java.lang.ThreadLocal,主要是用于解决多线程情况下变量安全的问题。
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
ThreadLocal提供了4个接口:
1. void set(Object value) 设置当前局部变量的值
2. Object get()该方法返回当前线程所对应的线程局部变量。
3. public void remove()将当前线程局部变量的值删除。线程结束后,会自动回收内存。
4. protected Object initialValue()返回该线程局部变量的初始值
使用场景
1. 当我们需要维护一个变量,并且这个变量需要在多线程情况下安全
2. 不想使用synchronized复杂的同步机制的ThreadLocal使用例子
看一下下面的一个简单的例子,多线程情况下,更新变量。
<span style="font-family:FangSong_GB2312;font-size:18px;">public class Test2 {
public static ThreadLocal<Integer> tl = new ThreadLocal<Integer>();
/**
* 入口函数
* @param args
*/
public static void main(String[] args) throws Exception {
for (int i = 0; i < 4; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 4; i++) {
Test2.tl.set(i);
System.out.println("Thread:" + Thread.currentThread().getId()
+ " ThreadLocal值:" + Test2.tl.get());
try {
Thread.sleep(1000);
} catch (Exception e) {
}
}
}
}).start();
}
}
}
</span>
结果:
ThreadLocal源码实现
set方法源码。可以看到set方法的时候,会去取当前的线程信息。然后放入ThreadLocalMap中。ThreadLocalMap是ThreadLocal类的一个静态内部类,它实现了键值对的设置和获取(对比Map对象来理解),每个线程中都有一个独立的ThreadLocalMap副本,它所存储的值,只能被当前线程读取和修改。ThreadLocal类通过操作每一个线程特有的ThreadLocalMap副本,从而实现了变量访问在不同线程中的隔离。
<span style="font-family:FangSong_GB2312;font-size:18px;"> /**
* 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 map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}</span>
get方法源码。
<span style="font-family:FangSong_GB2312;font-size:18px;"> /**
* 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 map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}</span>
静态内部类和非静态内部类区别:
1. 内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。
2. 非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。
3. 一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。
ThreadLocalMap就是一个静态内部类,Thread每个线程上都会有一个ThreadLocalMap,所以能实现线程安全。
转自:http://blog.csdn.net/initphp/article/details/8259391