在Java中分析ThreadLocal实例
从概念上理解threadlocal可以使变量与多个线程隔离,以实现线程安全. threadlocal打包的变量最终专用于每个相应的线程. 线程彼此独立. 一个具体的实现用于说明: <
public interface Consumer {
int consume();
}
public class ComsumeThread implements Runnable {
private Consumer consumer;
public ComsumeThread(Consumer consumer) {
this.consumer = consumer;
}
@Override
public void run() {
for(int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+" After Consume left:"+consumer.consume());
}
}
}
public class ConsumeClientA implements Consumer {
private static int leftNum = 30;
@Override
public int consume() {
int orgLeftNum = leftNum;
Random random = new Random(System.currentTimeMillis());
try {
Thread.sleep(random.nextInt(3));
} catch (InterruptedException e) {
e.printStackTrace();
}
orgLeftNum = orgLeftNum -1;
leftNum = orgLeftNum;
return leftNum;
}
public static void main(String[] args){
Consumer consumer = new ConsumeClientA();
Thread thread1 = new Thread(new ComsumeThread(consumer));
Thread thread2 = new Thread(new ComsumeThread(consumer));
Thread thread3 = new Thread(new ComsumeThread(consumer));
thread1.start();
thread2.start();
thread3.start();
}
}
ConsumeClientA没有进行任何线程安全的处理,结果如下:
Thread-2 After Consume left:29
Thread-1 After Consume left:29
Thread-3 After Consume left:29
Thread-2 After Consume left:28
Thread-1 After Consume left:28
Thread-3 After Consume left:28
Thread-2 After Consume left:27
Thread-1 After Consume left:27
Thread-2 After Consume left:26
Thread-3 After Consume left:27
Thread-1 After Consume left:25
Thread-2 After Consume left:25
Thread-3 After Consume left:25
Thread-1 After Consume left:24
Thread-2 After Consume left:24
Thread-3 After Consume left:24
Thread-1 After Consume left:23
Thread-2 After Consume left:23
Thread-3 After Consume left:23
Thread-1 After Consume left:22
Thread-2 After Consume left:22
Thread-3 After Consume left:22
Thread-1 After Consume left:21
Thread-2 After Consume left:21
Thread-3 After Consume left:21
Thread-1 After Consume left:20
Thread-2 After Consume left:20
Thread-3 After Consume left:20
Thread-1 After Consume left:19
Thread-3 After Consume left:18
添加线程本地处理,每个线程彼此独立,实现如下:
public class ConsumeClientB implements Consumer {
private ThreadLocal leftNumThreadLocal = new ThreadLocal(){
@Override
protected Integer initialValue() {
return 30;
}
};
@Override
public int consume() {
int orgLeftNum = leftNumThreadLocal.get();
Random random = new Random(System.currentTimeMillis());
try {
Thread.sleep(random.nextInt(3));
} catch (InterruptedException e) {
e.printStackTrace();
}
orgLeftNum = orgLeftNum -1;
leftNumThreadLocal.set(orgLeftNum);
return leftNumThreadLocal.get();
}
public static void main(String[] args){
Consumer consumer = new ConsumeClientB();
Thread thread1 = new Thread(new ComsumeThread(consumer));
Thread thread2 = new Thread(new ComsumeThread(consumer));
Thread thread3 = new Thread(new ComsumeThread(consumer));
thread1.start();
thread2.start();
thread3.start();
}
}
操作结果如下:
Thread-1 After Consume left:29
Thread-3 After Consume left:29
Thread-2 After Consume left:29
Thread-1 After Consume left:28
Thread-3 After Consume left:28
Thread-2 After Consume left:28
Thread-1 After Consume left:27
Thread-3 After Consume left:27
Thread-2 After Consume left:27
Thread-1 After Consume left:26
Thread-3 After Consume left:26
Thread-2 After Consume left:26
Thread-1 After Consume left:25
Thread-3 After Consume left:25
Thread-2 After Consume left:25
Thread-1 After Consume left:24
Thread-3 After Consume left:24
Thread-2 After Consume left:24
Thread-1 After Consume left:23
Thread-3 After Consume left:23
Thread-2 After Consume left:23
Thread-1 After Consume left:22
Thread-3 After Consume left:22
Thread-2 After Consume left:22
Thread-1 After Consume left:21
Thread-3 After Consume left:21
Thread-2 After Consume left:21
Thread-1 After Consume left:20
Thread-3 After Consume left:20
Thread-2 After Consume left:20
每个线程都有自己的独立变量threadlocal使用实例,将它们彼此隔离以实现线程安全.
ThreadLocal如何实现这种线程隔离和线程安全性?
从ThreadLocal源代码可以看出,线程隔离和线程挂钩实际上是ThreadLocal.ThreadLocalMap的实现类. 最明显的体现是,这样的Thread源代码变量声明表明ThreadLocal.ThreadLocalMap和Thread Relationships:
ThreadLocal.ThreadLocalMap threadLocals, inheritableThreadLocals;
Thread类包含threadLocals对象. ThreadLocal的具体实现是根据提供的get,set和其他接口,对当前线程的threadLocals变量执行相关操作,例如以下get操作代码:
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();
}
ThreadLocal.ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
如您所见,getMap()方法是从当前线程获取相应的threadLocals变量,然后从ThreadLocal.ThreadLocalMap类型的threadLocals变量获取与相应线程中的ThreadLocal对象相对应的变量值.
set方法的操作相同:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocal.ThreadLocalMap map = getMap(t);
if(map != null) {
map.set(this, value);
} else {
this.createMap(t, value);
}
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static class Entry extends WeakReference {
Object value;
Entry(ThreadLocal var1, Object var2) {
super(var1);
this.value = var2;
}
}
在ThreadLocalMap中,有一个内部类Entry数组. 条目继承WeakReference实现. WeakReference的优点是保存对象引用,而不会干扰GC回收的对象. 当线程完成对threadLocals变量的回收后,Entry将不会对其进行封装. 变量的干扰.
并且ThreadLocalMap中的键是ThreadLocal,因此ThreadLocal对象只能将ThreadLocal值保存在Thread对象中.
总而言之threadlocal使用实例,很说ThreadLocal的实现是一种映射结构,将Thread对象存储为键,将变量存储为ThreadLocalMap中的值,这实际上是错误的.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-269085-1.html