前言
先考虑一个问题,多线程的情况下,如何隔离变量,例如
1 2 3 4 5 6 7 8 9 10 11
| public class Number{ private int number;
public int getNumber() { return number; }
public void setNumber(int number) { this.number = number; } }
|
在两个线程同时访问同一个Number实例时,从效果来看,通过getNumber获取到的是同一个值,并且可以通过setNunber修改其他线程的值,如何做到number在线程间的隔离呢
Map
先看例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Number{ private Map<Thread, Integer> numberMap;
public int getNumber() { Thread thread = Thread.currentThread(); return numberMap.get(thread); }
public void setNumber(int number) { Thread thread = Thread.currentThread(); numberMap.put(thread, number); }
public void remove(){ Thread thread = Thread.currentThread(); numberMap.remove(thread); } }
|
从效果来看,两个线程同时访问同一个Number实例时,通过getNumber获取的值是不一样的,并且无法通过setNunber修改其他线程的值,但是有一个问题,严格来讲,numberMap仍然是线程间持有的,线程仍然可以通过手段访问到其他线程的值甚至线程对象
ThreadLocal
先看例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Number{ private ThreadLocal<Integer> threadLocal;
public int getNumber() { return threadLocal.get(); }
public void setNumber(int number) { threadLocal.set(number); }
public void remove(){ threadLocal.remove(); } }
|
ThreadLocal类的get和set方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
|
从ThreadLocal的get和set方法,不难看出,是使用了当前线程的一个ThreadLocalMap,number相当于是存储到了线程内部,所以ThreadLocalMap 可以实现一个隔离的效果