今天看到一篇文章主要内容是ThreadLocal是用来解决多线程下线程安全问题的,一开始很疑惑,比如从数据库获取一个Connection ,为什么要用ThreadLocal呢?为了线程安全吗?不是的,不使用ThreadLocal也是线程安全的,比如写一个工具类
public class ConnectionUtil {
private static String driver;
private static String uri;
private static String user;
private static String password;
static {
Properties props = new Properties();
try {
props.load(ConnectionUtil.class.getClassLoader()
.getResourceAsStream("properties文件路径"));
driver = props.getProperty("driver");
uri = props.getProperty("uri");
user = props.getProperty("user");
password = props.getProperty("password");
Class.forName(driver);
} catch (Exception e) {
}
}
/**
* 获得Connection对象
* @return
* @throws Exception
*/
public static Connection getConnection() throws Exception {
Connection con = DriverManager.getConnection(uri, user, password);
return con;
}
}
每个线程去getConnection()获取的Connection是不一样的,怎么会线程不安全的,明明是不同的Connection明显是线程安全的!而ThreadLocal是用来解决线程安全吗? 翻看源码发现ThreadLocal里面保存的仅是对象的引用,指向的堆中同一块内存!
那为什么要这样写呢?1.一个线程里可能需要多次获得一个Connection,如果不涉及事务还好,多消耗内存获取释放Connection,如果涉及事务就需要获得通一个Connction,当然我们不会在表现层和服务层获取Connection,但是这种思想是需要有的。2.在一个线程中多次获取一个对象 内存消耗大,将对象的引用保存在ThreadLocal中可以省去每次要用去new,如果需要用同一个省去了参数传递的麻烦。
总结一下:ThreadLocal 并不是为了解决线程安全问题,而是提供了一种将实例绑定到当前线程的机制,类似于隔离的效果,实际上自己在方法中 new 出来变量也能达到类似的效果。ThreadLocal 跟线程安全基本不搭边,绑定上去的实例也不是多线程公用的,而是每个线程 new 一份,这个实例肯定不是共用的,如果共用了,那就会引发线程安全问题。ThreadLocal 最大的用处就是用来把实例变量共享成全局变量,在程序的任何方法中都可以访问到该实例变量而已。网上很多人说 ThreadLocal 是解决了线程安全问题,其实是望文生义,两者不是同类问题。
如果还不明白,我们来看看阿里巴巴 java 开发手册中推荐的 ThreadLocal 的用法,那就彻底懂了:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
然后我们再要用到 DateFormat 对象的地方,这样调用:
1 |
|
如果还没明白,我再解释一下,ThreadLocal 相当于每个线程A在创建的时候,已经为你创建好了一个 DateFormat,这个 DateFormat 在当前这个线程A中共享。其他线程B,再用到 DateFormat 的地方,也会创建一个 DateFormat 对象,这个对象会在线程 B 中共享,直到线程 B 结束。
也就是说 ThreadLocal 的用法和我们自己 new 对象一样,然后将这个 new 的对象传递到各个方法中。但是到处传递的话,太麻烦了。这个时候,就应该用 ThreadLocal。