zoukankan      html  css  js  c++  java
  • 并发和多线程(十二)--ThreadLocal

    ThreadLocal是什么?

      当使用ThreadLocal修饰变量的时候,ThreadLocal会为每个使用该变量的线程提供独立的变量副本,每个线程可以独立改变自己的副本,而不

    影响其他线程的变量副本。

      相对于synchronized和lock实现对共享资源的操作互斥而实现原子性,这是一种新的思路解决并发问题。

    原理:

    public class Thread implements Runnable {
        ThreadLocal.ThreadLocalMap threadLocals = null;
    }
    static class ThreadLocalMap {
    
            static class Entry extends WeakReference<ThreadLocal<?>> {
                Object value;
    
                Entry(ThreadLocal<?> k, Object v) {
                    super(k);
                    value = v;
                }
            }
    
            private static final int INITIAL_CAPACITY = 16;
    
            private Entry[] table;
    
            private int size = 0;
    
            private int threshold; // Default to 0
    
            private void setThreshold(int len) {
                threshold = len * 2 / 3;
            }
    
            private static int nextIndex(int i, int len) {
                return ((i + 1 < len) ? i + 1 : 0);
            }
    
            private static int prevIndex(int i, int len) {
                return ((i - 1 >= 0) ? i - 1 : len - 1);
            }
    }

    ThreadLocalMap:

      ThreadLocal的内部类,类似Hashmap结构,以ThreadLocal为key,需要隔离的数据为value的Entry键值对数组结构。

      Entry继承了WeakReferences,只要发生GC,key为null的entry就会被清理掉

    get()源码:

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);//获取当前线程的ThreadLocalMap
        if (map != null) {//如果不为空
            ThreadLocalMap.Entry e = map.getEntry(this);//取出对应位置的Entry
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;//取出当前ThreadLocal对应的value值,返回
                return result;
            }
        }
        return setInitialValue();//如果没取到,进行初始化
    }

    getMap()源码:

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;//获取线程的ThreadLocals,也就是ThreadLocal.ThreadLocalMap
    }

    setInitialValue()源码:

    private T setInitialValue() {
        T value = initialValue();//自定义初始化
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)//有对应的map,直接set
            map.set(this, value);
        else                   //否则创建新的map,保存当前线程内部
            createMap(t, value);
        return value;
    }

    set()源码:和前面一样

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    remove()源码:

    public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }
    private void remove(ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return; } } }

    应用:

      数据库连接、Session管理、用户管理

    public class UserContext {
        
        private static ThreadLocal<User> userHolder = new ThreadLocal<User>();
        
        public static void setUser(User user) {
            userHolder.set(user);
        }
        
        public static User getUser() {
            return userHolder.get();
        }
    
    }

    下面两段代码来自:https://www.cnblogs.com/dolphin0520/p/3920407.html

    public static ThreadLocal<Connection> connectionHolder = ThreadLocal.withInitial(() -> {
    Connection conn = null;
    try {
      conn = DriverManager.getConnection("", "", "");
    } catch (SQLException e) {
      e.printStackTrace();
    }
      return conn;
    });
    
    public static Connection getConnection() {
      return connectionHolder.get();
    }
    private static final ThreadLocal threadSession = new ThreadLocal();
     
    public static Session getSession() throws InfrastructureException {
        Session s = (Session) threadSession.get();
        try {
            if (s == null) {
                s = getSessionFactory().openSession();
                threadSession.set(s);
            }
        } catch (HibernateException ex) {
            throw new InfrastructureException(ex);
        }
        return s;
    }

    与Thread同步机制的比较:

      ThreadLocal:用于线程间的数据隔离,适用于多实例对象的访问,并且这个对象很多地方都要用到

      Synchronized:用于线程间的数据共享

    Spring中的应用:

      只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(

    如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态采用ThreadLocal进行处理,让

    它们也成为线程安全的状态,因为有状态的Bean就可以在多线程中共享了。

     

  • 相关阅读:
    asp.net笔记第一章
    数据库复习笔记
    tp5博客项目实战2
    springboot调整MybatisPlus全局的验证策略
    SpringBoot整合MybatisPlus,并实现新增、修改、删除、查看、分页
    springboot整合Apollo
    创建apollo项目,并发布配置
    Apollo部门管理
    搭建Apollo环境(Ubuntu-18.04.4)
    启动apollo时出现的问题,../demo.sh: 行 84: curl: 未找到命令
  • 原文地址:https://www.cnblogs.com/huigelaile/p/10844991.html
Copyright © 2011-2022 走看看