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 plain  copy
 print ?
  1. public class SerialNum {  
  2.     // The next serial number to be assigned  
  3.     private static int nextSerialNum = 0;  
  4.   
  5.     private static ThreadLocal serialNum = new ThreadLocal() {  
  6.         protected synchronized Object initialValue() {  
  7.             return new Integer(nextSerialNum++);  
  8.         }  
  9.     };  
  10.   
  11.     public static int get() {  
  12.         return ((Integer) (serialNum.get())).intValue();  
  13.     }  
  14. }  



【例】

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

用法一:在关联数据类中创建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 plain  copy
 print ?
  1. public class SerialNum {  
  2.     // The next serial number to be assigned  
  3.     private static int nextSerialNum = 0;  
  4.   
  5.     private static ThreadLocal serialNum = new ThreadLocal() {  
  6.         protected synchronized Object initialValue() {  
  7.             return new Integer(nextSerialNum++);  
  8.         }  
  9.     };  
  10.   
  11.     public static int get() {  
  12.         return ((Integer) (serialNum.get())).intValue();  
  13.     }  
  14. }  



【例】

 
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;
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值