zoukankan      html  css  js  c++  java
  • ThreadLocal用法和实现原理

    背景:

           如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap。

           并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义。

           那么你不要sychronize这么复杂的东西,ThreadLocal将是你不错的选择。

     why:

          因为线程同步限制了并发访问,会带来很大的性能损失。

    误解:

          ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。

     正解:

           其实 ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易理解。

           从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。

    举例来说:

    package com.xzc.util;
    
    import java.util.HashMap;
    
    /**
     * @Descrption
     * @Author xingzc
     * @Date 2018/11/9 10:18
     */
    public class TreadLocalTest {
        static ThreadLocal<HashMap> mapThreadLocal = new ThreadLocal<HashMap>() {
            @Override
            protected HashMap initialValue() {
                System.out.println(Thread.currentThread().getName() + "initialValue");
                return new HashMap();
            }
        };
    
        public void run() {
            Thread[] runs = new Thread[3];
            for (int i = 0; i < runs.length; i++) {
                runs[i] = new Thread(new T1(i));
            }
            for (int i = 0; i < runs.length; i++) {
                runs[i].start();
            }
        }
    
        public static class T1 implements Runnable {
            int id;
    
            public T1(int id0) {
                id = id0;
            }
    
            public void run() {
                System.out.println(Thread.currentThread().getName() + ":start");
                HashMap map = mapThreadLocal.get();
                for (int i = 0; i < 10; i++) {
                    map.put(i, i + id * 100);
                    try {
                        Thread.sleep(100);
                    } catch (Exception ex) {
                    }
                }
                System.out.println(Thread.currentThread().getName() + ':' + map);
            }
        }
    
        /**
         * Main
         *
         * @param args
         */
        public static void main(String[] args) {
            TreadLocalTest test = new TreadLocalTest();
            test.run();
        }
    
    }
    

      

    输出解释;

    Thread-0:start
    Thread-2:start
    Thread-1:start
    Thread-2initialValue
    Thread-0initialValue
    Thread-1initialValue
    Thread-0:{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9}
    Thread-2:{0=200, 1=201, 2=202, 3=203, 4=204, 5=205, 6=206, 7=207, 8=208, 9=209}
    Thread-1:{0=100, 1=101, 2=102, 3=103, 4=104, 5=105, 6=106, 7=107, 8=108, 9=109}
    

      结论:

    1) mapThreadLocal虽然是个静态变量,但是initialValue被调用了三次,通过debug发现,initialValue是从mapThreadLocal.get处发起的;

    2) ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本 ,变量是线程安全的共享对象

    3) ThreadLocal确实只有一个变量,但是它内部包含一个ThreadLocalMap,针对每个thread保留一个entry,如果对应的thread不存在则会调用initialValue;

    源码解析:

          Theadlocal 代码片段;

    /**
         * Returns the value in the current thread's copy of this
         * thread-local variable.  If the variable has no value for the
         * current thread, it is first initialized to the value returned
         * by an invocation of the {@link #initialValue} method.
         *
         * @return the current thread's value of this thread-local
         */
        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();
        }
    
    

     

    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }
    

      

     

    在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。 

    参考

     @ ThreadLocal和线程同步机制对比

  • 相关阅读:
    IOS Charles(代理服务器软件,可以用来拦截网络请求)
    Javascript中addEventListener和attachEvent的区别
    MVC中实现Area几种方法
    Entity Framework Code First 中使用 Fluent API 笔记。
    自定义JsonResult解决 序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    序列化类型 System.Data.Entity.DynamicProxies 的对象时检测到循环引用
    An entity object cannot be referenced by multiple instances of IEntityChangeTracker 的解决方案
    Code First :使用Entity. Framework编程(8) ----转发 收藏
    Code First :使用Entity. Framework编程(6) ----转发 收藏
    Code First :使用Entity. Framework编程(5) ----转发 收藏
  • 原文地址:https://www.cnblogs.com/xingzc/p/5752401.html
Copyright © 2011-2022 走看看