婚庆网站策划书,网站 建设 原则,造价统计报表在哪个网站上做,手机app下载客户端此类提供线程局部变量。这些变量与普通变量不同#xff0c;每个访问一个线程#xff08;通过其get或set方法#xff09;的线程 都有其自己的#xff0c;独立初始化的变量副本。 ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段#xff08;例如#xff0c…此类提供线程局部变量。这些变量与普通变量不同每个访问一个线程通过其get或set方法的线程 都有其自己的独立初始化的变量副本。 ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段例如用户ID或事务ID。 以射击游戏举例游戏开始时,每个人能够领到一把枪,枪把上有三个数字:子弹数、杀敌数、自己的命数为其设置的初始值分别为100、0、10.设战场上的每个人都是一个线程,那么这三个初始值写在哪里呢? 如果每个线程都写死这三个值,万一将初始子弹数统一改成 1000发呢? 如果共享,那么线程之间的并发修改会导致数据不准确. 能不能构造这样一个对象,将这个对象设置为共享变量,统一设置初始值,但是每个线程对这个值的修改都是互相独立的.这个对象就是ThreadLocal 一、类定义
public class ThreadLocalT {}…用来限制Class中的参数类型确保Class中参数的一致性
二、实例变量和相关方法
//用于ThreadLocalMap
private final int threadLocalHashCode nextHashCode();//下一个hash code从0开始
private static AtomicInteger nextHashCode new AtomicInteger();//hash增量
private static final int HASH_INCREMENT 0x61c88647;//在获取下一个hash code
private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);
}三、内部类
内部类ThreadLocalMap
ThreadLocalMap负责存储ThreadLocal及其变量即ThreadLocal对象本身作为键ThreadLocal存储的变量作为值。每个Thread对象在声明一个ThreadLocal后会持有一个ThreadLocalMap的引用来实现ThreadLocal的功能。
ThreadLocalMap持有一个内部类Entry类似于HashMap.Node类负责保存键值对。
static class Entry extends WeakReferenceThreadLocal? {Object value;Entry(ThreadLocal? k, Object v) {super(k);value v;}
}Entry继承了WeakReference类使Entry的键为弱引用。
看到这里很多人或许有这样一个疑问为什么Entry要继承WeakReference 既然将ThreadLocal声明为弱引用那么自然会联想到和GC有关。
如果不声明为弱引用以最上面Test类的代码为例当我们将上述ThreadLocal类型的静态变量tl设置为null时Thread对象成员变量threadLocals依然保留有一个ThreadLocalMap该Map中持有保存该ThreadLocal的Entry在这个线程运行期间无法GC从而引发内存泄漏。所以Entry的键要声明为弱引用。
四、主要方法
1.get()
返回此线程局部变量的当前线程副本中的值。
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();
}首先是获取当前运行线程对象然后根据该线程对象找到对应的ThreadLocalMap。
如果找到了该线程对应的ThreadLocalMap则通过当前ThreadLocal对象作为键查找Map中对应的Entry键值对对象如果查找结果不为null则返回Entry对象的value。否则调用setInitialValue方法将当前ThreadLocal对象(this)和变量作为键值对存入ThreadLocalMap并返回变量。
2.initialValue()
为变量设置初始值该方法的默认实现是
protected T initialValue() {return null;
}如果想要为该变量设置一个初始值只需重写该方法即可例如
Override
protected String initialValue() {return hello world;
}3.set(T value)
与get方法类似set方法首先会获取当前运行的Thread对象并通过该对象获取对应的ThreadLocalMap如果map为空则为当前Thread对象新建一个ThreadLocalMap否则直接将value放入map中。
public void set(T value) {Thread t Thread.currentThread();ThreadLocalMap map getMap(t);if (map ! null)map.set(this, value);elsecreateMap(t, value);
}4、remove()
同样获取当前Thread对应的ThreadLocalMap然后调用ThreadLocalMap的remove方法移除ThreadLocal对象无需通过弱引用机制对该ThreadLocal对象进行GC。
public void remove() {ThreadLocalMap m getMap(Thread.currentThread());if (m ! null)m.remove(this);
}五、总结
ThreadLocal是如何做到为每一个线程维护变量的副本的呢
在ThreadLocal类中设置了一个Map存储每一个线程的变量的副本。
ThreadLocal使用场合主要解决多线程中数据数据因并发产生不一致问题。ThreadLocal为每个线程的中并发访问的数据提供一个副本通过访问副本来运行业务这样的结果是耗费了内存单大大减少了线程同步所带来性能消耗也减少了线程并发控制的复杂度。
Synchronized用于线程间的数据共享而ThreadLocal则用于线程间的数据隔离。
Threadlocal底层是通过threadlocalMap进行存储键值 每个ThreadLocal类创建一个Map然后用线程的ID作为Map的key实例对象作为Map的value这样就能达到各个线程的值隔离的效果。 ThreadLocal的作用是提供线程内的局部变量这种变量在线程的生命周期内起作用减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。