ThreadLocal使用分析

来源:互联网 发布:军事机构的域名是 编辑:程序博客网 时间:2024/05/22 06:57

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

  •  在对运行同一段代码的多线程程序中,用以实现同一个线程之内同一个变量的同步,避免其多个线程之间彼此的干扰。效率相对于synchronized而言,有相当的提升。
  • 本质上讲,其就是实现单一线程的私有变量

关于其实现,摘引klyuan(javaeye)上的例子,如下,很好的说明了ThreadLocal的实现方式,当然你也可以参考JDK源代码中的实现。本质上,其就是一个同步的HashMap而已,可以为线程,value为所定义的局部变量。

  1. public class ThreadLocal  
  2. {  
  3.  private Map values = Collections.synchronizedMap(new HashMap());  
  4.  public Object get()  
  5.  {  
  6.   Thread curThread = Thread.currentThread();   
  7.   Object o = values.get(curThread);   
  8.   if (o == null && !values.containsKey(curThread))  
  9.   {  
  10.    o = initialValue();  
  11.    values.put(curThread, o);   
  12.   }  
  13.   return o;   
  14.  }  
  15.   
  16.  public void set(Object newValue)  
  17.  {  
  18.   values.put(Thread.currentThread(), newValue);  
  19.  }  
  20.   
  21.  public Object initialValue()  
  22.  {  
  23.   return null;   
  24.  }  
  25. }  

应用分析,一个同事将一段代码给我,说其中关于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就可以了。每一个线程都是用于该变量的一个独立副本。

原创粉丝点击