真實專案中 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來實現這種隔離
2.2 HTTP Cookie
比如你訪問百度、我訪問百度,會有不同 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 去清理,加個註解就行。因為同一個請求執行緒可能被業務方公用。
(完)
相關推薦
真實專案中 ThreadLocal 的妙用
一、什麼是 ThreadLocal ThreadLocal 提供了執行緒的區域性變數,每個執行緒都可以通過 set() 和 get() 來對這個區域性變數進行操作,但不會和其他執行緒的區域性變數衝突,實現了執行緒間的據隔離。 簡單講:一個獲取使用者的請求執行緒 A,如果向 ThreadLocal 填充變數 A
KeyPath在Swift中的妙用
原文連結: The power of key paths in Swift 自從swift剛開始就被設計為是編譯時安全和靜態型別後,它就缺少了那種我麼經常在執行時語言中的動態特性,比如Object-C, Ruby和JavaScript。舉個例子,在Object-C中,我們可以很輕易的動態去獲取一個物件的任意
C語言異或運算在程式設計中的妙用
異或運算子^也稱XOR運算子。它的規則是若參加運算的兩個二進位同號,則結果為0(假);異號則為1(真)。即0 ^ 0=0,0 ^ 1=1,1 ^ 1=0。 性質: (1) 一個數與1異或會翻轉 (2) 一個數與0異或保持不變 (3) 一個數異或它本身等於0
switchHosts! 專案中人人都用的神器
SwitchHosts! 是一個管理、切換多個 hosts 方案的工具。 不管是開發人員、測試人員、PD、、、都離不開switchHosts! 它是一個免費開源軟體。日常開發工作
jQuery select 全國城市三級聯動省市區(專案中修改頁面用到了)
jQuery select 全國城市三級聯動 在專案中修改頁面會用到,之前用$.filter()函式不行,換成$.each()就可以啦 附程式碼: $(function () { _init_area(); setTimeout(functi
Android省市區三級聯動滾輪選擇(真實專案中提取出來的元件)
最近專案要做一個,類似淘寶手機客戶端的,選擇收貨地址的三級聯動滾動選擇元件,下面是它的大致介面截圖: 在IOS中有個叫UIPickerView的選擇器,並且在dataSource中定義了UIPickerView的資料來源和定製內容,所以用只要熟悉它的基本用法,要實現這麼
專案中統計報表用到echarts圖表,備份一下
首先引入js檔案 <script src="/assets/js/echarts.min.js" charset="utf-8"></script> 觸發事件 <button onclick="javascript:que
談動態代理在解決記憶體洩露中的妙用
記憶體洩露在Android開發中很常見,每次產品上線之前都要集中解決記憶體洩露問題,有的問題很明顯,有的藏的很深,解決起來要頗費一番功夫,不過總的思路都是一樣,就是切斷引用鏈,讓資源在該釋放的時候能被及時釋放。 我們先看一個記憶體洩露的案例: publi
雙引號在搜尋中的妙用
有時候我們想輸入一個完整的片語,卻不想搜尋結果不盡人意,例如,輸入:VC++ 教程會返回如圖1的結果: (圖1) 這時我們要藉助Google中的一個雙引號功能輸入:"VC++ 教程" (圖2) 瞧,"VC++ 教程"這個片語被準確地顯示在搜尋結果中。所以平常要搜尋片語時
getchar()在C程式中的妙用!
getchar()在C程式中的功能是接收一個字元,當我們在連續輸入字元的時候getchar()會給你意想不到的效果。下面是net小夥做的一些測試: 首先看下面的這個程式: 1 #include<stdio.h> 2 #include<stdl
【一起學設計模式】觀察者模式實戰:真實專案中屢試不爽的瓜娃EventBus到底如何實現觀察者模式的?
申明 本文章首發自本人公眾號:壹枝花算不算浪漫,如若轉載請標明來源! 感興趣的小夥伴可關注個人公眾號:壹枝花算不算浪漫 22.jpg 前言 之前出過一個設計模式的系列文章,這些文章和其他講設計模式的文章 有些不同 文章沒有拘泥於講解設計模式的原理,更多的是梳理工作中實際用到的一些設計模式,並提取出對應業務模
深入淺出 妙用Javascript中apply、call、bind
com alt apply all 如何使用 name 深入 期待 單體模式 網上文章雖多,大多復制粘貼,且晦澀難懂,我希望能夠通過這篇文章,能夠清晰的提升對apply、call、bind的認識,並且列出一些它們的妙用加深記憶。 apply、call 在 ja
C語言在linux內核中do while(0)妙用之法
pos turn jsb world div fprintf cpp efault code 為什麽說do while(0) 妙?由於它的確就是妙,並且在linux內核中實現是相當的妙,我們來看看內核中的相關代碼: #define db_error(fmt, ..
asp.net core中IHttpContextAccessor和HttpContextAccessor的妙用
class sys image 只需要 iap href build .com bubuko 分享一篇文章,關於asp.net core中httpcontext的拓展。 現在,試圖圍繞HttpContext.Current構建你的代碼真的不是一個好主意,但是我想如果你
Python中__name__屬性的妙用
-s mod 特點 ont __main__ span pytho 執行 自己 在Python中,每一個module文件都有一個built-in屬性:__name__,這個__name__有如下特點: 1 如果這個module文件是被別的文件導入的,那麽,該__name__
delphi 中OutputDebugString 函數的妙用(轉載)
ins dbgview rect blank read con fine eve bsp 原文地址 https://www.peganza.com/delphi-and-outputdebugstring.html Ever wanted to monitor your
賦值語句中||與&&的理解與妙用
一、 宣告變數a a = 1 || 100; a = 0 || 100; 1、上述程式碼在JavaScript(弱型別的解釋型語言)中,結果如下: a = 1 || 100; //1 a = 0 || 100; //100 2、上述程式碼在C、Java等(強型別編譯型語言)中,結果如下:
分享JavaWeb中filter過濾器的案例妙用 - 髒話過濾/編碼過濾/程式碼過濾
案例1. 利用Servlet的過濾器Filter進行完成髒話過濾 package cn.javabs.filter; import java.io.IOException; import javax.servlet.Filter; import javax.servle
所謂的網頁爬蟲用java程式碼來實現,此程式碼適合在maven專案中使用中使用,因為,程式碼中的類所對應的依賴可以讓maven下載。
//獲得httpClient物件 CloseableHttpClient httpClient = HttpClients.createDefault(); //url公司域名隨便 String url = "https://www.baidu.co
delphi 中OutputDebugString 函式的妙用(轉載)
原文地址 https://www.peganza.com/delphi-and-outputdebugstring.html Ever wanted to monitor your Delphi application in realtime, and be able to view log message