关于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就可以了。每一个线程都是用于该变量的一个独立副本。
在对运行同一段代码的多线程程序中,用以实现同一个线程之内同一个变量的同步,避免其多个线程之间彼此的干扰。效率相对于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就可以了。每一个线程都是用于该变量的一个独立副本。