ThreadLocal
认识
ThreadLocal是一个map结构,ThreadLocal.set()默认是用当前线程作为key来使用。
ThreadLocal不是用来解决共享对象的多线程并发问题,而是每个线程都创建一个对象,其他线程访问不到本线程的对象,从而达到线程安全。
如果ThreadLocal.set()进行的对象本来就是多个线程共享的一个对象,还是会出现并发访问的问题。
源码简析
//空构造方法
public ThreadLocal() {
}
//添加元素
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
//如果不为null,map set值
if (map != null)
map.set(this, value);
else
//如果为null,创建一个map,key为当前线程
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
//线程里面持有一个变量ThreadLocal.ThreadLocalMap threadLocals = null;
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
//取值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//创建一个key值为当前线程,value为null的map
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();//null
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);//创建map
return value;
}
用法
InheritableThreadLocal 可以继承父线程的属性值
public class TestThreadLocal{
static final ThreadLocal<String> threadLocal = new ThreadLocal<String>();
static final InheritableThreadLocal<String> inheritableThreadLocal = new InheritableThreadLocal<String>();
public static void main(String[] args) {
threadLocal.set("主线程局部变量");
inheritableThreadLocal.set("可继承的父类的局部变量");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(threadLocal.get());//null
System.out.println(inheritableThreadLocal.get());//可继承的父类的局部变量
}
}).start();
}
}
自定义ThreadLocal
public class ThreadLocalTest
{
private static int data = 1;
static ThreadLocal threadLocal = new ThreadLocal();
public static void main(String[] args)
{
for (int i = 0; i < 2; i++)
{
new Thread(new Runnable()
{
@Override
public void run()
{
int data = new Random().nextInt();
MyThreadLocal.getInstance().put("data", data);
System.out.println(Thread.currentThread().getName()
+ " get data " + data);
System.out.println(Thread.currentThread().getName()
+ MyThreadLocal.getInstance());
new A().get();
new B().get();
}
}).start();
}
}
static class A
{
public void get()
{
System.out.println("A from " + Thread.currentThread().getName()
+ " get data " + MyThreadLocal.getInstance().get("data"));
}
}
static class B
{
public void get()
{
System.out.println("B from " + Thread.currentThread().getName()
+ " get data " + MyThreadLocal.getInstance().get("data"));
}
}
static class MyThreadLocal extends HashMap
{
private MyThreadLocal()
{
};
private static MyThreadLocal instance;
public static MyThreadLocal getInstance()
{// 因为每个线程不一样对象,所以不需要添加同步
if (threadLocal.get() == null)
{
instance = new MyThreadLocal();
map.set(instance);
}
return (MyThreadLocal) map.get();
}
}
}
数据库连接实现线程绑定
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import cn.zlz.exception.DaoException;
public class JdbcUtils {
private JdbcUtils(){}
private static String url;
private static String user;
private static String password;
private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();
// 将四要素抽取至配置文件
static {
try {
//读取配置文件 获得四要素
Properties props = new Properties();
InputStream inStream = JdbcUtils.class.getClassLoader()
.getResourceAsStream("jdbc.properties");
props.load(inStream);
String driverClass = props.getProperty("driverClass");
url = props.getProperty("url");
user = props.getProperty("user");
password = props.getProperty("password");
// 注册驱动
Class.forName(driverClass);
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
}
// 获得数据库连接
public static Connection getConnection() throws SQLException {
// 返回当前线程绑定的连接 原因是该连接上有事务
Connection conn = tl.get();
// 如果conn 为 null 说明线程上未绑定连接
if(conn==null) {
// 获得与数据库的连接
conn = DriverManager.getConnection(url, user, password);
// 绑定到当前线程
tl.set(conn);
}
return conn;
}
// 开启事务
public static void startTransaction() {
try {
// 获得当前线程上绑定的连接
Connection conn = getConnection();
// 开启事务
conn.setAutoCommit(false);
} catch (SQLException e) {
throw new DaoException(e);
}
}
// 提交事务
public static void commit() {
// 获得当前线程上绑定的连接
Connection conn = tl.get();
// 判断
if(conn!=null) {
try {
// 如果线程上有连接 提交该连接事务
conn.commit();
} catch (SQLException e) {
throw new DaoException(e);
}
}
}
// 回滚事务
public static void rollback() {
// 获得当前线程上绑定的连接
Connection conn = tl.get();
// 判断
if(conn!=null) {
try {
// 如果线程上有连接 回滚事务
conn.rollback();
} catch (SQLException e) {
throw new DaoException(e);
}
}
}
// 关闭连接 关闭当前线程上绑定的连接
public static void close() {
// 获得当前线程上绑定的连接
Connection conn = tl.get();
// 判断
if(conn!=null) {
try {
// 如果线程上有连接 关闭连接
conn.close();
} catch (SQLException e) {
throw new DaoException(e);
}
// 移除当前线程绑定的 connnection 对象
tl.remove();
}
}
public static void release(Connection conn, Statement stmt, ResultSet rs) {
if(rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
stmt = null;
}
if(conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}