美文网首页
ThreadLocal简介

ThreadLocal简介

作者: 枯木风 | 来源:发表于2018-11-30 10:34 被阅读0次

    ThreadLocal用法

    Java中线程的同步机制保证了多线程访问共享变量的安全性,通常我们使用synchronized关键字来实现。在多个线程对共享变量进行读写操作时,同步锁保证了同一时间只有一个线程对共享变量进行操作,概括地说,这是一种“以时间换空间”的解决策略。

    在JDK1.2中引入了ThreadLocal类来提供了一种“以空间换时间”的同步解决策略。ThreadLocal内部维护了一份类似Map的静态变量ThreadLocalMap,其中key为当前线程,value为共享变量。JDK1.5引入泛型,ThreadLocal也同时支持泛型。

    其具体实现如下

    public class ThreadLocal<T> {
      /**
       * ThreadLocals rely on per-thread hash maps attached to each thread
       * (Thread.threadLocals and inheritableThreadLocals).  The ThreadLocal
       * objects act as keys, searched via threadLocalHashCode.  This is a
       * custom hash code (useful only within ThreadLocalMaps) that eliminates
       * collisions in the common case where consecutively constructed
       * ThreadLocals are used by the same threads, while remaining well-behaved
       * in less common cases.
       */
      private final int threadLocalHashCode = nextHashCode();
    
      /**
       * The next hash code to be given out. Accessed only by like-named method.
       */
      private static int nextHashCode = 0;
    
      /**
       * The difference between successively generated hash codes - turns
       * implicit sequential thread-local IDs into near-optimally spread
       * multiplicative hash values for power-of-two-sized tables.
       */
      private static final int HASH_INCREMENT = 0x61c88647;
    
      /**
       * Compute the next hash code. The static synchronization used here
       * should not be a performance bottleneck. When ThreadLocals are
       * generated in different threads at a fast enough rate to regularly
       * contend on this lock, memory contention is by far a more serious
       * problem than lock contention.
       */
      private static synchronized int nextHashCode() {
          int h = nextHashCode;
          nextHashCode = h + HASH_INCREMENT;
          return h;
      }
    
      /**
       * Creates a thread local variable.
       */
      public ThreadLocal() {
      }
    
      /**
       * Returns the value in the current thread's copy of this thread-local
       * variable.  Creates and initializes the copy if this is the first time
       * the thread has called this 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)
              return (T)map.get(this);
    
          // Maps are constructed lazily.  if the map for this thread
          // doesn't exist, create it, with this ThreadLocal and its
          // initial value as its only entry.
          T value = initialValue();
          createMap(t, value);
          return value;
      }
    
      /**
       * Sets the current thread's copy of this thread-local variable
       * to the specified value.  Many applications will have no need for
       * this functionality, relying solely on the {@link #initialValue}
       * method to set the values of thread-locals.
       *
       * @param value the value to be stored in the current threads' copy of
       *        this thread-local.
       */
      public void set(T value) {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null)
              map.set(this, value);
          else
              createMap(t, value);
      }
    
      /**
       * 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;
      }
    
      /**
       * Create the map associated with a ThreadLocal. Overridden in
       * InheritableThreadLocal.
       *
       * @param t the current thread
       * @param firstValue value for the initial entry of the map
       * @param map the map to store.
       */
      void createMap(Thread t, T firstValue) {
          t.threadLocals = new ThreadLocalMap(this, firstValue);
      }
    
      .......
    
      /**
       * ThreadLocalMap is a customized hash map suitable only for
       * maintaining thread local values. No operations are exported
       * outside of the ThreadLocal class. The class is package private to
       * allow declaration of fields in class Thread.  To help deal with
       * very large and long-lived usages, the hash table entries use
       * WeakReferences for keys. However, since reference queues are not
       * used, stale entries are guaranteed to be removed only when
       * the table starts running out of space.
       */
      static class ThreadLocalMap {
    
      ........
    
      }
    
    }
    

    从中很清晰的可以看出,多个线程拥有自己一份单独的ThreadLocalMap,共享变量对于每个线程都是单独的一份,因此不会造成线程的安全问题。

    JDBC的ConnectionManager类就是以这种方式来实现数据库连接Connection对象线程隔离。

    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class ConnectionManager {
    
        private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() {
            @Override
            protected Connection initialValue() {
                Connection conn = null;
                try {
                    conn = DriverManager.getConnection(
                            "jdbc:mysql://localhost:3306/test", "username",
                            "password");
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                return conn;
            }
        };
    
        public static Connection getConnection() {
            return connectionHolder.get();
        }
    
        public static void setConnection(Connection conn) {
            connectionHolder.set(conn);
        }
    }  
    

    但是,有些情况ThreadLocal可能并不适用,例如存储大量数据的共享变量,或共享变量只能被创建一次时,就只能通过synchronized来实现了。

    推荐阅读https://my.oschina.net/lichhao/blog/111362

    相关文章

      网友评论

          本文标题:ThreadLocal简介

          本文链接:https://www.haomeiwen.com/subject/damccqtx.html