把對象封裝到一個線程裏,只有這個線程能看到這個對象。html
Ad-hoc 線程封閉:程序控制實現,最糟糕,忽略
堆棧封閉:局部變量,無併發問題
ThreadLocal 線程封閉:特別好的封閉方法java
ThreadLocal 實例保存登陸用戶信息編程
public class RequestHolder { private final static ThreadLocal<Long> requestHolder = new ThreadLocal<>(); /** * 添加數據 * 在filter裏將登陸用戶信息存入ThreadLocal * 若是不使用ThreadLocal,咱們會須要將request一直透傳 * @param id */ public static void add(Long id){ // ThreadLocal 內部維護一個map,key爲當前線程名,value爲當前set的變量 requestHolder.set(id); } /** * 獲取數據 * @return */ public static Long getId(){ return requestHolder.get(); } /** * 移除變量信息 * 若是不移除,那麼變量不會釋放掉,會形成內存泄漏 * 在接口處理完之後進行處理(interceptor) */ public static void remove(){ requestHolder.remove(); } }
1.StringBuilder 線程不安全,StringBuffer線程安全
緣由:StringBuffer幾乎全部的方法都加了synchronized關鍵字。安全
2.SimpleDateFormat
SimpleDateFormat 在多線程共享使用的時候回拋出轉換異常,應該才用堆棧封閉在每次調用方法的時候在方法裏建立一個SimpleDateFormat。
另外一種方式是使用joda-time的DateTimeFormatter(推薦使用)。多線程
3.ArrayList,HashMap,HashSet等Collections併發
4.先檢查再執行高併發
// 非原子性 if(condition(a)){ handle(a); }
如今使用的比較少,主要使用併發容器。
ArrayList->Vector,Stack
HashMap->HashTable工具
Collections.synchronizedXXX (list,set,map)ui
J.U.C下的工具類:【併發編程】【JDK源碼】JDK的(J.U.C)java.util.concurrent包結構線程
ArrayList->CopyOnWriteArrayList
HashSet/TreeSet->CopyOnWriteArraySet/ConcurrentSkipListSet
HashMap/TreeMap->ConcurrentHashMap/ConcurrentSkipListMap
安全地共享對象包括如下幾種策略:
線程限制:一個被線程限制的對象,由線程獨佔,而且只能被佔有它的線程修改。
共享只讀:一個共享只讀的對象,在沒有額外同步的狀況下,能夠被多個線程併發訪問,可是任何線程都不能修改它。
線程安全對象:一個線程安全的對象或者容器,在內部經過同步機制來保證線程安全,因此其餘線程無需額外的同步就能夠經過公共接口隨意訪問它。
被守護對象:被守護對象只能經過獲取特定的鎖來訪問。
參考資料:
慕課網高併發實戰(六)- 線程安全策略