1.ThreadLocal用处:
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本,从而达到线程安全。
例如:
public class TestNum {
// ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
private ThreadLocal<User> seqNum = new ThreadLocal<User>(){
@Override
protected User initialValue() {
return new User();
}
};
}
变量seqNum使用ThreadLocal维护的一个User变量
2.案例详解与分析
当使用:
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();
在每一个线程中,都会创建一个User对象,保存在Thread.threadLocals变量保存, Thread. threadLocals变量是一个key-value型的变量,key是当前维护user对象的threadLocal,
1》 怎么创建User:
ThreadLocal源码:
初始化:initialValue(): return newUser();
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the <tt>initialValue</tt> method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* <p>This implementation simply returns <tt>null</tt>; if the
* programmer desires thread-local variables to have an initial
* value other than <tt>null</tt>, <tt>ThreadLocal</tt> must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
protected T initialValue() {
return null;
}
为每个thread创建User对象:
/**
* 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();
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
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;
}
在获取User对象时,会根据当前线程,获取线程的thread.threadLocals,如果当前线程之前没有存储过这个user,就创建调用setInitialValue(),如果有就返回:
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
2》关于ThreadLocalmap:
a.ThreadLocal的内部类;
b.key-value类型存储;
c.key是当前ThreadLocal对象,value就是当前threadLocal维护的对象user
d.每个线程都有一个threadLocals,用于维护这个线程的线程安全的一系列对象
e.ThreadLocal中定义的子类,但是在Thread类中存在变量
3》销毁user:
由于ThreadLocal维护的user对象是跟当前线程相关的,只保存在当前线程的threadLocals变量中,thread会在exit()方法中将threadLocal变量至空。
/**
* This method is called by the system to give a Thread
* a chance to clean up before it actually exits.
*/
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
/* Speed the release of some of these resources */
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
3.与synchronized对比:
1》都是解决线程同步问题
2》synchronized修饰:线程将排队访问变量,以时间换空间;threadloca修饰:会为每个线程创建一个副本,以空间换时间
3》synchronized修饰:每个线程的调用后对变量的修改都是有影响的;threadloca修饰:线程之间对变量的修改互不影响,各自持有变量的副本
4.关于Looper:
1》Looper类中有静态变量: static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal是静态的,所以每个Thread.threadLocals中对应的key是不变的,所以每个thread中,Looper只能有一个。这样就“ 保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue”