这里有新鲜出炉的 Java 函数式编程,程序狗速度看过来!
java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台(即 JavaEE(j2ee), JavaME(j2me), JavaSE(j2se))的总称。
这篇文章主要介绍了 java 中 ThreadLocal 实例分析的相关资料, 需要的朋友可以参考下
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
增加 threadlocal 处理,每个线程相互独立,实现如下:
- public class ConsumeClientB implements Consumer {
- private ThreadLocal<Integer> leftNumThreadLocal = new ThreadLocal<Integer>(){
- @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.ThreadLocalMap 这个实现类,最明显的体现就在于 Thread 类源码的这样一个变量申明说明了 ThreadLocal.ThreadLocalMap 与 Thread 的关系:
- ThreadLocal.ThreadLocalMap threadLocals, inheritableThreadLocals;
Thread 类是包含 threadLocals 对象的,ThreadLocal 的具体实现就是根据提供的 get,set 等接口,对当前 thread 的 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() 方法就是从当前 thread 获取对应的 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 < ThreadLocal > {
- Object value;
- Entry(ThreadLocal var1, Object var2) {
- super(var1);
- this.value = var2;
- }
- }
ThreadLocalMap 中存的是内部类 Entry 的数组, Entry 是继承 WeakReference 实现,WeakReference 的好处是保存对象引用,而又不干扰该对象被 GC 回收,线程执行完回收 threadLocals 变量时不会受到 Entry 封装的变量的干扰。
而且 ThreadLocalMap 中的 key 是 ThreadLocal,所以一个 ThreadLocal 对象只能在一个 Thread 对象中保存一个 ThreadLocal 的 value。
综上,很多人说 ThreadLocal 的实现是 ThreadLocalMap 中存 Thread 对象为 key,变量为 value 的 map 结构,其实是错误的。
来源: http://www.phperz.com/article/17/0828/338256.html