【java项目实战】ThreadLocal封装Connection,实现同一线程共享资源

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

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

1、认识一下ThreaLocal

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

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

2、ThreaLocal封装Connection实例+解析

以下的代码仅仅是ThreaLocal封装Connection的核心代码,对于多余的内容成功避开就好,而且有一部分代码是“dom4j解析xml文件。连接数据库”的内容,很适合刚開始学习的人,如有须要,请您移驾到此

package com.bjpowernode.drp.util;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 採用ThreadLocal封装Connection
 * 仅仅要线程是活动的,没有结束,ThreadLocal是可訪问的,就能够訪问本线程的connection
 *
 * @author liang
 *
 */
public class ConnectionManager {

	//使用ThreadLocal保存Connection变量
	private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>();

	/**
	 * 连接Connection
	 * @return
	 */
	public static Connection getConnection(){
		//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 new ApplicationException("系统错误,请联系系统管理员");
			} catch (SQLException e) {
				e.printStackTrace();
			throw new ApplicationException("系统错误。请联系系统管理员");
			}
		}
		return conn;									

	}
	/**
	 * 关闭Connection,清除集合中的Connection
	 */
	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资源。

package com.bjpowernode.drp.flowcard.manager.impl;

import java.sql.Connection;
import java.util.Date;
import com.bjpowernode.drp.flowcard.dao.FlowCardDao;
import com.bjpowernode.drp.flowcard.domain.FlowCard;
import com.bjpowernode.drp.flowcard.manager.FlowCardManager;
import com.bjpowernode.drp.util.ApplicationException;
import com.bjpowernode.drp.util.BeanFactory;
import com.bjpowernode.drp.util.ConnectionManager;
import com.bjpowernode.drp.util.DaoException;
import com.bjpowernode.drp.util.PageModel;

public class FlowCardManagerImpl 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 new ApplicationException("加入流向单失败!

");
		}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、对照ThreadLocal和synchronized同步机制

同样点:

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

不同点:

1、适用的情况不同

在同步机制中,使用同步保证同一时间仅仅有一个线程訪问,不能同一时候訪问共享资源,否则就是出现错误。ThreadLocal则隔离了相关的资源,并在同一个线程中能够共享这个资源。

彼此独立,改动不会影响到对方。

2、终于实现的效果不同

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

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

4、一句话总结ThreadLocal

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

时间: 2024-08-04 17:17:38

【java项目实战】ThreadLocal封装Connection,实现同一线程共享资源的相关文章

【java项目实战】dom4j解析xml文件,连接Oracle数据库

简介 dom4j是由dom4j.org出品的一个开源XML解析包.这句话太官方,我们还是看一下官方给出的解释.如下图: dom4j是一个易于使用的.开源的,用于解析XML,XPath和XSLT等语言的库.它应用于Java平台,采用了Java集合框架并完全支持DOM,SAX和JAXP等编程标准. 特点 dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用的特点,同时它也是一个开放源代码的软件.如今你可以看到越来越多的Java软件都在使用dom4j来读写XML,例

【java项目实战】Servlet详解以及Servlet编写登陆页面(二)

Servlet是Sun公司提供的一门用于开发动态web网页的技术.Sun公司在API中提供了一个servlet接口,我们如果想使用java程序开发一个动态的web网页,只需要实现servelet接口,并把类部署到web服务器上就可以运行了. 到底什么是Servlet呢? 通俗一点,只要是实现了servlet接口的java程序,均称Servlet.Servlet是由sun公司命名的,Servlet = Server + Applet(Applet表示小应用程序),Servlet是在服务器端运行的小

【java项目实战】一步步教你使用MyEclipse搭建java Web项目开发环境(一)

首先,在开始搭建MyEclipse的开发环境之前,还有三步工具的安装需要完成,只要在安装配置成功之后才可以进入下面的java Web项目开发环境的搭建. 1.安装工具 第一步,下载并安装JDK,到官网上下载安装即可,之后需要细心的配置环境变量,我给大家推荐百度文库的一篇文章,猛戳这里. 第二步,下载Tomcat,当然可以去Apache Tomcat的官网,同样,您可以移驾到我的资源下载,外送API文档(免资源分). 第三步,下载MyEclipse,MyEclipse官网,傻瓜式安装即可. ===

Java项目实战1

本文主要介绍一个Java实战项目的例子: DAO类设计: com.huawei.daojava.sql.Connectionjava.sql.PreparedStatementjava.sql.ResultSetjava.sql.SQLExceptionjava.text.SimpleDateFormatjava.util.ArrayListjava.util.Collectionsjava.util.Datejava.util.HashMapjava.util.Listjava.util.Ma

【java项目实战】代理模式(Proxy Pattern),静态代理 VS 动态代理

这篇博文,我们主要以类图和代码的形式来对照学习一下静态代理和动态代理.重点解析各自的优缺点. 定义 代理模式(Proxy Pattern)是对象的结构型模式,代理模式给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用. 代理模式不会改变原来的接口和行为,仅仅是转由代理干某件事,代理能够控制原来的目标,比如:代理商,代理商仅仅会买东西,但并不会改变行为.不会制造东西. 让我们通过以下的代码好好理解一下这句话. 分类 静态代理和动态代理 静态代理 静态代理类图 代码演示样例 接口 pac

【java项目实战】Servlet具体解释以及Servlet编写登陆页面(二)

Servlet是Sun公司提供的一门用于开发动态web网页的技术. Sun公司在API中提供了一个servlet接口,我们假设想使用java程序开发一个动态的web网页,仅仅须要实现servelet接口,并把类部署到webserver上就能够执行了. 究竟什么是Servlet呢? 通俗一点,仅仅要是实现了servlet接口的java程序,均称Servlet. Servlet是由sun公司命名的,Servlet = Server + Applet(Applet表示小应用程序),Servlet是在s

JAVA项目实战,项目架构,高并发,分布式,微服务架构,微信支付,支付宝支付,理财系统,并发编程

Spring Cloud集成项目有很多,下面我们列举一下和Spring Cloud相关的优秀项目,我们的企业架构中用到了很多的优秀项目,说白了,也是站在巨人的肩膀上去整合的.在学习Spring Cloud之前大家必须了解一下相关项目,希望可以帮助到大家. Spring Cloud Config 配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储.Git以及Subversion. Spring Cloud Bus 事件.消息总线,用于在集群(例如,配置变化事件)中传

【Java项目实战】——DRP之HTML总结

在DRP的学习之中,又将之前BS的内容又一次复习了一遍,借着复习的机会将BS的各个部分再又一次总结一下.今天来总结一下HTML. 在学习BS之后就进入了权限系统的开发之中,可是仍然发现非常多代码不会不懂,所以又一次去网上查去网上找,在那个循序渐进的过程里,我发现自己学习的东东真的非常浅非常浅.在学习DRP的过程中.又将BS的内容又一次复习了一遍.这一遍就发现这些内容亲切多了.在今天总结的HTML中就不像之前那样介绍HTML是什么,介绍HTML的背景知识了,直接将HTML一些须要注意的标签拿出来,

【Java技术点滴】——ThreadLocal封装JDBC事务操作

背景 在Java程序实现中,我们往往应用到事务的机制,在业务层进行事务开启,创建数据库连接,调用Dao层方法进行数据库访问,过程中需要将数据库连接Connection作为参数传递给Dao层方法.显而易见,这样的实现不利于Dao层方法的复用,当在不使用事务的情况下,我们是需要在Dao层方法中创建数据库连接的,这样Dao层方法免去Connection参数就可以使得方法更加独立.明确了,怎样解决这样的尴尬?对于此,我们使用了ThreadLocal进行解决. 基本介绍 "本地线程变量",可以理