线程封闭#
当访问共享的可变数据时,通常需要同步.一种避免同步的方法就是不共享数据.如果仅在单线程内访问数据,就不需要同步.这种技术被称为线程封闭,它是实现线程安全性的最简单方式之一.当某个对象封闭在一个线程中,这种用法将自动实现线程安全性,即使被封闭的对象本身不是线程安全的.
ThreadLocal类##
- jdk实现的ThreadLocal是典型的维持线程封闭性的方法,这个类能使线程中的某个值与保存的对象关联起来.ThreadLocal提供了set和get等访问接口和方法,这些方法为每个使用这个变量的线程都存有一份独立的副本.
- ThreadLocal对象通常用于防止对可变的单实例变量或全局变量进行共享.
一个小例子来使用ThreadLocal类
public class Counter {
private static ThreadLocal<Integer> context = new ThreadLocal<Integer>() {
protected Integer initialValue() {
return 10;
}
};
public static Integer get() {
return context.get();
}
public static void set(Integer value) {
context.set(value);
}
public static Integer getNextCounter() {
context.set(context.get()+1);
return context.get();
}
}
创建多个线程访问ThreadLocal类初始化的变量.
public class ThreadLocalTest extends Thread{
public void run() {
for (int i = 0; i < 3; i++) {
System.out.println("Thread["+Thread.currentThread().getName()+"],counter="
+Counter.getNextCounter());
}
}
public static void main(String[] args) {
ThreadLocalTest thread1 = new ThreadLocalTest();
ThreadLocalTest thread2 = new ThreadLocalTest();
ThreadLocalTest thread3 = new ThreadLocalTest();
thread1.start();
thread2.start();
thread3.start();
}
}
3个线程对初始值的修改都互不影响
Thread[Thread-1],counter=11
Thread[Thread-1],counter=12
Thread[Thread-1],counter=13
Thread[Thread-2],counter=11
Thread[Thread-2],counter=12
Thread[Thread-2],counter=13
Thread[Thread-0],counter=11
Thread[Thread-0],counter=12
Thread[Thread-0],counter=13
get和set方法是如何与当前线程关联起来的?##
public class ThreadLocal<T> {
public void set(T value) {
Thread t = Thread.currentThread();//获取当前访问的线程
ThreadLocalMap map = getMap(t);//获取当前线程中的ThreadLocalMap
if (map != null)
map.set(this, value);//如果不为空的话,就以当前hreadLocal实例为key,存储的对象为值存入ThreadLocalMap 中
else
createMap(t, value);//创建一个ThreadLocalMap
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);//同样以当前ThreadLocal实例为key
}
public T get() {
Thread t = Thread.currentThread();//获取当前访问的线程
ThreadLocalMap map = getMap(t);//获取当前线程中的ThreadLocalMap
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);//获取当前线程中以当前ThreadLocal实例为key的变量值
if (e != null)
return (T)e.value;
}
return setInitialValue();//当map不存在的时候设置初始值.
}
ThreadLocalMap getMap(Thread t) {//从线程中获取对应的ThreadLocalMap,是多个ThreadLocal的集合.
return t.threadLocals;
}
}