Java并发编程之ThreadLocal类详解
jopen
10年前
ThreadLocal类可以理解为ThreadLocalVariable(线程局部变量),提供了get与set等访问接口或方法,这些方法为每个使用该变量的线程都存有一份独立的副本,因此get总是返回当前执行线程在调用set时设置的最新值。可以将ThreadLocal<T>视为 包含了Map<Thread,T>对象,保存了特定于该线程的值。
概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
模拟ThreadLocal
import java.util.Collections; import java.util.HashMap; import java.util.Map; public class SimpleThreadLocal<T> { private Map<Thread, T> valueMap = Collections .synchronizedMap(new HashMap<Thread, T>()); public void set(T newValue) { valueMap.put(Thread.currentThread(), newValue); // ①键为线程对象,值为本线程的变量副本 } public T get() { Thread currentThread = Thread.currentThread(); T o = valueMap.get(currentThread); // ②返回本线程对应的变量 if (o == null && !valueMap.containsKey(currentThread)) { // ③如果在Map中不存在,放到Map中保存起来。 o = initialValue(); valueMap.put(currentThread, o); } return o; } public void remove() { valueMap.remove(Thread.currentThread()); } protected T initialValue() { return null; } }
实用ThreadLocal
class Count { private SimpleThreadLocal<Integer> count = new SimpleThreadLocal<Integer>() { @Override protected Integer initialValue() { return 0; } }; public Integer increase() { count.set(count.get() + 1); return count.get(); } } class TestThread implements Runnable { private Count count; public TestThread(Count count) { this.count = count; } @Override public void run() { // TODO Auto-generated method stub for (int i = 1; i <= 3; i++) { System.out.println(Thread.currentThread().getName() + "\t" + i + "th\t" + count.increase()); } } } public class TestThreadLocal { public static void main(String[] args) { Count count = new Count(); Thread t1 = new Thread(new TestThread(count)); Thread t2 = new Thread(new TestThread(count)); Thread t3 = new Thread(new TestThread(count)); Thread t4 = new Thread(new TestThread(count)); t1.start(); t2.start(); t3.start(); t4.start(); } }
输出
Thread-0 1th 1
Thread-0 2th 2
Thread-0 3th 3
Thread-3 1th 1
Thread-1 1th 1
Thread-1 2th 2
Thread-2 1th 1
Thread-1 3th 3
Thread-3 2th 2
Thread-3 3th 3
Thread-2 2th 2
Thread-2 3th 3