1. 多線程場景下儘可能使用併發容器代替同步容器java
(如ConcurrentHashMap代替同步且基於散列的Map, 遍歷操做爲主要操做的狀況下用CopyOnWriteArrayList代替同步的List)數組
ConcurrentHashMap:分段鎖機制,多線程條件下優於HashMap+synchronized的組合方式;
CopyOnWriteArrayList: 每次修改時都會建立並從新發佈一個新的容器副本,從而實現可變性。容器的迭代器保留一個指向底層基礎數組的引用,這個數組當前位於迭代器的起始位置,因爲他不會被修改,
因此在對其進行同步時只需確保數組內容的可見性。
2. 避免死鎖
a)儘可能不要在釋放鎖以前競爭其餘鎖:通常能夠經過細化同步方法來實現,只在真正須要保護共享資源的地方去拿鎖,並儘快釋放鎖,這樣能夠有效下降在同步方法裏調用其餘同步方法 的狀況
b)順序索取鎖資源: 若是實在沒法避免嵌套索取鎖資源,則須要制定一個索取鎖資源的策略,先規劃好有哪些鎖,而後各個線程按照一個順序去索取
c)嘗試定時鎖: Java 5提供了更靈活的鎖工具,能夠顯式地索取和釋放鎖。那麼在索取鎖的時候能夠設定一個超時時間,若是超過這個時間還沒索取到鎖,則不會繼續堵塞而是放棄這次任務,以下:安全
public boolean trySendOnSharedLine(String message, long timeout, TimeUnit unit) throws InterruptedException { long nanosToLock = unit.toNanos(timeout) - estimatedNanosToSend(message); if (!lock.tryLock(nanosToLock, NANOSECONDS)){ return false; } try { return sendOnSharedLine(message); } finally { lock.unlock(); } }
這樣能夠效打破死鎖條件。
3. Amdahl定理:
speedup<= 1/(F+(1-F)/N)
其中,F是串行化比例,N是處理器數量,由上可知,只有儘量減小串行化,才能最大化地提升可擴展能力。下降串行化的關鍵就是下降鎖競爭,當不少並行任務掛在鎖的獲取上,就是串行化的表現.
4. 下降鎖競爭
1)縮小鎖的範圍
儘可能縮小鎖保護的範圍,快進快出,所以儘可能不要直接在方法上使用synchronized關鍵字,而只是在真正須要線程安全保護的地方使用
2)減少鎖的粒度
儘可能避免大段的synchronize代碼塊
3)減小共享資源的依賴
在多線程開發中儘可能減小對共享資源的依賴,好比對象池的技術應該慎重考慮,新的JVM對新建對象以作了足夠的優化,性能很是好,若是用對象池不但不能提升多少性能,反而 會由於鎖競爭致使下降線程的可併發性。
4)使用讀寫分離鎖來替換獨佔鎖
Java 5提供了一個讀寫分離鎖(ReadWriteLock)來實現讀-讀併發,讀-寫串行,寫-寫串行的特性。這種方式更進一步提升了可併發性,由於有些場景大部分是讀操做,所以不必串行工做。
5. 切換上下文
線程比較多的時候,操做系統切換線程上下文的性能消耗是不能忽略的,
6. 內存同步
當使用到synchronized、volatile或Lock的時候,都會爲了保證可見性致使更多的內存同步,這就沒法享受到JMM結構帶來了性能優化。
7. 適當使用同步工具類
(1) 閉鎖(CountDownLatch): 延遲線程的進度直到其達到終止狀態,用來確保某些活動直到其餘活動都完成後才繼續執行;一次性對象,一旦進入終止狀態,就不能被重置;
(2) FutureTask: 可生成結果的Callable,若是有結果可用,那麼FutureTask.get將當即返回結果,不然它會一直阻塞,直到結果計算出來再將其返回。
(3) 信號量(Semaphore):用來控制同時訪問某個特定資源的操做數量,或者同時某個指定操做的數量,Semaphore還能夠用來實現某種資源池,或者對容器施加邊界。
(4) 柵欄(Barrier): 相似於閉鎖,區別在於全部線程必須同時到達柵欄位置才能繼續執行,閉鎖用於等待事件,而柵欄用於等待其餘線程。可被重置用於下次使用。兩種實現方式:CyclicBarrier,Exchanger性能優化
8. 實際狀況中,應儘量的使用現有的線程安全對象(例如AtomicInteger)來管理類的狀態多線程
9. 在多線程程序中使用共享且可變的long和double等類型的變量也是不安全的,除非用volatile來聲明它們,或者用鎖保護起來。併發