天空

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ThreadLocal 学习

http://zhyxfancy.javaeye.com/blog/281045

ThreadLocal 学习

关于ThreadLocal的用法在进行了诸多的研究分析之后,终于有所斩获,掌握了其本质的若干用法,先总结如下:

在对运行同一段代码的多线程程序中,用以实现同一个线程之内同一个变量的同步,避免其多个线程之间彼此的干扰。效率相对于synchronized而言,有相当的提升。
本质上讲,其就是实现单一线程的私有变量
关于其实现,摘引klyuan(javaeye)上的例子,如下,很好的说明了ThreadLocal的实现方式,当然你也可以参考JDK源代码中的实现。本质上,其就是一个同步的HashMap而已,可以为线程,value为所定义的局部变量。

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

应用分析,一个同事将一段代码给我,说其中关于ThreadLocal的set(null)这行代码,如果注释掉,会出现什么情况,详细代码如下:

我们可以看到有2行关于local和local_tr的set(null)的方法如果被注释掉的情况,我们可以推测会出现什么样的情况。

/**
  *  Import Package missing for space
  **/
public class HibernateUtil {
         private static SessionFactory sf;
         private static ThreadLocal local = new ThreadLocal();
         private static ThreadLocal local_tr = new ThreadLocal();
      
       static{
             Configuration conf = new Configuration();
             conf = conf.configure("/hibernate.cfg.xml");
             sf = conf.buildSessionFactory();
        }

       public static Session getSession(){
             System.out.println("threadLocalid=="+local);
             Session session = null;
        if(local.get()==null){
             session = sf.openSession();
             System.out.println("---------session is created------------");
              local.set(session);
         }else{
            session = (Session)local.get();
       }
          return session;
      }
     
     public static void begin(){
           Session session = (Session)local.get();
          Transaction ts = null;
          if(local_tr.get()==null){
                 ts = session.beginTransaction();
                 local_tr.set(ts);
          }
        }

        public static void commit(){
            Transaction tr = (Transaction)local_tr.get();
            tr.commit();
            local_tr.set(null); // this line is removed,then what will happen?
          System.out.println("---------transaction is commited------------");
        }

       public static void rollback(){
                Transaction tr = (Transaction)local_tr.get();
                 tr.rollback();
                System.out.println("---------transaction is rollbacked------------");
         }

        public static void close(){
                Session session = (Session)local.get();
                if(session!=null){
                        session.close();
                        System.out.println("---------session is destroyed------------");
         }
             local.set(null);  // this line is removed, then what will happen?
      }
}



如果基于local(Session的局部变量)不进行set(null)的话,会出现所有的thread都基于获取同一个session的情况。

如果local_tr(Transaction的局部变量)不进行set(null)的话,对于基于同一个session的线程而言,其只可以进行一次的事务提交,后续都将无法进行,因为每次进行之前会进行局部变量的有效判断。

总结: ThreadLocal是一个有效的多线程局部变量工具,当然也是一把双刃剑,用好的话可以制敌,反之则可能祸己。要用好ThreadLocal,我们只需记住其本质:线程局部变量;其实现的本质是一个基于同步的HashMap就可以了。每一个线程都是用于该变量的一个独立副本。
posted on 2010-05-20 11:14  天空-天空  阅读(179)  评论(0)    收藏  举报