问题场景一:高并发的时候,我们在调用一些公有的对象资源的时候,会有线程安全问题。
问题场景二:我既要解决安全问题,我又要实现全局共享呢。
很多地方我们都需要这样做。比如:我们需要获取数据库连接的时候,我们会单独封装一个方法叫getConnection()这个方法用来获取connect
,那么我们还会封装几个方法
commit()提交事物,
rollback()回滚事物的方法,
closeConnection()关闭连接方法。
这几个方法自然需要共用一个connection对象才能对当前连接进行操作。
那么如何共用呢?全局变量会造成线程安全问题,加锁会对性能有影响,设置为局部变量,那么就不能在各个方法中使用了。 我们现在需要一个:既能够共用,但又不是全局变量线程安全的东西,仿佛是局部定义的变量能够在各个方法中重用一样。
这个时候就可以使用ThreadLocal来解决既能够共用,又不会造成线程安全的问题。**
至于ThreadLocal怎么用,网上很多例子,我也看了,但是看来看去都没说为什么要用,只说了怎么用,怎么用的博客太多了。我这里就简单的贴一下代码案例:
package day02;
import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.commons.dbcp.BasicDataSource;
/**
* 该类用于维护数据库连接
* @author tarena
*
*/
public class DBUtil {
/*
* ThreadLocal用于线程跨方法共享数据使用
* TheaddLocal内部有一个Map,key为要共
* 享数据的线程本身,value就是其需要共享的数据。
*/
private static ThreadLocal<Connection> tl;
private static BasicDataSource dataSource;
private static String className;
private static String url;
private static String username;
private static String password;
static{
tl = new ThreadLocal<Connection>();
/*
* properties文件
* properties文件常被用来做配置文件,
* 结构简单。
*/
try{
Properties pro = new Properties();
pro.load(new FileInputStream("src/main/java/day02/config.properties"));
className = pro.getProperty("classname");
url = pro.getProperty("url");
username = pro.getProperty("username");
password = pro.getProperty("password");
int maxActive = Integer.parseInt(pro.getProperty("maxactive"));
long maxWait = Long.parseLong(pro.getProperty("maxwait"));
//初始化连接池
dataSource = new BasicDataSource();
dataSource.setDriverClassName(className);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
//设置最大连接
dataSource.setMaxActive(maxActive);
//设置最大等待时间
dataSource.setMaxWait(maxWait);
}catch(Exception e){
e.printStackTrace();
}
}
/**
* 获取数据库连接
* @return
* @throws SQLException
* @throws ClassNotFoundException
*/
public static Connection getConnection() throws SQLException, ClassNotFoundException{
Connection connection = dataSource.getConnection();
// Class.forName(className);
// Connection connection = DriverManager.getConnection(url,username,password);
tl.set(connection);
return connection;
}
/**
* 关闭数据库
* @param conn
*/
public static void closeConnection(){
try{
//关闭连接前,提交事务
TransCommit();
//如果是使用连接池获得的连接,那么调用该连接的close方法不会关闭连接,只是表示当前连接使用完毕,空闲。
Connection connection = tl.get();
//删除当前线程所存放的连接
tl.remove();
if(connection != null){
connection.close();
}
}catch(Exception e){
e.printStackTrace();
}
}
/*
* 开启事务
*/
public static void TransBegin(){
try {
tl.get().setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
//回滚事务
public static void TransRollBack(){
try {
tl.get().rollback();
tl.get().setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
//提交事务
public static void TransCommit(){
try {
tl.get().commit();
tl.get().setAutoCommit(true);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
因篇幅问题不能全部显示,请点此查看更多更全内容