`
hujin1979
  • 浏览: 80147 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

ThreadLocal理解和使用

阅读更多

    ThreadLocal:local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。从线程的角度看,就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明,在其它的一些语言编译器实现(如IBM XL FORTRAN)中,它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线程局部变量的代码相对比较笨拙,这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。

  

     在线程是活动的并且ThreadLocal对象是可访问的时,该线程就持有一个到该线程局部变量副本的隐含引用,当该线程运行结束后,该线程拥有的所以线程局部变量的副本都将失效,并等待垃圾收集器收集。

 

     ThreadLocal和其它同步机制相比有什么优势呢?ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal。

 

     由于ThreadLocal中可以持有任何类型的对象,所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本(1.5)将模版的引入,新的支持模版参数的ThreadLocal类将从中受益。也可以减少强制类型转换,并将一些错误检查提前到了编译期,将一定程度地简化ThreadLocal的使用。

 

    ThreadLocal的原理

   

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 的使用:

    Hibernate,iBatis中都使用了ThreadLocal管理多线程访问的部分,当然在应用中的事务也可以使用到ThreadLocal。具体代码如下:

  

public static final ThreadLocal session = new ThreadLocal(); 
  public static Session currentSession() { 
      Session s = (Session)session.get(); 
      //open a new session,if this session has none 
      if(s == null){ 
      s = sessionFactory.openSession(); 
      session.set(s); 
     } 
      return s; 
 }

 

   逐行分析:
  1. 初始化一个ThreadLocal对象,ThreadLocal有三个成员方法 get()、set()、initialvalue()。如果不初始化initialvalue,则initialvalue返回null。
  2. session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。 
  3. 如果是该线程初次访问,自然,s(数据库连接)会是null,接着创建一个Session,具体就是行6。
  4. 创建一个数据库连接实例 s 。
  5. 保存该数据库连接s到ThreadLocal中。
  6. 如果当前线程已经访问过数据库了,则从session中get()就可以获取该线程上次获取过的连接实例。

 

 

    当要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,EasyDBO中创建jdbc连接上下文就是这样做的:

   

public class JDBCContext{
 private static Logger logger = Logger.getLogger(JDBCContext.class);
 private DataSource ds;
 protected Connection connection;
 private boolean isValid = true;
 private static ThreadLocal jdbcContext;
 
 private JDBCContext(DataSource ds){
  this.ds = ds;
  createConnection();  
 }
 public static JDBCContext getJdbcContext(javax.sql.DataSource ds) {  
  if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds);
  JDBCContext context = (JDBCContext) jdbcContext.get();
  if (context == null) {
   context = new JDBCContext(ds);
  }
  return context;
 }

 private static class JDBCContextThreadLocal extends ThreadLocal {
  public javax.sql.DataSource ds;
  public JDBCContextThreadLocal(javax.sql.DataSource ds)  {
   this.ds=ds;
  }
  protected synchronized Object initialValue() {
   return new JDBCContext(ds);
  }
 }
}

 

    使用单例模式,不同的线程调用getJdbcContext()获得自己的jdbcContext,都是通过JDBCContextThreadLocal 内置子类来获得JDBCContext对象的线程局部变量,这个变量是该线程所独有的。

 

    我的项目中有使用Hibernate,使用的规范不算标准,采取了小型化获取Hibernate的回话进行一些数据库操作,之前编写了一个Hibernate的会话工具类:

   

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactory {
    private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
    private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
    private  static Configuration configuration = new Configuration();
    private static org.hibernate.SessionFactory sessionFactory;
    private static String configFile = CONFIG_FILE_LOCATION;

    static {
    	try {
	     configuration.configure(configFile);
	     sessionFactory = configuration.buildSessionFactory();
	} catch (Exception e) {
	     System.err.println("%%%% Error Creating SessionFactory %%%%");
	     e.printStackTrace();
	}
    }
    private HibernateSessionFactory() {   }
	
    public static synchronized Session getSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
		if (session == null || !session.isOpen()) {
			if (sessionFactory == null) {
				rebuildSessionFactory();
			}
			session = (sessionFactory != null) ? sessionFactory.openSession(): null;
			threadLocal.set(session);
		}

        return session;
    }

    public static void rebuildSessionFactory() {
	try {
	     configuration.configure(configFile);
	     sessionFactory = configuration.buildSessionFactory();
	} catch (Exception e) {
	     System.err.println("%%%% Error Creating SessionFactory %%%%");
	     e.printStackTrace();
	}
    }

    public static void closeSession() throws HibernateException {
        Session session = (Session) threadLocal.get();
        threadLocal.set(null);

        if (session != null) {
            session.close();
        }
    }

    public static org.hibernate.SessionFactory getSessionFactory() {
	return sessionFactory;
    }

    public static void setConfigFile(String configFile) {
		HibernateSessionFactory.configFile = configFile;
		sessionFactory = null;
   }

    public static Configuration getConfiguration() {
		return configuration;
   }


}

 

   hibernate.cfg.xml代码清单如下:

  

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
        <!--property name="show_sql">true</property-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true</property>	      		
        <property name="connection.username">root</property>
        <property name="connection.password">123456</property>        
        <property name="c3p0.min_size">1</property>
        <property name="c3p0.max_size">3</property>
        <property name="c3p0.timeout">1800</property>
        <property name="c3p0.max_statements">1</property>
        <!-- 对象与数据库表格映像文件 -->
        <mapping resource="register/User.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

 

   熟悉使用过hibernate的朋友一定可以理解上面的配置,还有不理解的可以搜索资料进行理解,希望能帮到china写代码的朋友们。

分享到:
评论

相关推荐

    理解ThreadLocal

    理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal

    JDK的ThreadLocal理解(一)使用和测试

    **标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...

    ThreadLocal应用示例及理解

    以上就是关于ThreadLocal的基本概念、使用方法、生命周期管理和实际应用示例的详细解释。了解并熟练掌握ThreadLocal可以帮助我们编写出更高效、更安全的多线程代码。在Java并发编程中,ThreadLocal是一个不可或缺的...

    java中ThreadLocal类的使用

    - **代码可读性和可维护性**:`ThreadLocal`的使用可能使代码变得复杂,不易于理解和调试,尤其是在多线程环境下的问题排查。 总结,`ThreadLocal`是Java中用于实现线程局部变量的工具,它提供了一种简单的方式在多...

    正确理解ThreadLocal.pdf

    ### 正确理解ThreadLocal:深入解析其工作原理与应用场景 #### 一、ThreadLocal的基本...因此,在使用`ThreadLocal`时,应当充分理解其工作机制,合理规划其生命周期,并适时进行资源清理,以确保系统的稳定性和性能。

    Spring事务处理-ThreadLocal的使用

    本篇文章将聚焦于Spring事务处理中ThreadLocal的使用,以及如何通过源码理解和应用这个工具。 首先,了解Spring事务管理的基本概念。在多线程环境中,事务管理是至关重要的,它负责确保一组数据库操作要么全部成功...

    ThreadLocal

    在使用ThreadLocal时,理解其工作原理和限制是非常重要的。合理的使用能够帮助我们编写出更高效、更易于维护的多线程程序,但也要避免滥用,因为它可能会引入难以察觉的并发问题和内存管理问题。

    Java中ThreadLocal的设计与使用

    理解ThreadLocal的工作原理和使用方法对于编写高效、安全的多线程程序至关重要。 ### ThreadLocal简介 ThreadLocal并非一个线程对象,而是一个线程局部变量的容器。每个线程都有自己的ThreadLocal实例,它们各自...

    ThreadLocal的几种误区

    然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将详细探讨这些常见的误解。 误区一:ThreadLocal是Java线程的一个实现 ThreadLocal并非Java线程的实现,它只是一个工具类,用于创建线程局部变量。...

    从ThreadLocal的使用到Spring的事务管理

    在IT行业中,线程安全和事务管理是两个非常重要的概念,尤其在多线程环境下的分布式系统中。本文将深入探讨ThreadLocal的使用以及...通过深入学习源码和实际应用,我们可以更好地理解其工作原理,并在实践中灵活运用。

    理解threadlocal

    ### 理解ThreadLocal #### 一、ThreadLocal简介 `ThreadLocal`是一个非常有用的类,它在Java 1.2版本中...理解`ThreadLocal`的工作原理及其使用方法,可以帮助我们在多线程编程中更加高效地处理数据和状态管理问题。

    使用ThreadLocal管理“session”数据

    在实际开发中,有些框架如Spring已经内置了对ThreadLocal的管理和清理机制,可以更方便地在多线程环境中使用session。 总结,ThreadLocal是Java中处理线程局部数据的利器,特别适用于需要线程隔离的场景,如Web...

    threadLocal

    1. 多线程:理解ThreadLocal的使用必须建立在对多线程的理解基础上,包括线程的创建、执行、同步机制等。 2. 并发编程:ThreadLocal是解决并发问题的一种策略,它提供了一种避免共享状态的方式,减少了锁的使用。 3....

    ThreadLocal的简单理解.doc

    ThreadLocal 简单理解 ThreadLocal 是 Java 中的一个类,它提供了一个简单的方式来在每个线程中存储变量,并且能够确保这些变量之间不受影响。下面是对 ThreadLocal 的简单理解。 一、背景 最近有人问我 ...

    java事务 - threadlocal

    在具体实践中,开发者需要根据业务场景合理选择事务管理方式和ThreadLocal的使用,以保证系统的性能和数据一致性。例如,在分布式服务中,可能会使用分布式事务解决方案如两阶段提交(2PC)、补偿事务(TCC)等,而...

    事务的封装和Threadlocal实例

    在Java的数据库编程中,事务(Transaction)是确保数据一致性的重要机制。...通过使用ThreadLocal,我们可以创建线程安全的变量,使得每个线程都能拥有独立的数据库连接和事务管理,避免了潜在的并发问题。

    ThreadLocal深度理解

    ThreadLocal深度理解

    ThreadLocal简单Demo

    - `ThreadLocalMap`的扩容策略和哈希冲突处理不同于标准的`HashMap`,理解其内部机制有助于避免潜在的问题。 以上就是关于`ThreadLocal`及其内部类`ThreadLocalMap`的基础知识,它们在多线程编程中起到关键作用,...

Global site tag (gtag.js) - Google Analytics