1. 【強制】獲取單例對象需要保證線程安全,其中的方法也要保證線程安全。說明:資源驅動類、工具類、單例工廠類都需要注意。
2. 【強制】創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯。
##### 正例:
public class TimerTaskThread extends Thread { public TimerTaskThread() { super.setName("TimerTaskThread"); ... }
1. 【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創建線程。
說明:使用線程池的好處是減少在創建和銷毀線程上所花的時間以及系統資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或者 “過度切換”的問題。
1. 【強制】線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。
說明:Executors返回的線程池對象的弊端如下:
1) FixedThreadPool和SingleThreadPool: 允許的請求隊列長度為Integer.MAX\_VALUE,可能會堆積大量的請求,從而導致OOM。
2) CachedThreadPool和ScheduledThreadPool: 允許的創建線程數量為Integer.MAX\_VALUE,可能會創建大量的線程,從而導致OOM。
1. 【強制】SimpleDateFormat 是線程不安全的類,一般不要定義為static變量,如果定義為 static,必須加鎖,或者使用DateUtils工具類。
正例:注意線程安全,使用DateUtils。亦推薦如下處理:
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); }
};
說明:如果是JDK8的應用,可以使用Instant代替Date,LocalDateTime代替Calendar, DateTimeFormatter代替SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe。
1. 【強制】高并發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。
說明:盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調用 RPC 方法。
1. 【強制】對多個資源、數據庫表、對象同時加鎖時,需要保持一致的加鎖順序,否則可能會造成死鎖。
說明:線程一需要對表A、B、C依次全部加鎖后才可以進行更新操作,那么線程二的加鎖順序也必須是A、B、C,否則可能出現死鎖。
1. 【強制】并發修改同一記錄時,避免更新丟失,需要加鎖。要么在應用層加鎖,要么在緩存加
鎖,要么在數據庫層使用樂觀鎖,使用version作為更新依據。
說明:如果每次訪問沖突概率小于20%,推薦使用樂觀鎖,否則使用悲觀鎖。樂觀鎖的重試次數不得小于3次。
1. 【強制】多線程并行處理定時任務時,Timer運行多個TimeTask時,只要其中之一沒有捕獲
拋出的異常,其它任務便會自動終止運行,使用ScheduledExecutorService則沒有這個問題。
1. 【推薦】使用CountDownLatch進行異步轉同步操作,每個線程退出前必須調用countDown 方法,線程執行代碼注意catch異常,確保countDown方法被執行到,避免主線程無法執行至await方法,直到超時才返回結果。
說明:注意,子線程拋出異常堆棧,不能在主線程try-catch到。
1. 【推薦】避免Random實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一
seed 導致的性能下降。
說明:Random實例包括java.util.Random 的實例或者 Math.random()的方式。
正例:在JDK7之后,可以直接使用API ThreadLocalRandom,而在 JDK7之前,需要編碼保證每個線程持有一個實例。
1. 【推薦】在并發場景下,通過雙重檢查鎖(double-checked locking)實現延遲初始化的優化問題隱患(可參考 The "Double-Checked Locking is Broken" Declaration),推薦解決方案中較為簡單一種(適用于JDK5及以上版本),將目標屬性聲明為 volatile型。
###### 反例:
class Singleton { private Helper helper = null; public Helper getHelper() {
if (helper == null) synchronized(this) { if (helper == null) helper = new Helper();
}
return helper;
}
// other methods and fields...
}
1. 【參考】volatile解決多線程內存不可見問題。對于一寫多讀,是可以解決變量同步問題,但是如果多寫,同樣無法解決線程安全問題。如果是count++操作,使用如下類實現:
AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是JDK8,推薦使用LongAdder對象,比AtomicLong性能更好(減少樂觀鎖的重試次數)。
1. 【參考】 HashMap在容量不夠進行resize時由于高并發可能出現死鏈,導致CPU飆升,在開發過程中可以使用其它數據結構或加鎖來規避此風險。
2. 【參考】ThreadLocal無法解決共享對象的更新問題,ThreadLocal對象建議使用static
修飾。這個變量是針對一個線程內所有操作共享的,所以設置為靜態變量,所有此類實例共享此靜態變量 ,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,所有此類的對象(只要是這個線程內定義的)都可以操控這個變量。
- 一、編程規約????1
- (一) 命名風格????1
- (二) 常量定義????3
- (三) 代碼格式????4
- (四) OOP規約????6
- (五) 集合處理????9
- (六) 并發處理????12
- (七) 控制語句????14
- (八) 注釋規約????16
- (九) 其它????17
- 二、異常日志????18
- (一) 異常處理????18
- (二) 日志規約????19
- 三、單元測試????21
- 四、安全規約????23
- 五、MySQL數據庫????24
- (一) 建表規約????24
- (二) 索引規約????25
- (三) SQL語句????27
- (四) ORM映射????28
- 六、工程結構????30
- (一) 應用分層????30
- (二) 二方庫依賴????31
- (三) 服務器????32
- 附1:版本歷史????34
- 附2:本手冊專有名詞????35