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; } }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!