• 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() 时分配的,并在后续调用中不会更改。)

     

     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;
        }
        
    }
     
     
     
  • 相关阅读:
    JavaScript学习记录总结(九)——移动添加效果
    JavaScript学习记录总结(十)——几个重要的BOM对象
    Hibernate——property的access属性
    JavaWeb学习记录(一)——response响应头之缓存设置与下载功能的实现
    使用配置方式进行ssh的整合以及管理员管理的案例(二)
    Hibernate设置派生属性(formula)
    JavaScript学习记录总结(五)——servlet将json数据写出去
    反射
    集合详解
    包装器类型
  • 原文地址:https://www.cnblogs.com/Evil-Rebe/p/5895546.html
Copyright © 2020-2023  润新知