ThreadLocal的彻底理解(ThreadLocal不是用来解决多线程下访问共享变量问题的)

今天看到一篇文章主要内容是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

package com.xttblog.test;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

public class DateUtil {

    public static final ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(){

        @Override

        protected DateFormat initialValue() {

            return new SimpleDateFormat("yyyy-MM-dd");

        }

    };

}

然后我们再要用到 DateFormat 对象的地方,这样调用:

1

DateUtils.df.get().format(new Date());

如果还没明白,我再解释一下,ThreadLocal 相当于每个线程A在创建的时候,已经为你创建好了一个 DateFormat,这个 DateFormat 在当前这个线程A中共享。其他线程B,再用到 DateFormat 的地方,也会创建一个 DateFormat 对象,这个对象会在线程 B 中共享,直到线程 B 结束。

也就是说 ThreadLocal 的用法和我们自己 new 对象一样,然后将这个 new 的对象传递到各个方法中。但是到处传递的话,太麻烦了。这个时候,就应该用 ThreadLocal。

 

猜你喜欢

转载自blog.csdn.net/qq_35232663/article/details/82914537