zoukankan      html  css  js  c++  java
  • ThreadLocal封装Connection,实现同一线程共享资源

     JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。使用这个工具类可以很简洁地编写出优美的多线程程序,ThreadLocal并不是一个Thread,而是Thread的局部变量

    线程安全一直是程序猿们关注的焦点,多线程也一直是比较让人头疼的话题,想必大家曾经也遇到过各种各种的问题,我就不再累述了。当然,解决方式也有很多,这篇博文给大家提供一种很好的解决线程安全问题的思路。

          首先,我们先简单的认识一下ThreadLocal,之后是实例+解析,最后一句话总结。

    1、认识一下ThreaLocal

           认识ThreadLocal必须要通过api文档,不仅仅具有说服力,而且它会给你更加全面的解释。下面我我给大家从api文档上截取一张图,并标出来了七点需要重点理解的内容,实例过后的解析也是重点解释这七部分。

    对于上面的内容,不理解没有关系,我们通过下面的实例加深一下理解,实例之后我会给大家一个更加深入的解释。 

    2ThreaLocal封装Connection实例+解析

       ​下面的代码只是ThreaLocal封装Connection的核心代码,对于多余的内容成功避开就好,并且有一部分代码是“dom4j解析xml文件,连接数据库”的内容,非常适合初学者,如有需要,请您移驾到此。

    [java] viewplaincopyprint?

    packagecom.bjpowernode.drp.util; 

     

    importjava.sql.Connection; 

    importjava.sql.DriverManager; 

    importjava.sql.ResultSet; 

    importjava.sql.SQLException; 

    importjava.sql.Statement; 

     

     

    public classConnectionManager { 

     

        //使用ThreadLocal保存Connection变量 

        private staticThreadLocal connectionHolder = newThreadLocal();      

        public static ConnectiongetConnection(){ 

            //ThreadLocal取得当前线程的connection 

            Connection conn =connectionHolder.get(); 

            //如果ThreadLocal没有绑定相应的Connection,创建一个新的Connection, 

            //并将其保存到本地线程变量中。 

            if(conn == null){ 

                try { 

                    JdbcConfig jdbcConfig =XmlConfigReader.getInstance().getJdbcConfig(); 

                   Class.forName(jdbcConfig.getDriverName());               

                    conn =DriverManager.getConnection(jdbcConfig.getUrl(), jdbcConfig.getUserName(),jdbcConfig.getPassword()); 

                    //将当前线程的Connection设置到ThreadLocal 

                   connectionHolder.set(conn); 

                } catch (ClassNotFoundException e){ 

                    e.printStackTrace(); 

                    throw newApplicationException("系统错误,请联系系统管理员"); 

                } catch (SQLException e) { 

                    e.printStackTrace(); 

                throw newApplicationException("系统错误,请联系系统管理员"); 

                } 

            } 

            return conn;    

             

        }  

         

        public static void closeConnection(){ 

            //ThreadLocal取得当前线程的connection 

            Connection conn =connectionHolder.get(); 

            //当前线程的connection不为空时,关闭connection. 

            if(conn != null){ 

                try{ 

                    conn.close(); 

                    //connection关闭之后,要从ThreadLocal的集合中清除Connection 

                    connectionHolder.remove(); 

                }catch(SQLException e){ 

                    e.printStackTrace(); 

                } 

     

            } 

        } 

     

          下面的代码给大家演示了:ThreadLocal如何在同一个线程中可以共享Connection资源。

     

    [java] viewplaincopyprint?

    packagecom.bjpowernode.drp.flowcard.manager.impl; 

     

    importjava.sql.Connection; 

    importjava.util.Date; 

    importcom.bjpowernode.drp.flowcard.dao.FlowCardDao; 

    importcom.bjpowernode.drp.flowcard.domain.FlowCard; 

    importcom.bjpowernode.drp.flowcard.manager.FlowCardManager; 

    importcom.bjpowernode.drp.util.ApplicationException; 

    importcom.bjpowernode.drp.util.BeanFactory; 

    importcom.bjpowernode.drp.util.ConnectionManager; 

    importcom.bjpowernode.drp.util.DaoException; 

    importcom.bjpowernode.drp.util.PageModel; 

     

    public classFlowCardManagerImpl implements FlowCardManager { 

     

         

        private FlowCardDao flowCardDao; 

        //构造函数 

        public FlowCardManagerImpl(){ 

            this.flowCardDao = (FlowCardDao)BeanFactory.getInstance().getDaoObject(FlowCardDao.class); 

        } 

         

        @Override 

        public void addFlowCard(FlowCard flowCard)throws ApplicationException { 

             

            Connection conn = null; 

            try{ 

                //ThreadLocal中获取线程对应的Connection 

                conn =ConnectionManager.getConnection(); 

                //开始事务 

               ConnectionManager.beginTransaction(conn); 

                //生成流向单单号 

                String flowCardVouNo = flowCardDao.generateVouNo(); 

                //添加流向单主信息 

               flowCardDao.addFlowCardMaster(flowCardVouNo, flowCard); 

                //添加流向单明细信息 

               flowCardDao.addFlowCardDetail(flowCardVouNo,flowCard.getFlowCardDetailList()); 

                //提交事务 

               ConnectionManager.commitTransaction(conn);       

            }catch(DaoException e){ 

                //回滚事务 

               ConnectionManager.rollbackTransaction(conn); 

                throw newApplicationException("添加流向单失败!"); 

            }finally{ 

                //关闭Connection并从ThreadLocal集合中清除 

               ConnectionManager.closeConnection(); 

            } 

         

        } 

     

    解析:

     

    1、该类提供了线程局部变量,它独立于变量的初始化副本

     

           大家可能对局部变量不太理解,为什么不是成员变量或全局变量,此时就涉及到变量的作用域问题。ThreadLocal具有比局部变量更大一点的作用域,在此作用域内资源可以共享,线程是安全的。

           我们还了解到ThreadLocal并不是本地线程,而是一个线程变量,它只是用来维护本地变量。针对每个线程提供自己的变量版本,避免了多线程的冲突问题,每个线程只需要维护自己的版本就好,彼此独立,不会影响到对方。

     

    2、每个线程有自己的一个ThreadLocal,修改它并不影响其他线程

     

          我们根据下面这张图可以看到,ThreadLocal里面存东西就是创建了一个Map,一个线程对应一个Map集合,然后ThreadLocal把这个Map挂到当前的线程底下,一个key值对应一个value,这样Map就只属于当前线程。(如果您不理解Map的特点可以猛戳)

     

     

     

    3、在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用)

     

          上面我们知道了变量副本的存放在了map,当我们不在调用set,此时不在将引用指向该‘map,而本线程退出时会执行资源回收操作,将申请的资源进行回收,其实就是将引用设置为null。这时已经不在有任何引用指向该map,故而会被垃圾回收。

     

    3、对比ThreadLocalsynchronized同步机制

     

    相同点:

            1ThreadLocal和线程同步机制都能解决多线程中相同变量的访问冲突问题。

    不同点:

           1、适用的情况不同

     

            在同步机制中,使用同步保证同一时间只有一个线程访问,不能同时访问共享资源,否则就是出现错误。ThreadLocal则隔离了相关的资源,并在同一个线程中可以共享这个资源。彼此独立,修改不会影响到对方。

     

           2、最终实现的效果不同

       

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

     

          上面博客的链接同样也是线程同步机制synchronized的实例,大家可以通过两个实例体会一下它们的异同点,再加上异同点解析,相信您对它们已经有了很深刻的认识。

     

    4、一句话总结ThreadLocal

     

           ThreadLocal是解决线程安全问题一个很好的思路,在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,并且程序拥有更高的并发性。


  • 相关阅读:
    Centos 安装字体库 以及解决confluence 旧文档数据的乱码
    设置Linux自启服务以及优先级
    Centos7下设置MySql自动启动
    Linux配置tomcat开机自启
    Linux安装JDK、tomcat
    CentOS7下安装mysql5.1 或升级到5.7 以及小问题的解决方案
    安装虚拟机,镜像文件下载链接
    1.键盘消失,阻止键盘弹出
    5. react父子组件
    CSS- 一些少用的
  • 原文地址:https://www.cnblogs.com/luckForever/p/7254203.html
Copyright © 2011-2022 走看看