A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

【黑马程序员济南】Spring使用ThreadLocal解决线程安全问题

一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全的“状态性对象”采用ThreadLocal进行封装,让它们也成为线程安全的“状态性对象”,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了。

一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用。在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程。
这样用户就可以根据需要,将一些非线程安全的变量以ThreadLocal存放,在同一次请求响应的调用线程中,所有对象所访问的同一ThreadLocal变量都是当前线程所绑定的。
下面的实例能够体现Spring对有状态Bean的改造思路:

  TopicDao:非线程安全
Java代码  [url=][/url]

  • public class TopicDao {  
  •    //①一个非线程安全的变量  
  •    private Connection conn;   
  •    public void addTopic(){  
  •         //②引用非线程安全变量  
  •        Statement stat = conn.createStatement();  
  •        …  
  •    }  
  • }  



由于①处的conn是成员变量,因为addTopic()方法是非线程安全的,必须在使用时创建一个新TopicDao实例(非singleton)。下面使用ThreadLocal对conn这个非线程安全的“状态”进行改造:


代码清单9-6  TopicDao:线程安全
Java代码  [url=][/url]

  • import java.sql.Connection;  
  • import java.sql.Statement;  
  • public class TopicDao {  
  •   
  •   //①使用ThreadLocal保存Connection变量  
  • private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>();
  • public static Connection getConnection(){             
  •         //②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,  
  •         //并将其保存到线程本地变量中。  
  •       if (connThreadLocal.get() == null) {  
  •             Connection conn = ConnectionManager.getConnection();  
  •             connThreadLocal.set(conn);  
  •               return conn;  
  •         }else{  
  •               //③直接返回线程本地变量  
  •             return connThreadLocal.get();  
  •         }  
  • }
  • public void addTopic() {  
  •         //④从ThreadLocal中获取线程对应的  
  •          Statement stat = getConnection().createStatement();  
  •     }  
  • }  



不同的线程在使用TopicDao时,先判断connThreadLocal.get()是否为null,如果为null,则说明当前线程还没有对应的Connection对象,这时创建一个Connection对象并添加到本地线程变量中;如果不为null,则说明当前的线程已经拥有了Connection对象,直接使用就可以了。这样,就保证了不同的线程使用线程相关的Connection,而不会使用其他线程的Connection。因此,这个TopicDao就可以做到singleton共享了。

当然,这个例子本身很粗糙,将Connection的ThreadLocal直接放在Dao只能做到本Dao的多个方法共享Connection时不发生线程安全问题,但无法和其他Dao共用同一个Connection,要做到同一事务多Dao共享同一个Connection,必须在一个共同的外部类使用ThreadLocal保存Connection。但这个实例基本上说明了Spring对有状态类线程安全化的解决思路。在本章后面的内容中,我们将详细说明Spring如何通过ThreadLocal解决事务管理的问题。




点进这个帖子的同学肯定是要奋发图强,学技术拿高薪的有志青年,这里我看你骨骼惊奇,是个绝世的练武奇才,你我有缘,今天我就把这个武林秘籍如来神掌传授于你! 什么?不想学如来神掌?不要紧!这里有各个门派的武林绝学,链接拿好!!哈哈哈哈












2 个回复

正序浏览
棒棒哒 ............
回复 使用道具 举报
学习了,那么这有没有深入讲threadlocal
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马