java 中ThreadLocal 的正确用法
java中ThreadLocal的正确用法
用法一:在关联数据类中创建privatestaticThreadLocalThreaLocal的JDK文档中说明:ThreadLocalinstancesaretypicallyprivatestaticfieldsinclassesthatwishtoassociatestatewithathread。如果我们希望通过某个类将状态(例如用户ID、事务ID)与线程关联起来,那么通常在这个类中定义privatestatic类型的ThreadLocal实例。
例如,在下面的类中,私有静态ThreadLocal实例(serialNum)为调用该类的静态SerialNum.get()方法的每个线程维护了一个“序列号”,该方法将返回当前线程的序列号。(线程的序列号是在第一次调用SerialNum.get()时分配的,并在后续调用中不会更改。)
publicclassSerialNum{
//Thenextserialnumbertobeassigned
privatestaticintnextSerialNum=0;
privatestaticThreadLocalserialNum=newThreadLocal(){
protectedsynchronizedObjectinitialValue(){
returnnewInteger(nextSerialNum++);
}
};
publicstaticintget(){
return((Integer)(serialNum.get())).intValue();
}
}
【例】
publicclassThreadContext{
privateStringuserId;
privateLongtransactionId;
privatestaticThreadLocalthreadLocal=newThreadLocal(){
@Override
protectedThreadContextinitialValue(){
returnnewThreadContext();
}
};
publicstaticThreadContextget(){
returnthreadLocal.get();
}
publicStringgetUserId(){
returnuserId;
}
publicvoidsetUserId(StringuserId){
this.userId=userId;
}
publicLonggetTransactionId(){
returntransactionId;
}
publicvoidsetTransactionId(LongtransactionId){
this.transactionId=transactionId;
}
}
用法二:在Util类中创建ThreadLocal
这是上面用法的扩展,即把ThreadLocal的创建放到工具类中。
【例】例如hibernate的工具类:
publicclassHibernateUtil{
privatestaticLoglog=LogFactory.getLog(HibernateUtil.class);
privatestaticfinalSessionFactorysessionFactory;//定义SessionFactory
static{
try{
//通过默认配置文件hibernate.cfg.xml创建SessionFactory
sessionFactory=newConfiguration().configure().buildSessionFactory();
}catch(Throwableex){
log.error("初始化SessionFactory失败!",ex);
thrownewExceptionInInitializerError(ex);
}
}
//创建线程局部变量session,用来保存Hibernate的Session
publicstaticfinalThreadLocalsession=newThreadLocal();
/**
*获取当前线程中的Session
*@returnSession
*@throwsHibernateException
*/
publicstaticSessioncurrentSession()throwsHibernateException{
Sessions=(Session)session.get();
//如果Session还没有打开,则新开一个Session
if(s==null){
s=sessionFactory.openSession();
session.set(s);//将新开的Session保存到线程局部变量中
}
returns;
}
publicstaticvoidcloseSession()throwsHibernateException{
//获取线程局部变量,并强制转换为Session类型
Sessions=(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()方法获取要操作的数据,这样可以保证每个线程对应一个数据对象,在任何时刻都操作的是这个对象。
publicclassThreadLocalTestimplementsRunnable{
ThreadLocalstudenThreadLocal=newThreadLocal();
@Override
publicvoidrun(){
StringcurrentThreadName=Thread.currentThread().getName();
System.out.println(currentThreadName+"isrunning...");
Randomrandom=newRandom();
intage=random.nextInt(100);
System.out.println(currentThreadName+"issetage:"+age);
Studenstuden=getStudent();//通过这个方法,为每个线程都独立的new一个student对象,每个线程的的student对象都可以设置不同的值
studen.setAge(age);
System.out.println(currentThreadName+"isfirstgetage:"+studen.getAge());
try{
Thread.sleep(500);
}catch(InterruptedExceptione){
e.printStackTrace();
}
System.out.println(currentThreadName+"issecondgetage:"+studen.getAge());
}
privateStudengetStudent(){
Studenstuden=studenThreadLocal.get();
if(null==studen){
studen=newStuden();
studenThreadLocal.set(studen);
}
returnstuden;
}
publicstaticvoidmain(String[]args){
ThreadLocalTestt=newThreadLocalTest();
Threadt1=newThread(t,"ThreadA");
Threadt2=newThread(t,"ThreadB");
t1.start();
t2.start();
}
}
classStuden{
intage;
publicintgetAge(){
returnage;
}
publicvoidsetAge(intage){
this.age=age;
}
}
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!