之漫谈使用ThreadLocal改进你的层次的划分.docx

上传人:牧羊曲112 文档编号:1878034 上传时间:2022-12-23 格式:DOCX 页数:28 大小:307.42KB
返回 下载 相关 举报
之漫谈使用ThreadLocal改进你的层次的划分.docx_第1页
第1页 / 共28页
之漫谈使用ThreadLocal改进你的层次的划分.docx_第2页
第2页 / 共28页
之漫谈使用ThreadLocal改进你的层次的划分.docx_第3页
第3页 / 共28页
之漫谈使用ThreadLocal改进你的层次的划分.docx_第4页
第4页 / 共28页
之漫谈使用ThreadLocal改进你的层次的划分.docx_第5页
第5页 / 共28页
点击查看更多>>
资源描述

《之漫谈使用ThreadLocal改进你的层次的划分.docx》由会员分享,可在线阅读,更多相关《之漫谈使用ThreadLocal改进你的层次的划分.docx(28页珍藏版)》请在三一办公上搜索。

1、一、什么是ThreadLocal早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序。ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而

2、不会影响其它线程所对应的副本。从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。线程局部变量并不是Java的新发明,很多语言(如IBM IBM XL FORTRAN)在语法层面就提供线程局部变量。在Java中没有提供在语言级支持,而是变相地通过ThreadLocal的类提供支持。所以,在Java中编写线程局部变量的代码相对来说要笨拙一些,因此造成线程局部变量没有在Java开发者中得到很好的普及。ThreadLocal的接口方法ThreadLocal类接口很简单,只有4个方法,我们先来了解一下:void set(Object value)设置当前线程的线程局

3、部变量的值。public Object get()该方法返回当前线程所对应的线程局部变量。public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。protected ObjectinitialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)

4、时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。值得一提的是,在JDK5.0中,ThreadLocal已经支持泛型,该类的类名已经变为ThreadLocal。API方法也相应进行了调整,新版本的API方法分别是void set(T value)、T get()以及T initialValue()。一、来看一个实际案例2.1同一Service方法中调用多个Dao方法可以看到,我们有一个Service方法,在该Service方法中调用多个Dao方法,所有在该Service方法中的的Dao都处于同一事务中。该Service方法结束后,提交事务;该Service方法中

5、有任何错,回滚事务;2.2传统的做法来看下面这段伪代码Service层代码:public void serviceMethod()Connection conn=null;tryConnection conn=getConnection();conn.setAutoCommit(false);Dao1 dao1=new Dao1(conn);dao1.doSomething();Dao2 dao2=new Dao2(conn);dao2.doSomething();Dao3 dao3=new Dao3(conn);dao3.doSomething(); mit();catch(Exceptio

6、n e) try conn.rollback();catch(Exception ex)finallytryconn.setAutoCommit(true);catch(Exception e) try if(conn!=null) conn.close(); conn=null;catch(Exception e)每个Dao层的代码:Class Dao1private Connection conn=null;public Dao1(Connection conn) this.conn=conn;public void doSomething() PreparedStatement pstm

7、t=null; try pstmt=conn.preparedStatement(sql); pstmt.execute catch(Exception e) log.error(e,”Exeception occurred in Dao1.doSomething():”+e.getMessage,e);finally try if(pstmt!=null) pstmt.close(); pstmt=null; catch(Exception e)如果我一个Service方法有调用一堆dao方法,先不说这样写首先破坏了OOP的封装性原则,如果有一个dao多关了一个conn,那就会导致其它的da

8、o得到的conn为null,这种事在这样的写法下由其当你还有业务逻辑混合在一起时很容易发生。笔者曾经遇见过2个项目,出现out of memory或者是connection pool has been leakage,经查代码就是在每个dao中多关或者在service层中漏关,或者是每个dao有自己的conntionconn=getConnection(),然后还跑到Service层里去关这个connection(那关什么,关个P关!)。当然,如果你说你在写法上绝对promise绝对注意这样的问题不会发生,但是我们来看看下面的这种做法,是否会比上面这个写法更好呢?2.3 Spring中的做法先

9、来看Spring中的写法。大家应该都很熟悉Spring中的写法了,来看一下它是怎么解决的。Service层public void serviceMethod()try /aop 自动加入connection,并且将conn.setAutoCommit(false);dao1.doSomething();dao2.doSomething();dao3.doSomething();catch(Exception e) /aop 自动加入rollbackfinally /aop自动加入conn.setAutoCommit(true) /aop 自动加入conn.close();这边我们不讲AOP,因

10、为用类反射结合xml很容易将aop 自动。这些东西加入我们的代码中去是不是?我们只管写dao方法,service方法,不需要关心在哪边commit哪边rollback何时connection,spring的声明式事务会帮我们负责,这种风格我们称为“优雅”,各层间耦合度极大程度上的降低,封装性好。因此,我们可以总结出下面这些好处: Service层的方法只管开启事务(如果讲究点的还会设一个Transaction); 在该Service层中的所有dao使用该service方法中开启的事务(即connection); Dao中每次只管getCurrentConnection(获取当前的connect

11、ion),与进行数据处理 Dao层中如果发生错误就抛回Service层 Service层中接到exception,在catch中rollback,在try未尾commit,在finally块中关闭整个connection。这。就是我们所说的ThreadLocal。举个更实际的例子再次来说明ThreadLocal:我们有3个用户访问同一个service方法,该service方法内有3个dao方法为一个完整事务,那么整个web容器内只因该有3个connection,并且每个connection之间的状态,彼此“隔离”。我们下面一起来看我们如何用代码实现类似于Spring的这种做法。首先,根据我们的

12、ThreadLocal的概念,我们先声明一个ConnectionManager的类。2.4利用ThreadLocal制作ConnectionManagerpublic class ConnectionManager private static ThreadLocal tl = new ThreadLocal(); private static Connection conn = null; public static void BeginTrans(boolean beginTrans) throws Exception if (tl.get() = null | (Connection)

13、tl.get().isClosed() conn = SingletonDBConnection.getInstance().getConnection(); conn = new ConnectionSpy(conn); if (beginTrans) conn.setAutoCommit(false); tl.set(conn); public static Connection getConnection() throws Exception return (Connection) tl.get(); public static void close() throws SQLExcept

14、ion try (Connection) tl.get().setAutoCommit(true); catch (Exception e) (Connection) tl.get().close(); tl.set(null); public static void commit() throws SQLException try (Connection) tl.get().commit(); catch (Exception e) try (Connection) tl.get().setAutoCommit(true); catch (Exception e) public static

15、 void rollback() throws SQLException try (Connection) tl.get().rollback(); catch (Exception e) try (Connection) tl.get().setAutoCommit(true); catch (Exception e) 2.5利用ThreadLocal改造Service与Dao层Service层(注意红色标粗-好粗yeah,的地方)package sky.org.service.impl;public class StudentServiceImpl implements StudentSe

16、rvice public void addStudent(Student std) throws Exception StudentDAO studentDAO = new StudentDAOImpl(); ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl(); try ConnectionManager.BeginTrans(true);studentDAO.addStudent(std);classRoomDAO.addStudentClassRoom(std.getClassRoomId(), std.getsNo();Connectio

17、nMmit(); catch (Exception e) try ConnectionManager.rollback(); catch (Exception de) throw new Exception(e); finally try ConnectionManager.close(); catch (Exception e) Look,如果我把上述标粗(没有加红色)的地方,全部用AOP的方式从这块代码的外部“切”进去。是不是一个Spring里的Service方法就诞生了?下面来看一个完整的例子2.6使用ThreadLocal分离Service、DAO层先来看表结构:T_Student表T

18、_ClassRoom表T_Student_ClassRoom表需求:很简单,T_ClassRoom表里已经有值了,在插入T_Student表的数据时同时要给这个学生分配一个班级并且插入T_Student_ClassRoom表,这就是一个事务,这两步中有任何一步出错,事务必须回滚。看来工程的结构吧:下面开始放出所有源代码:2.6.1 ConnectionManager类package sky.org.util.db;import java.sql.*;public class ConnectionManager private static ThreadLocal tl = new Thread

19、Local(); private static Connection conn = null; public static void BeginTrans(boolean beginTrans) throws Exception if (tl.get() = null | (Connection) tl.get().isClosed() conn = DBConnection.getInstance().getConnection(); conn = new ConnectionSpy(conn); if (beginTrans) conn.setAutoCommit(false); tl.s

20、et(conn); public static Connection getConnection() throws Exception return (Connection) tl.get(); public static void close() throws SQLException try (Connection) tl.get().setAutoCommit(true); catch (Exception e) (Connection) tl.get().close(); tl.set(null); public static void commit() throws SQLExcep

21、tion try (Connection) tl.get().commit(); catch (Exception e) try (Connection) tl.get().setAutoCommit(true); catch (Exception e) public static void rollback() throws SQLException try (Connection) tl.get().rollback(); catch (Exception e) try (Connection) tl.get().setAutoCommit(true); catch (Exception

22、e) 2.6.2 DBConnection类package sky.org.util.db;public class DBConnection private static DBConnection instance = null; private static String driverClassName = null; private static String connectionUrl = null; private static String userName = null; private static String password = null; private static

23、Connection conn = null; private static Properties jdbcProp = null; private DBConnection() private static Properties getConfigFromPropertiesFile() throws Exception Properties prop = null; prop = JdbcProperties.getPropObjFromFile(); return prop; private static void initJdbcParameters(Properties prop)

24、driverClassName = prop.getProperty(Constants.DRIVER_CLASS_NAME); connectionUrl = prop.getProperty(Constants.CONNECTION_URL); userName = prop.getProperty(Constants.DB_USER_NAME); password = prop.getProperty(Constants.DB_USER_PASSWORD); private static void createConnection() throws Exception Class.for

25、Name(driverClassName); conn = DriverManager.getConnection(connectionUrl, userName, password); public static Connection getConnection() throws Exception return conn; public synchronized static DBConnection getInstance()throws Exception if (instance = null) jdbcProp = getConfigFromPropertiesFile(); in

26、stance = new DBConnection(); initJdbcParameters(jdbcProp); createConnection(); return instance; 2.6.3 JdbcProperties类package sky.org.util.db;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStream;import .URL;impor

27、t java.util.*;public class JdbcProperties private static Log logger = LogFactory.getLog(JdbcProperties.class); public static Properties getPropObjFromFile() Properties objProp = new Properties(); ClassLoader classLoader = Thread.currentThread() .getContextClassLoader(); URL url = classLoader.getReso

28、urce(Constants.JDBC_PROPERTIES_FILE); if (url = null) classLoader = ClassLoader.getSystemClassLoader(); url = classLoader.getResource(Constants.JDBC_PROPERTIES_FILE); File file = new File(url.getFile(); InputStream inStream = null; try inStream = new FileInputStream(file); objProp.load(inStream); ca

29、tch (FileNotFoundException e) objProp = null; e.printStackTrace(); catch (IOException e) e.printStackTrace(); finally try if (inStream != null) inStream.close(); inStream = null; catch (Exception e) return objProp; 2.6.4 Resource目录下的jdbc.propertiesjdbc.driverClassName=com.mysql.jdbc.Driverjdbc.datab

30、aseURL=jdbc:mysql:/localhost:3306/mydb?useUnicode=true&characterEncoding=utf8jdbc.username=mysqljdbc.password=password_12.6.5 StudentService接口package sky.org.service;import java.util.List;import java.util.Vector;import sky.org.bean.*;public interface StudentService public void addStudent(Student std

31、) throws Exception;2.6.6 StudentServiceImpl类package sky.org.service.impl;import java.util.ArrayList;import java.util.List;import java.util.Vector;import sky.org.util.db.ConnectionManager;import sky.org.util.*;import sky.org.bean.*;import sky.org.dao.*;import sky.org.dao.impl.*;import sky.org.service

32、.*;public class StudentServiceImpl implements StudentService public void addStudent(Student std) throws Exception StudentDAO studentDAO = new StudentDAOImpl(); ClassRoomDAO classRoomDAO = new ClassRoomDAOImpl(); try ConnectionManager.BeginTrans(true); studentDAO.addStudent(std); classRoomDAO .addStudentClassRoom(std.getClassRoomId(), std.getsNo(); ConnectionMmit(); catch (Exception e) try ConnectionManager.rollback(); catch (Exception de) throw new Exception(e); finally try ConnectionManager.close(); catch (Exception e) 2.6.7 ClassRoomDAO接口package sky.org.dao

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号