zoukankan      html  css  js  c++  java
  • Spring使用ThreadLocal解决线程安全问题

    http://www.iteye.com/topic/1123824



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

    一般的Web应用划分为展现层、服务层和持久层三个层次,在不同的层中编写对应的逻辑,下层通过接口向上层开放功能调用。在一般情况下,从接收请求到返回响应所经过的所有程序调用都同属于一个线程。

    这样用户就可以根据需要,将一些非线程安全的变量以ThreadLocal存放,在同一次请求响应的调用线程中,所有对象所访问的同一ThreadLocal变量都是当前线程所绑定的。 
    下面的实例能够体现Spring对有状态Bean的改造思路: 

    代码清单9-5  TopicDao:非线程安全 

    Java代码  收藏代码
    1. public class TopicDao {  
    2.    //①一个非线程安全的变量  
    3.    private Connection conn;   
    4.    public void addTopic(){  
    5.         //②引用非线程安全变量  
    6.        Statement stat = conn.createStatement();  
    7.        …  
    8.    }  
    9. }  



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


    代码清单9-6  TopicDao:线程安全 

    Java代码  收藏代码
    1. import java.sql.Connection;  
    2. import java.sql.Statement;  
    3. public class TopicDao {  
    4.   
    5.   //①使用ThreadLocal保存Connection变量  
    6. private static ThreadLocal<Connection> connThreadLocal = new ThreadLocal<Connection>(); 
    7.  
    8. public static Connection getConnection(){             
    9.         //②如果connThreadLocal没有本线程对应的Connection创建一个新的Connection,  
    10.         //并将其保存到线程本地变量中。  
    11.       if (connThreadLocal.get() == null) {  
    12.             Connection conn = ConnectionManager.getConnection();  
    13.             connThreadLocal.set(conn);  
    14.               return conn;  
    15.         }else{  
    16.               //③直接返回线程本地变量  
    17.             return connThreadLocal.get();  
    18.         }  
    19.  
    20.  public void addTopic() {  
    21.         //④从ThreadLocal中获取线程对应的  
    22.          Statement stat = getConnection().createStatement();  
    23.     }  
    24. }  



    不同的线程在使用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解决事务管理的问题。 

    这些文章摘自于我的《Spring 3.x企业应用开发实战》,我将通过连载的方式,陆续在此发出。欢迎大家讨论。 


  • 相关阅读:
    sql面试题
    C#基础(1)
    Java中的冒泡排序(减少比较次数)
    Java中面向对象的分拣存储
    Java中分拣存储的demo
    XML序列化
    C#读取csv文件使用字符串拼接成XML
    Java中HashMap(泛型嵌套)的遍历
    Java 中List 集合索引遍历与迭代器遍历
    java 中的try catch在文件相关操作的使用
  • 原文地址:https://www.cnblogs.com/leeeee/p/7276222.html
Copyright © 2011-2022 走看看