zoukankan      html  css  js  c++  java
  • ThreadLocal的正确用法

    用法一:在关联数据类中创建private static ThreadLocal
    ThreaLocal的JDK文档中说明:ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread。如果我们希望通过某个类将状态(例如用户ID、事务ID)与线程关联起来,那么通常在这个类中定义private static类型的ThreadLocal 实例。


    例如,在下面的类中,私有静态 ThreadLocal 实例(serialNum)为调用该类的静态 SerialNum.get() 方法的每个线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用 SerialNum.get() 时分配的,并在后续调用中不会更改。)


    [java] view plaincopyprint?
    01.public class SerialNum { 
    02.    // The next serial number to be assigned  
    03.    private static int nextSerialNum = 0; 
    04. 
    05.    private static ThreadLocal serialNum = new ThreadLocal() { 
    06.        protected synchronized Object initialValue() { 
    07.            return new Integer(nextSerialNum++); 
    08.        } 
    09.    }; 
    10. 
    11.    public static int get() { 
    12.        return ((Integer) (serialNum.get())).intValue(); 
    13.    } 
    14.} 
     public class SerialNum {
         // The next serial number to be assigned
         private static int nextSerialNum = 0;

         private static ThreadLocal serialNum = new ThreadLocal() {
             protected synchronized Object initialValue() {
                 return new Integer(nextSerialNum++);
             }
         };

         public static int get() {
             return ((Integer) (serialNum.get())).intValue();
         }
     }


    【例】


     
    public class ThreadContext {
     
      private String userId;
      private Long transactionId;
     
      private static ThreadLocal threadLocal = new ThreadLocal(){
        @Override
            protected ThreadContext initialValue() {
                return new ThreadContext();
            }
     
      };
      public static ThreadContext get() {
        return threadLocal.get();
      }

      public String getUserId() {
        return userId;
      }
      public void setUserId(String userId) {
        this.userId = userId;
      }
      public Long getTransactionId() {
        return transactionId;
      }
      public void setTransactionId(Long transactionId) {
        this.transactionId = transactionId;
      }
     
    }
     

    用法二:在Util类中创建ThreadLocal
    这是上面用法的扩展,即把ThreadLocal的创建放到工具类中。

    【例】例如Hibernate的工具类:


    public class HibernateUtil {
        private static Log log = LogFactory.getLog(HibernateUtil.class);
        private static final SessionFactory sessionFactory;     //定义SessionFactory
     
        static {
            try {
                // 通过默认配置文件hibernate.cfg.xml创建SessionFactory
                sessionFactory = new Configuration().configure().buildSessionFactory();
            } catch (Throwable ex) {
                log.error("初始化SessionFactory失败!", ex);
                throw new ExceptionInInitializerError(ex);
            }
        }

        //创建线程局部变量session,用来保存Hibernate的Session
        public static final ThreadLocal session = new ThreadLocal();
     
        /**
         * 获取当前线程中的Session
         * @return Session
         * @throws HibernateException
         */
        public static Session currentSession() throws HibernateException {
            Session s = (Session) session.get();
            // 如果Session还没有打开,则新开一个Session
            if (s == null) {
                s = sessionFactory.openSession();
                session.set(s);         //将新开的Session保存到线程局部变量中
            }
            return s;
        }
     
        public static void closeSession() throws HibernateException {
            //获取线程局部变量,并强制转换为Session类型
            Session s = (Session) session.get();
            session.set(null);
            if (s != null)
                s.close();
        }
    }


     

     
    用法三:在Runnable中创建ThreadLocal
     还有一种用法是在线程类内部创建ThreadLocal,基本步骤如下:


    1、在多线程的类(如ThreadDemo类)中,创建一个ThreadLocal对象threadXxx,用来保存线程间需要隔离处理的对象xxx。
    2、在ThreadDemo类中,创建一个获取要隔离访问的数据的方法getXxx(),在方法中判断,若ThreadLocal对象为null时候,应该new()一个隔离访问类型的对象,并强制转换为要应用的类型。
    3、在ThreadDemo类的run()方法中,通过调用getXxx()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。 
     
    public class ThreadLocalTest implements Runnable{
       
        ThreadLocal<Studen> studenThreadLocal = new ThreadLocal<Studen>();

        @Override
        public void run() {
            String currentThreadName = Thread.currentThread().getName();
            System.out.println(currentThreadName + " is running...");
            Random random = new Random();
            int age = random.nextInt(100);
            System.out.println(currentThreadName + " is set age: "  + age);
            Studen studen = getStudent(); //通过这个方法,为每个线程都独立的new一个student对象,每个线程的的student对象都可以设置不同的值
            studen.setAge(age);
            System.out.println(currentThreadName + " is first get age: " + studen.getAge());
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println( currentThreadName + " is second get age: " + studen.getAge());
           
        }
       
        private Studen getStudent() {
            Studen studen = studenThreadLocal.get();
            if (null == studen) {
                studen = new Studen();
                studenThreadLocal.set(studen);
            }
            return studen;
        }

        public static void main(String[] args) {
            ThreadLocalTest t = new ThreadLocalTest();
            Thread t1 = new Thread(t,"Thread A");
            Thread t2 = new Thread(t,"Thread B");
            t1.start();
            t2.start();
        }
       
    }

    class Studen{
        int age;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
       
    }

  • 相关阅读:
    背水一战 Windows 10 (90)
    背水一战 Windows 10 (89)
    背水一战 Windows 10 (88)
    背水一战 Windows 10 (87)
    背水一战 Windows 10 (86)
    背水一战 Windows 10 (85)
    背水一战 Windows 10 (84)
    背水一战 Windows 10 (83)
    背水一战 Windows 10 (82)
    背水一战 Windows 10 (81)
  • 原文地址:https://www.cnblogs.com/wzh123/p/3740652.html
Copyright © 2011-2022 走看看