对ThreadLocal的初步理解

来源:互联网 发布:掌趣上游网络牟正文 编辑:程序博客网 时间:2024/05/14 08:53

  学习到ThreadLocal的时候,我又是高兴又是疑惑,高兴的是它给我提供一种解决多线程问题的新思路,疑惑的是仔细想想却不知道在项目中遇到的多线程问题是不是能用它来解决。

  一直以来,都觉得多线程问题,很难触摸。真得需要静下来,仔细看一些资料和思考总结。今天的博客只是初步理解了一下ThreadLocal,举例说明它在项目中的简单实用,以及它和锁的一些对比。


  前提:之前做项目时,我总有这样一个思路:如果Dao层(也就是常说的D层)操作数据库时需要某些信息,而这些信息是随着登录人的信息查询出来的。我想我登录完成后查询出来信息就必须要在一层层调用方法时作为参数带过去到Dao层。其实执行起来这几乎是不可能的。因为我已经写好的方法都要重新修改,添加参数,仅仅为了Dao层使用。那有没有更好的办法?


1.ThreadLocal的概念

ThreadLocal是线程的局部变量,功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。如果用车在公路上行驶做对比,可以看做每一辆车都有一条只属于自己的道,不会和其他的车辆发生冲突。


2.ThreadLocal的使用

 先来看一段代码:

public class ConnectionManager {private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();public static Connection getConnection(){Connection conn = connectionHolder.get();if (conn == null){try {JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbc();Class.forName(jdbcConfig.getDriverName());conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());//将Connection设置到ThreadLocalconnectionHolder.set(conn);} catch (ClassNotFoundException e) {e.printStackTrace();throw new ApplicationException("系统错误,请联系系统管理员");} catch (SQLException e) {e.printStackTrace();throw new ApplicationException("系统错误,请联系系统管理员");}}return conn;}public static void closeConnection() {Connection conn = connectionHolder.get();if (conn != null) {try {conn.close();//从ThreadLocal中清除ConnectionconnectionHolder.remove();} catch (SQLException e) {e.printStackTrace();}}}}

 我们加入事务时,以Manager层作为事务边界,保证一个完整的功能具有事务特性,要求完成这个功能块使用一个Connection,之前的做法就是Dao里面的每个方法都有一个参数来传递Connection,这样做其实很麻烦,现在看到的代码是用ThreadLocal改进过得。

 private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>(); 先实例化出一个ThreadLocal对象,在每次获取Connection时,先从ThreadLocal中去取,代码很简单:Connection conn = connectionHolder.get(); 如果没有取到的话,说明之前并没有使用过,所以创建一个Connection,然后需要connectionHolder.set(conn);  将它放入ThreadLocal中,那么该功能块中再需要使用Connection时直接从ThreadLocal中取就可以了。ThreadLocal很是神奇啊,任何参数都不用就把值拿出来。这一点比使用Map需要key来获取方便很多。


3.ThreadLocal和锁的简单对比

  ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。

  概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。

总结:

   多线程的问题,很多地方有待于学习,学习到ThreadLocal感觉到自己之前的想法真是傻的可以,还是需要解决不怕不知道,就怕不知道的问题。

   理解尚浅,请多指教。

0 0