Why ThreadLocal?

无论如何,要编写一个多线程安全(Thread-safe)的程序是困难的,为了让线程共享资源,必须小心地对共享资源进行同步,同步带来一定的效能延迟,而另一方面,在处理同步的时候,又要注意对象的锁定与释放,避免产生死结,种种因素都使得编写多线程程序变得困难。

尝试从另一个角度来思考多线程共享资源的问题,既然共享资源这么困难,那么就干脆不要共享,何不为每个线程创造一个资源的复本。将每一个线程存取数据的行为加以隔离,实现的方法就是给予每个线程一个特定空间来保管该线程所独享的资源

 

什么是ThreadLocal?

顾名思义它是local variable(线程局部变量)。它的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。

使用场景

  1. To keep state with a thread (user-id, transaction-id, logging-id)
  2. To cache objects which you need frequently

ThreadLocal类  实现线程范围的共享变量

它主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null:

ThreadLocal的原理

ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现:

public class ThreadLocal
{
  private Map values = Collections.synchronizedMap(new HashMap());
  public Object get()
  {
    Thread curThread = Thread.currentThread();
    Object o = values.get(curThread);
    if (o == null && !values.containsKey(curThread))
    {
       o = initialValue();
       values.put(curThread, o);
    }
    return o;
 }

 public void set(Object newValue)
 {
    values.put(Thread.currentThread(), newValue);
 }

 public Object initialValue()
 {
    return null;
 }
}

ThreadLocal 的使用

使用方法一:

hibernate的文档时看到了关于使ThreadLocal管理多线程访问的部分。具体代码如下

1.  public static final ThreadLocal session = new ThreadLocal();
2.  public static Session currentSession() {
3.      Session s = (Session)session.get();
4.      //open a new session,if this session has none
5.   if(s == null){
6.      s = sessionFactory.openSession();
7.      session.set(s);
8.   }
      return s;
9. }

我们逐行分析
1。 初始化一个ThreadLocal对象,ThreadLocal有三个成员方法 get()、set()、initialvalue()。
    如果不初始化initialvalue,则initialvalue返回null。
3。 session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。
5。如果是该线程初次访问,自然,s(数据库连接)会是null,接着创建一个Session,具体就是行6。
6。创建一个数据库连接实例 s
7。保存该数据库连接s到ThreadLocal中。
8。如果当前线程已经访问过数据库了,则从session中get()就可以获取该线程上次获取过的连接实例。

使用方法二

当要给线程初始化一个特殊值时,需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,EasyDBO中创建jdbc连接上下文就是这样做的:

public class JDBCContext{
 private static Logger logger = Logger.getLogger(JDBCContext.class);
 private DataSource ds;
 protected Connection connection;
 private boolean isValid = true;
 private static ThreadLocal jdbcContext;
 
 private JDBCContext(DataSource ds){
  this.ds = ds;
  createConnection();  
 }
 public static JDBCContext getJdbcContext(javax.sql.DataSource ds)
 {  
  if(jdbcContext==null)jdbcContext=new JDBCContextThreadLocal(ds);
  JDBCContext context = (JDBCContext) jdbcContext.get();
  if (context == null) {
   context = new JDBCContext(ds);
  }
  return context;
 }

private static class JDBCContextThreadLocal extends ThreadLocal {
  public javax.sql.DataSource ds;
  public JDBCContextThreadLocal(javax.sql.DataSource ds)
  {
   this.ds=ds;
  }
  protected synchronized Object initialValue() {
   return new JDBCContext(ds);
  }
 }
}

使用单例模式,不同的线程调用getJdbcContext()获得自己的jdbcContext,都是通过JDBCContextThreadLocal 内置子类来获得JDBCContext对象的线程局部变量

本文转自http://blog.csdn.net/wenzhihui_2010/article/details/8985575 感谢作者

hibernate将connection放进threadlocal里实现数据库连接池的更多相关文章

  1. 数据库连接池中是将connection放进threadlocal里的

    我有几点不太明白的,望各位大侠指教下.1.j2ee的应用中,有一个用户请求就会启动一个线程.而如果我们把connection放在Threadlocal里的话,那么我们的程序只需要一个connectio ...

  2. [原创]java WEB学习笔记80:Hibernate学习之路--- hibernate配置文件:JDBC 连接属性,C3P0 数据库连接池属性等

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

  3. 怎样把SEL放进NSArray里

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3805270.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  4. C#、winform、wpf将类控件放进工具箱里

    有时我们需要将vs自带的控件的某一些方法或属性进行一些修改,我们通常会新建一个类来继承它然后对它的方法或属性进行修改,那么我们如何将修改完成的控件类变成可视化控件放到工具箱中便于使用呢? 很简单,只要 ...

  5. java jdbc深入理解(connection与threadlocal与数据库连接池和事务实)

    1.jdbc连接数据库,就这样子 Class.forName("com.mysql.jdbc.Driver");java.sql.Connection conn = DriverM ...

  6. MPC8313ERDB不新鲜pkg包裹,把文件放进Ramdisk

    MPC8313ERDB不新鲜pkg包裹,把文件放进Ramdisk 经ltib编译器生成rootfs.ext2.gz.uboot它可以直接uboot采用.假设我们编写了相应的外部文件把Ramdisk往里 ...

  7. Win7里面如何把这一堆图标放进那个右下角的小三角框框

    Win7里面如何把这一堆图标放进那个右下角的小三角框框.. Win7里面如何把这一堆图标放进那个小框框:1.在任务栏空白处右击,点击属性:2.在属性中的通知区域-->点击自定义按钮:3.去除勾选 ...

  8. 零元学Expression Blend 4 - Chapter 31 看如何简单的把SampleData 绑进ListBox里

    原文:零元学Expression Blend 4 - Chapter 31 看如何简单的把SampleData 绑进ListBox里 前面几章连续讲到ListBox的运用,本章要讲得是如何简单的把Sa ...

  9. Linux 下EXT2文件系统 —— 如何将蚂蚁和大象优雅的装进冰箱里

    这一阵子真是偷懒,无时无刻不和自己身体中的懒癌做斗争.最终我还是被打败了,星期天两天几乎都是荒废过去的,在空闲的时候实际上我内心也是有点焦虑的,不知道去怎么度过这时间.学习吧又不想学习,看电视娱乐吧也 ...

随机推荐

  1. 杂乱的code

    /*o(n)的堆化方法*/ void myjust(vector<int>& A,int i){ int l=i*2+1; int r=i*2+2; int minn=i; if( ...

  2. inux命令英文缩写的含义(方便记忆) 2

    linux常用命令的英文单词缩写 命令缩写: ls:list(列出目录内容) cd:Change Directory(改变目录) su:switch user 切换用户rpm:redhat packa ...

  3. NTP详解-转

    网管实战:Linux时间服务器配置 [IT168 专稿]目前计算机网络中各主机和服务器等网络设备的时间基本处于无序的状态.随着计算机网络应用的不断涌现,计算机的时间同步问题成为愈来愈重要的事情.以Un ...

  4. 最直白、最易懂的话带你认识和学会---数据分析基础包之numpy的使用

    前言 numpy是一个很基础很底层的模块,其重要性不言而喻,可以说对于新手来说是最基础的入门必须要学习的其中之一.在很多数据分析,深度学习,机器学习亦或是人工智能领域的模块中,很多的底层都会用到这个模 ...

  5. awk进阶

    整理的awk的小技巧 begin是要放在正则前面的,按照这个顺序: awk 'begin{} /.*?/ {action}end{}' file FS=':' 和 -F: 是等同的 -F 表示以 XX ...

  6. 转:Ubuntu16.04下配置php+vscode+xdebug开发环境

    转:https://blog.csdn.net/its_my_dream/article/details/78549619 操作系统是Ubuntu16.04,首先要安装和配置php运行环境,我这里用的 ...

  7. Python并发编程-管道

    管道的作用- 两个进程间传递消息 from multiprocessing import Pipe, Process def func(conn1,conn2): conn2.close() #子进程 ...

  8. Java常用工具类之删除文件

    package com.wazn.learn.util; import java.io.File; /** * 删除文件工具类 * @author yangzhenyu * */ public cla ...

  9. Bzoj1202/洛谷P2294 [HNOI2005]狡猾的商人(带权并查集/差分约束系统)

    题面 Bzoj 洛谷 题解 考虑带权并查集,设\(f[i]\)表示\(i\)的父亲(\(\forall f[i]<i\)),\(sum[i]\)表示\(\sum\limits_{j=fa[i]} ...

  10. Xamarin 2017.9.13发布更新

     Xamarin 2017.9.13发布更新 Visual Studio 2017更新到15.3.4.其中,Xamarin.Visual更新到4.6.3.4;Xamarin.iOS更新到10.12.3 ...