为保证在DAO层里的操作都在同一事务里,我们曾使用以参数的形式将Connection向下传递的方式,而ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接)。那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里?

是什么:

对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。

解决什么问题:

ThreadLocal是解决线程安全问题一个很好的思路,ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本,由于Key值不可重复,每一个“线程对象”对应线程的“变量副本”,而到达了线程安全。

通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问题提供了一种隔离机制。

使用ThreadLocal可以使对象达到线程隔离的目的。同一个ThreadLocal操作不同的Thread,实质是各个Thread对自己的变量操作。

ThreadLocal与其它同步机制的比较:

相同点:

ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突。

不同点:

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序慎密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。

举例说明:

对于教师判分来说,每个教师登陆后会从答题记录表中抽取20道学生的答案进行阅卷,为了避免同一道题被多个教师抽到,需要加锁进行控制,保证当时只有一个教师在抽题,其他教师只能等待,只有当这名教师抽题完成,等待的教师才可以进行抽题。同步机制就是为了同步多个线程对相同资源的并发访问,解决了多个线程之间进行通信的问题。

ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。最明显的,ThreadLoacl变量的活动范围为某线程,并且我的理解是该线程“专有的,独自霸占”,对该变量的所有操作均有该线程完成!ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal。

举例说明:

我们现在软件经常会分层,比如MVC,类似这种横向分层,而ThreadLocal会提供一种方式,方便的在同一个线程范围内,提供一个存储空间,供我们使用,实现纵向的存储结构,便于我们在同一个线程范围内,随时取得我们在另外一个层面存放的数据。

比如:在业务逻辑层需要调用多个Dao层的方法,我们要保证事务(jdbc事务)就要确保他们使用的是同一个数据库连接.那么如何确保使用同一个数据库连接呢?

第一种方案,从业务层创建数据库连接,然后一直将连接以参数形式传递到Dao

第二种方案,使用ThreadLocal,每一个线程拥有自己的变量副本,从业务逻辑层创建connection,然后到Dao层获取这个数据库连接

代码示例:

/**
* 使用threadLocal
*/
public class ConnectionManager { //private static ThreadLocal<Connection> connectionHolder=new ThreadLocal<Connection>();
private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();
/**
* 得到Connection
*/
public static Connection getConnection(){
//get() 返回此线程局部变量的当前线程副本中的值,如果这是线程第一次调用该方法,则创建并初始化此副本。
Connection conn=connectionHolder.get();
//如果在当前线程中没有绑定相应的connection
if(conn == null){
try {
JdbcConfig jdbcConfig = XmlConfigReader.getInstance().getJdbcConfig();
Class.forName(jdbcConfig.getDriverName());
conn = DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(), jdbcConfig.getPassword());
} 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中清除Connection
connectionHolder.remove();
}catch(SQLException e){
e.printStackTrace();
}
}
} }

 业务逻辑层:

public void addFlowCard(FlowCard flowCard) throws ApplicationException {
Connection conn=null;
try{
//取得Connection
conn=ConnectionManager.getConnection(); //开始事务
ConnectionManager.beginTransaction(conn); //生成流向单单号
String flowCardVouNo=flowCardDao.generateVouNo(); //添加流向单主信息
flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard);
//添加流向单明细信息
flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
//flowCardDao.addFlowCardDetail(flowCardVouNo, flowCard.getFlowCardDetailList());
//提交事务
ConnectionManager.commitTransaction(conn); }catch(DaoException e){
//回滚事务
ConnectionManager.rollbackTransaction(conn);
throw new ApplicationException("添加流向单失败");
}finally{
//关闭Connection并从threadLocal中清除
ConnectionManager.closeConnection();
}
}

  

总结

  当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序,使程序更加易读、简洁。

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

联系生活中的实例:员工用车

同步就是一个公司只有一辆车,员工甲使用的时候其他人只能等待,只有员工甲用完后,其他人才可以使用

ThreadLocal就是公司为每一个员工配一辆车,每个员工使用自己的车,员工之间用车互不影响,互相不受制约

ThreadLocal(线程绑定)的更多相关文章

  1. ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

  2. (未使用AOP)使用ThreadLocal对象把Connection和当前线程绑定, 从而使一个线程中只有一个能控制事务的对象

    每个连接都有自己的独立事务,会造成数据的不一致 这组操作应该要么一起操作成功,要么一起操作失败, 应该使用同一个连接,只有一个能控制事务的对象 需要使用ThreadLocal对象把Connection ...

  3. Java并发编程原理与实战二十五:ThreadLocal线程局部变量的使用和原理

    1.什么是ThreadLocal ThreadLocal顾名思义是线程局部变量.这种变量和普通的变量不同,这种变量在每个线程中通过get和set方法访问, 每个线程有自己独立的变量副本.线程局部变量不 ...

  4. Java-ThreadLocal,Java中特殊的线程绑定机制

    在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个 ...

  5. Hibernate中Session与本地线程绑定

    ------------------siwuxie095 Hibernate 中 Session 与本地线程绑定 1.Session 类似于 JDBC 的连接 Connection 2.Session ...

  6. Threadlocal线程本地变量理解

    转载:https://www.cnblogs.com/chengxiao/p/6152824.html 总结: 作用:ThreadLocal 线程本地变量,可用于分布式项目的日志追踪 用法:在切面中生 ...

  7. linux下将不同线程绑定到不同core和cpu上——pthread_setaffinity_np

    =============================================================== linux下的单进程多线程的程序,要实现每个线程平均分配到多核cpu,主 ...

  8. [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  9. Linux编程之《进程/线程绑定CPU》

    Intro----- 通常我们在编写服务器代码时,可以通过将当前进程绑定到固定的CPU核心或者线程绑定到固定的CPU核心来提高系统调度程序的效率来提高程序执行的效率,下面将完整代码贴上. /***** ...

随机推荐

  1. Oracle12c:支持通过创建identity columen来实现创建自增列

    oracle12c之前如果需要创建自增列必须要通过sequence+trigger来实现.但是oracle12c已经可以像mysql,sqlserver一样通过identity column来设置自增 ...

  2. Git Bash

    Git Bash是Git的命令行工具,可以执行Git的所有命令,但是当我们想把一个URL粘贴到Git Blash时,Ctrl+V或者右键粘贴不起作用了 方法1-使用快捷键"Insert&qu ...

  3. 项目版本与分支管理之阿里AoneFlow模式分析

    前言 在我前期的项目管理的经验中,一个项目需要维护多个产品及多个版本,这给版本与分支的管理增加了难度.前期没有重视,使得分支太多太乱,版本也没记录好,引发了很多的问题.在多种分支与版本的管理模式下,最 ...

  4. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新

    unity热更新是一个经久不衰的话题.除了最常见的lua之外,还有如JSBinding,C#等等.这里介绍一个使用ECMAScript4进行热更新的方案.它吸收了各家的优点,特色很鲜明. 项目地址: ...

  5. 百度API-------热力图

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...

  6. Java操作属性文件与国际化

    在前面讲到的java类集中的Hashtable中,有一个子类Properties,此类定义如下: public class Properties extends Hashtable<Object ...

  7. [HNOI 2001]软件开发

    Description 某软件公司正在规划一项n天的软件开发计划,根据开发计划第i天需要ni个软件开发人员,为了提高软件开发人员的效率,公司给软件人员提供了很多的服务,其中一项服务就是要为每个开发人员 ...

  8. [JSOI2015]非诚勿扰

    Description [故事背景] JYY赶上了互联网创业的大潮,为非常勿扰开发了最新的手机App实现单身 大龄青年之间的“速配”.然而随着用户数量的增长,JYY发现现有速配的算法似 乎很难满足大家 ...

  9. RAC基本原理

    RAC基本原理 什么是RAC? 多个实例跑在多个服务器上 一个数据库存放在共享的存储上,所有实例都可以访问 实例之间通过内联网络交换数据和信息 共享存储内容:数据文件.REDO.UNDO.控制文件 参 ...

  10. 软件测试人员在工作中如何运用Linux

    从事过软件测试的小伙们就会明白会使用Linux是多么重要的一件事,工作时需要用到,面试时会被问到,简历中需要写到. 对于软件测试人员来说,不需要你多么熟练使用Linux所有命令,也不需要你对Linux ...