当访问共享的可变数据时,通常需要使用同步。
一种避免使用同步的方式就是不共享数据。如果尽在单线程内访问数据,就不需要同步。这种技术被称为线程封闭,这是实现线程安全最简单的方式之一。
ThreadLocal是一种维持线程封闭性的方法。
ThreadLocal类能使线程中的某个值域保存值的对象关联起来。
ThreadLocal提供的get和set等方法,为每个使用该变量的线程都存有一份独立的副本,因此get总是返回有当前执行线程在调用set时设置的最新值。
ThreadLoca对象通常用于全局变量的共享,例如用于jdbc线程池
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class DataSourceUtils {
private static DataSource dataSource = new ComboPooledDataSource();
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
// 直接可以获取一个连接池
public static DataSource getDataSource() {
return dataSource;
}
//从当前线程城绑定中获得connnection
public static Connection getCurrentConnection() throws SQLException{
Connection conn = tl.get();
//判断ThreadLocal中是否已经有connecction
if(conn==null){
conn = getConnection();
tl.set(conn);
}
return conn;
}
// 获取连接对象
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void startTransaction() throws SQLException {
Connection conn = getCurrentConnection();
conn.setAutoCommit(false);
}
public static void rollback() throws SQLException {
Connection conn = getCurrentConnection();
conn.rollback();
}
public static void commit() throws SQLException {
Connection conn = getCurrentConnection();
conn.commit();
tl.remove();
conn = null;
}
}
上例的DataSourceUtils的getCurrentConnection就使用了ThreadLocal类来保证当前线程得到的是同一个DataSource,
这可以用于jdbc连接保证service层的事务。
例如在service层开启事务,并执行业务逻辑,如果成功就commit,如果失败就rollback。可是如果在service层和dao层使用的连接不是同一个connection。则不能保证事务的一致性。
而ThreadLocal则可以避免这种情况的发生,在service层开启事务,并执行业务逻辑,如果成功就commit,如果失败就rollback。而在dao层使用getCurrentConnection获取的就是service层使用的connection,这样就保证了connection的唯一。