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;
        }
       
    }

  • 相关阅读:
    【C#】往异步下载的方法传递自定义完成事件
    【WPF】CommandParameter解决多传参问题
    【WPF/C#】使用BackgroundWorker实现多线程/异步操作
    【WPF】弹窗定位、弹窗关闭后再打开的报错
    【WPF/C#】测试下载文件(图片)
    【Unity】初始化物体的旋转角度
    【Unity/C#】DateTime时间字符串,月份用英文显示
    【转】【Unity】DateTime各种时间字符串
    【Unity】UGUI无法修改字体大小
    intellij idea运行Android程序时报错;Unable to locate adb within SDK
  • 原文地址:https://www.cnblogs.com/wzh123/p/3740652.html
Copyright © 2011-2022 走看看