ThreadLocal

xiaoxiao2021-03-01  9

什么是ThreadLocal

翻译过来中文意思就叫线程局部变量(thread local variable),就是为每个线程都创建一个这样的变量(以ThreadLocal对象为键、任意对象为值的存储结构),这个变量被附带在线程上,每个线程之接相互隔离,互不干扰,该变量副本只能创建它的线程能使用。

ThreadLocal应用场景

如下代码: public class DBUtil { private static Connection connect = null; public static Connection getConnection() { if(connect == null){ connect = DriverManager.getConnection(); } return connect; } public static void close() { if(connect!=null){ connect.close(); } } }

观察一下这段代码在单线程中使用是没有任何问题的,但是如果在多线程中使用呢?因为JDBC规范并未要求Connection自身一定是线程安全的,很显然,如果没有额外的协调时,在多线程中使用会存在线程安全问题:

(1):这里面的2个方法都没有进行同步,在多线程调用的情况下很可能在getConnection方法中会多次创建connect (2):由于connect是共享变量,那么必然在调用connect的地方需要使用到同步来保障线程安全,因为很可能一个线程在使用connect进行数据库操作,而另外一个线程调用close方法关闭链接(就可能会报 No operations allowed after connection closed)。

所以出于线程安全的考虑,必须将这段代码的两个方法进行同步处理,并且在调用connect的地方需要进行同步处理,这样将会大大影响程序执行效率,因为一个线程在使用connect进行数据库操作的时候,其他线程只有等待。

还有再试想下这个connect对象到底需不需要同步?不管是谁来getConnection方法都是为了得到一个数据库的连接,其实这种场景是不需要同步的;那么我们既需要保证线程安全又不需要同步的话使用ThreadLocal还是比较合适的,多线程多实例,确保线程封闭性。

改造一下代码:

public class DBUtil { private static final ThreadLocal<Connection> conn = new ThreadLocal<>(); public static Connection getConnection() { Connection con = conn.get(); if (con == null) { try { Class.forName("com.mysql.jdbc.Driver"); con = DriverManager.getConnection("url", "root", "root"); conn.set(con); } catch (Exception e) { // ... } } return con; } public static void close() { Connection con = conn.get(); if(con !=null){ con.close(); } } }

这样子,每个线程都有自己的数据库连接(当然,正规的应用应该要加连接池限制资源之类的),就不会产生那样的冲突了。还有由于在每个线程中都创建了副本,所以要考虑它对资源的消耗。

写的还比较粗糙,如果我的理解或者代码有不正确的地方,还望指正。

转载请注明原文地址: https://www.6miu.com/read-3264816.html

最新回复(0)