`

【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同步机制解决线程安全问题更简单,更方便,并且程序拥有更高的并发性。

 

 

分享到:
评论

相关推荐

    java ThreadLocal多线程专属的变量源码

    java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...

    java 简单的ThreadLocal示例

    java 简单的ThreadLocal示例

    java事务 - threadlocal

    ThreadLocal保证一个类的实例变量在各个线程中都有一份单独的拷贝, 从而不会影响其他线程中的实例变量

    java中ThreadLocal详解

    详解java底层实现原理,ThreadLocal底层实现的数据结构,为什么不会导致内存泄露

    事务的封装和Threadlocal实例

    JDBC事务的封装和Threadlocal实例,参考博客:http://blog.csdn.net/daijin888888/article/details/50988053

    Java中ThreadLocal的设计与使用

    Java中ThreadLocal的设计与使用.doc

    Java资料-详解ThreadLocal

    Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal ;Java资料—详解ThreadLocal Java资料—详解ThreadLocal

    JAVA ThreadLocal类深入

    深入研究java.lang.ThreadLocal类。ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是 threadlocalvariable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。

    线程ThreadLocal机制实现例子

    本例以序列号生成的程序为例,展示ThreadLocal的使用

    Java并发编程实战

    3.3.3 ThreadLocal类 3.4 不变性 3.4.1 Final域 3.4.2 示例:使用Volatile类型来发布不可变对象 3.5 安全发布 3.5.1 不正确的发布:正确的对象被破坏 3.5.2 不可变对象与初始化安全性 3.5.3 安全发布的常用...

    Java多线程编程中ThreadLocal类的用法及深入

    早在 JDK 1.2 的时代,java.lang.ThreadLocal 就诞生了,它是为了解决多线程并发问题而设计的,只不过设计得有些难用,所以至今没有得到广泛使用。其实它还是挺有用的,不相信的话,我们一起来看看这个例子吧。 一个...

    彻底理解Java 中的ThreadLocal

    主要介绍了彻底理解Java 中的ThreadLocal的相关资料,需要的朋友可以参考下

    java中ThreadLocal类的使用

    NULL 博文链接:https://justsee.iteye.com/blog/791919

    简单分析Java线程编程中ThreadLocal类的使用共

    简单分析Java线程编程中ThreadLocal类的使用共4页.pdf.zip

    Java单线程ThreadLocal串值问题解决方案

    主要介绍了Java单线程ThreadLocal串值问题解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    彻底理解Java中的ThreadLocal

    ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。使用这个工具类可以很简洁地编写出优美的多线程程序。接下来通过本文给大家介绍Java中的ThreadLocal,需要的朋友可以参考下

    Java多线程编程之ThreadLocal线程范围内的共享变量

    主要介绍了Java多线程编程之ThreadLocal线程范围内的共享变量,本文讲解了ThreadLocal的作用和目的、ThreadLocal的应用场景、ThreadLocal的使用实例等,需要的朋友可以参考下

    ThreadLocal详解

    java 多线程 ThreadLocal

    myMvcWeb2.rar Java实现

    MVC框架,加注解,Struts框架的思想,动态代理,线程管理对象ThreadLocal,Connection对象池,Properties文件读取,EL表达式,JSTL,JavaBean,Java访问MySQL数据库,增删改查... ---------------------------------...

    使用Java ThreadLocal.docx

    虽然所有的线程都能访问到这个ThreadLocal实例,但是每个线程却只能访问到自己通过调用ThreadLocal的set()方法设置的值。即使是两个不同的线程在同一个ThreadLocal对象上设置了不同的值,他们仍然无法访问到对方的值...

Global site tag (gtag.js) - Google Analytics