日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

真实项目中 ThreadLocal 的妙用

發布時間:2023/12/13 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 真实项目中 ThreadLocal 的妙用 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是 ThreadLocal

ThreadLocal 提供了線程的局部變量,每個線程都可以通過 set() 和 get() 來對這個局部變量進行操作,但不會和其他線程的局部變量沖突,實現了線程間的據隔離。

簡單講:一個獲取用戶的請求線程 A,如果向 ThreadLocal 填充變量 AValue(只能被線程 A 操作),該變量對其他獲取用戶的請求線程 B、C...是隔離的.

最簡單的使用方式:

類似一次 HTTP 請求線程中,利用 ThreadLocal 存儲 Cookie 對象,進行狀態管理。set Cookie:

private ThreadLocal httpThreadLocal = new ThreadLocal();httpThreadLocal.set(“Cookie: sid=13420771402233”)

上面存儲格式是 String ,實際場景存儲的是具體的對象。在這次 HTTP 請求過程中,任何時候都可以獲取 Cookie 。獲取方式很簡單 get Cookie:

String cookieValue = (String) httpThreadLocal.get();

Thread 與 ThreadLocal 對象引用關系圖

二、你熟悉的場景

2.1 數據庫連接池

比如一次請求線程進來,業務 Dao 需要更新 user 表和 user-detail 表。如果是 new 出兩個數據庫 Connection ,分別不同的 Connection 操作 user 表和 user-detail 表,就無法保證事務。那么數據庫連接池是如何保證的?

答案是:利用 ThreadLocal 存儲唯一 Connection 對象。每次請求線程,pool.getConnection 獲取連接的時候都會這樣操作:

  • 會從 ThreadLocal 獲取 Connection 對象。如果有,則保證了后面多個數據庫操作共用同一個 Connection ,從而保證了事務。
  • 如果沒有,往 ThreadLocal 新增Connection 對象,并返回到線程
錯誤的做法
public class XXXService {private Connection conn; }

因為 conn 是線程不安全的。這樣會導致多個請求公用一個連接。請求量很大的情況下,延遲各種。你懂。

因此,使用 ThreadLocal 保證每個請求線程的 Connection 是唯一的。即每個線程有自己的連接。

繼續講到 Spring 框架,在事務開始時,會給當前線程一個Jdbc Connection,在整個事務過程,都是使用該線程綁定的connection來執行數據庫操作,實現了事務的隔離性。Spring框架里面就是用的ThreadLocal來實現這種隔離

比如你訪問百度、我訪問百度,會有不同 Cookie 。而且你不能訪問我的 Cookie,我也不能。顧名思義,使用 ThreadLocal 保證每個 HTTP 請求線程的 Cookie 是唯一的。

Cookie 這樣才能做 Session 等狀態管理。

三、實戰場景

總結一下就是:ThreadLocal 可以讓同一個線程中上下文之間數據共享

在上面章節 二、你熟悉的場景 其實介紹了很多現有場景。那么我這邊具體的實戰場景是什么?

簡單的例子:

適用滿足這兩個條件的場景:1.每個線程獨有的一些信息,2.這些信息又會在多個方法或類中用到。

  • 一個請求線程,里面有兩個異步小線程,各有一個方法。分別處理 A 或 B 業務
  • 一種方法是傳遞不可變的入參
  • 另一種就是 ThreadLocal,放在 ThreadLocal 的入參,會被各個方法共享。而且多個請求線程互不影響
  • 復雜的例子:

    一次發貨操作:會根據入參,進行組件化、流程編排話。那么入參會被各個地方用到,而且有些流程組件是異步的(類似 new thread 操作的)。這時候可以定一個 XXContext 上下文:

    public class XXContext {private static ThreadLocal<Map<Class<?>, Object>> context = new InheritableThreadLocal<>();/*** 把參數設置到上下文的Map中*/public static void put(Object obj) {Map<Class<?>, Object> map = context.get();if (map == null) {map = new HashMap<>();context.set(map);}if (obj instanceof Enum) {map.put(obj.getClass().getSuperclass(), obj);} else {map.put(obj.getClass(), obj);}}/*** 從上下文中,根據類名取出參數*/@SuppressWarnings("unchecked")public static <T> T get(Class<T> c) {Map<Class<?>, Object> map = context.get();if (map == null) {return null;}return (T) map.get(c);}/*** 清空ThreadLocal的數據*/public static void clean() {context.remove();} }

    代碼解析:

    • 都是 static 操作,類似 DateUtil 玩法
    • 記得每次請求線程后清理。可以 AOP 去清理,加個注解就行。因為同一個請求線程可能被業務方公用。

    (完)

    轉載于:https://www.cnblogs.com/Alandre/p/11145516.html

    總結

    以上是生活随笔為你收集整理的真实项目中 ThreadLocal 的妙用的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。