zoukankan      html  css  js  c++  java
  • java-ThreadLocal常见的几种实现方式和实例

    简单介绍一下ThreadLocal的原理
    1.ThreadLocal会为每一个线程维护一个和该线程绑定的实例变量的副本
    2.因为每一个线程都拥有自己独立的实例变量副本,而不会和其它线程的副本冲突

    ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:

    void set(Object value)设置当前线程的线程局部变量的值。

    public Object get()该方法返回当前线程所对应的线程局部变量。

    public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。

    protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。


    • 法一. 在用户类中定义一个ThreadLocal实例属性(通常是静态实例)把ThreadLocal就当做一个map操作,该set就set(加入Thread.currentThread为key),该get就get(加入Thread.currentThread为key)
    例1: 下面是hibernate文档里提供的辅助类HibernateUtil
    ThreadLocal 模式管理hibernate Session
    每个线程都能获得一个session的副本

    public class HibernateUtil {

        public static final ThreadLocal session =new ThreadLocal();

        public static final SessionFactory sessionFactory;

       static {
          try {
            sessionFactory = new Configuration().configure().buildSessionFactory();
          } catch (Throwable ex) {
               throw new ExceptionInInitializerError(ex);
            
            }
        
         public static Session currentSession () throws HibernateException {
            Session s = session.get ();
            if(s == null) {
              s = sessionFactory.openSession ();
              session.set(s);
               }
             return s;
           }
           
        public static void closeSession() throws HibernateException {
               Session s = session.get ();
            if(s != null) {
                s.close();
            }
            session.set(null);
        }
    }
    例2: HibernateSessionFactory 中 getSession()的实现 .
    另一种和上面辅助类HibernateUtil类似的HibernateSessionFactory ,是MyEclipse自动生成的

    public class HibernateSessionFactory {

      public static final ThreadLocal threadLocal =new ThreadLocal();
     
      public static Session getSession() throws HibernateException ...{
            Session session = (Session) threadLocal.get();

            if (session == null || !session.isOpen()) ...{
                if (sessionFactory == null) ...{
                    rebuildSessionFactory();
                }
                session = (sessionFactory != null) ? sessionFactory.openSession()
                        : null;
                threadLocal.set(session);
            }

            return session;
         
    例3:struts2 中 请求的 Dispatcher对象
    struts2 中 Dispatcher对象是核心功能对象
    Dispatcher对象接受了参数FilterDispatcher过滤器的FilterConfig传来的ServletContext,这样才接管了基本Servlet的一切功能
    FilterDispatcher过滤器的doFilter()方法,调用了Dispatcher对象的serviceAction()方法,并把HttpServletRequest对象和HttpServletResponse对象传入, 这个serviceAction()方法,就是整个Strtus2的主引擎

    struts2对每个request请求分配一个线程,为每个线程安排一个ThreadLocal模式的Dispatcher对象

    public class Dispatcher {

     private static ThreadLocal instance = new ThreadLocal();

     //Store the dispatcher instance for this thread.
      public static void setInstance(Dispatcher instance) {
     
         Dispatcher.instance.set(instance);

         // Tie the ObjectFactory threadlocal instance to this Dispatcher instance
                  if (instance != null) {
             Container cont = instance.getContainer();
                      if (cont != null) {
                 ObjectFactory.setObjectFactory(cont.getInstance(ObjectFactory.class));
                       } else {
                 LOG.warn("This dispatcher instance doesn't have a container, so the object factory won't be set.");
                       }
                } else {
             ObjectFactory.setObjectFactory(null);
             }
     }

     //Provide the dispatcher instance for the current thread.
       public static Dispatcher getInstance() {
         return instance.get();
     }

    private ServletContext servletContext;
    private Map initParams;

     public  Dispatcher(ServletContext servletContext, Map initParams) {
         this.servletContext = servletContext;
         this.initParams = initParams;
     }
    例4:Struts2的请求的ActionContext对象
    Struts2的ActionContext对象,是为了弥补strtus2 action跳出标准servlet框架而造成的和WEB环境失去联系的缺陷
    struts2对每个request请求分配一个线程,为每个线程安排一个ThreadLocal模式的ActionContext对象

     public class ActionContext implements Serializable {

         static ThreadLocal actionContext = new ThreadLocal();
        
         //Sets the action context for the current thread.
         public static void setContext(ActionContext context) {
             actionContext.set(context);
         }
         //Returns the ActionContext specific to the current thread.
         public static ActionContext getContext() {
             return (ActionContext) actionContext.get();
         }


    • 法二.用户类继承标准ThreadLocal类,覆写initialValue(),增加初始化实例语句
    public class ThreadLocal
    {
     private Map values = Collections.synchronizedMap(new HashMap());
                                  
     public Object get()
     {
      Thread curThread = Thread.currentThread();
      Object o = values.get(curThread);

      if (o == null && !values.containsKey(curThread))
      {
       o = initialValue();
       values.put(curThread, o);
      }
      
            return o;
     }

     public void set(Object newValue)
     {
      values.put(Thread.currentThread(), newValue);
     }

     public Object initialValue()
     {
      return null;
     }
    }
     
    public class Test1 extends ThreadLocal{
        @Override
      public Object initialValue()
      {
          //return null;
       return 你要保存副本的实例变量;
      }

    //get(),set()都不必覆写,因为标准ThreadLocal下都是Object类型.
    }


    • 法三. 在类内建匿名类或内部类,实际是法一和法二的结合

    例1:设一个匿名类
    SerialNum类,为每一个类分配一个序号:
    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();
     }
    }

    SerialNum类的使用非常简单:
    int t1 = SerialNum.get(); 即可。
    例2:设一个内部类
    public class ConnectionDispenser {
           
            private static class ThreadLocalConnection extends ThreadLocal {
               public Object initialValue() {
                      return DriverManager.getConnection(ConfigurationSingleton.getDbUrl());
               }
       }
      
        private ThreadLocalConnection conn = new ThreadLocalConnection();
       
        public static Connection getConnection() {
                return (Connection) conn.get();
       }
    }
  • 相关阅读:
    Annotation
    injector
    Java容器(container)
    build tool(构建工具)maven和gradle安装方法
    version control(版本控制)
    函数式编程
    URI与URL
    超文本传输协议HTTP
    annotation的理解
    Injection
  • 原文地址:https://www.cnblogs.com/luckForever/p/7254131.html
Copyright © 2011-2022 走看看