<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kxbin
    成功留給有準備的人
    posts - 10,  comments - 35,  trackbacks - 0

    大家使用多線程無非是為了提高性能,但如果多線程使用不當,不但性能提升不明顯,而且會使得資源消耗更大。下面列舉一下可能會造成多線程性能問題的點:

    • 死鎖
    • 過多串行化
    • 過多鎖競爭
    • 切換上下文
    • 內(nèi)存同步

    下面分別解析以上性能隱患

    死鎖

    關(guān)于死鎖,我們在學習操作系統(tǒng)的時候就知道它產(chǎn)生的原因和危害,這里就不從原理上去累述了,可以從下面的代碼和圖示重溫一下死鎖產(chǎn)生的原因:

     

    1. public class LeftRightDeadlock {  
    2.     private final Object left = new Object();  
    3.     private final Object right = new Object();  
    4.     public void leftRight() {  
    5.         synchronized (left) {  
    6.             synchronized (right) {  
    7.                 doSomething();  
    8.             }  
    9.         }  
    10.     }  
    11.     public void rightLeft() {  
    12.         synchronized (right) {  
    13.             synchronized (left) {  
    14.                 doSomethingElse();  
    15.             }  
    16.         }  
    17.     }  
    18. }  

     

    預(yù)防和處理死鎖的方法:

    1)盡量不要在釋放鎖之前競爭其他鎖

    一般可以通過細化同步方法來實現(xiàn),只在真正需要保護共享資源的地方去拿鎖,并盡快釋放鎖,這樣可以有效降低在同步方法里調(diào)用其他同步方法的情況

    2)順序索取鎖資源

    如果實在無法避免嵌套索取鎖資源,則需要制定一個索取鎖資源的策略,先規(guī)劃好有哪些鎖,然后各個線程按照一個順序去索取,不要出現(xiàn)上面那個例子中不同順序,這樣就會有潛在的死鎖問題

    3)嘗試定時鎖

    Java 5提供了更靈活的鎖工具,可以顯式地索取和釋放鎖。那么在索取鎖的時候可以設(shè)定一個超時時間,如果超過這個時間還沒索取到鎖,則不會繼續(xù)堵塞而是放棄此次任務(wù),示例代碼如下:

     

    1. public boolean trySendOnSharedLine(String message,  
    2.                                    long timeout, TimeUnit unit)  
    3.                                    throws InterruptedException {  
    4.     long nanosToLock = unit.toNanos(timeout)  
    5.                      - estimatedNanosToSend(message);  
    6.     if (!lock.tryLock(nanosToLock, NANOSECONDS))  
    7.         return false;  
    8.     try {  
    9.         return sendOnSharedLine(message);  
    10.     } finally {  
    11.         lock.unlock();  
    12.     }  
    13. }  

     

    這樣可以有效打破死鎖條件。

    4)檢查死鎖

    JVM采用thread dump的方式來識別死鎖的方式,可以通過操作系統(tǒng)的命令來向JVM發(fā)送thread dump的信號,這樣可以查詢哪些線程死鎖。

    過多串行化

    用多線程實際上就是想并行地做事情,但這些事情由于某些依賴性必須串行工作,導致很多環(huán)節(jié)得串行化,這實際上很局限系統(tǒng)的可擴展性,就算加CPU加線程,但性能卻沒有線性增長。有個Amdahl定理可以說明這個問題:

    其中,F(xiàn)是串行化比例,N是處理器數(shù)量,由上可知,只有盡可能減少串行化,才能最大化地提高可擴展能力。降低串行化的關(guān)鍵就是降低鎖競爭,當很多并行任務(wù)掛在鎖的獲取上,就是串行化的表現(xiàn)

    過多鎖競爭

    過多鎖競爭的危害是不言而喻的,那么看看有哪些辦法來降低鎖競爭

    1)縮小鎖的范圍

    前面也談到這一點,盡量縮小鎖保護的范圍,快進快出,因此盡量不要直接在方法上使用synchronized關(guān)鍵字,而只是在真正需要線程安全保護的地方使用

    2)減小鎖的粒度

    Java 5提供了顯式鎖后,可以更為靈活的來保護共享變量。synchronized關(guān)鍵字(用在方法上)是默認把整個對象作為鎖,實際上很多時候沒有必要用這么大一個鎖,這會導致這個類所有synchronized都得串行執(zhí)行。可以根據(jù)真正需要保護的共享變量作為鎖,也可以使用更為精細的策略,目的就是要在真正需要串行的時候串行,舉一個例子:

     

    1. public class StripedMap {  
    2.     // Synchronization policy: buckets[n] guarded by locks[n%N_LOCKS]  
    3.     private static final int N_LOCKS = 16;  
    4.     private final Node[] buckets;  
    5.     private final Object[] locks;  
    6.     private static class Node { ... }  
    7.     public StripedMap(int numBuckets) {  
    8.         buckets = new Node[numBuckets];  
    9.         locks = new Object[N_LOCKS];  
    10.         for (int i = 0; i < N_LOCKS; i++)  
    11.             locks[i] = new Object();  
    12.     }  
    13.     private final int hash(Object key) {  
    14.         return Math.abs(key.hashCode() % buckets.length);  
    15.     }  
    16.     public Object get(Object key) {  
    17.         int hash = hash(key);  
    18.         synchronized (locks[hash % N_LOCKS]) {  
    19.             for (Node m = buckets[hash]; m != null; m = m.next)  
    20.                 if (m.key.equals(key))  
    21.                     return m.value;  
    22.         }  
    23.         return null;  
    24.     }  
    25.     public void clear() {  
    26.         for (int i = 0; i < buckets.length; i++) {  
    27.             synchronized (locks[i % N_LOCKS]) {  
    28.                 buckets[i] = null;  
    29.             }  
    30.         }  
    31.     }  
    32.     ...  
    33. }  

     

    上面這個例子是通過hash算法來把存取的值所對應(yīng)的hash值來作為鎖,這樣就只需要對hash值相同的對象存取串行化,而不是像HashTable那樣對任何對象任何操作都串行化。

    3)減少共享資源的依賴

    共享資源是競爭鎖的源頭,在多線程開發(fā)中盡量減少對共享資源的依賴,比如對象池的技術(shù)應(yīng)該慎重考慮,新的JVM對新建對象以做了足夠的優(yōu)化,性能非常好,如果用對象池不但不能提高多少性能,反而會因為鎖競爭導致降低線程的可并發(fā)性。

    4)使用讀寫分離鎖來替換獨占鎖

    Java 5提供了一個讀寫分離鎖(ReadWriteLock)來實現(xiàn)讀-讀并發(fā),讀-寫串行,寫-寫串行的特性。這種方式更進一步提高了可并發(fā)性,因為有些場景大部分是讀操作,因此沒必要串行工作。關(guān)于ReadWriteLock的具體使用可以參加一下示例:

     

    1. public class ReadWriteMap<K,V> {  
    2.     private final Map<K,V> map;  
    3.     private final ReadWriteLock lock = new ReentrantReadWriteLock();  
    4.     private final Lock r = lock.readLock();  
    5.     private final Lock w = lock.writeLock();  
    6.     public ReadWriteMap(Map<K,V> map) {  
    7.         this.map = map;  
    8.     }  
    9.     public V put(K key, V value) {  
    10.         w.lock();  
    11.         try {  
    12.             return map.put(key, value);  
    13.         } finally {  
    14.             w.unlock();  
    15.         }  
    16.     }  
    17.     // Do the same for remove(), putAll(), clear()  
    18.     public V get(Object key) {  
    19.         r.lock();  
    20.         try {  
    21.             return map.get(key);  
    22.         } finally {  
    23.             r.unlock();  
    24.         }  
    25.     }  
    26.     // Do the same for other read-only Map methods  
    27. }  

     

    切換上下文

    線程比較多的時候,操作系統(tǒng)切換線程上下文的性能消耗是不能忽略的,在構(gòu)建高性能web之路------web服務(wù)器長連接 可以看出在進程切換上的代價,當然線程會更輕量一些,不過道理是類似的

    內(nèi)存同步

    當使用到synchronized、volatile或Lock的時候,都會為了保證可見性導致更多的內(nèi)存同步,這就無法享受到JMM結(jié)構(gòu)帶來了性能優(yōu)化。

    posted on 2011-10-13 16:04 kxbin 閱讀(330) 評論(0)  編輯  收藏 所屬分類: java基礎(chǔ)
    你恨一個人是因為你愛他;你喜歡一個人,是因為他身上有你沒有的;你討厭一個人是因為他身上有你有的東西;你經(jīng)常在別人面前批評某人,其實潛意識中是想接近他。

    <2025年7月>
    293012345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    常用鏈接

    留言簿(5)

    隨筆檔案

    文章分類

    文章檔案

    相冊

    收藏夾

    J2EE

    java技術(shù)網(wǎng)站

    Linux

    平時常去的網(wǎng)站

    數(shù)據(jù)庫

    電影網(wǎng)站

    網(wǎng)站設(shè)計

    搜索

    •  

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲精品V天堂中文字幕| 青青草原1769久久免费播放| 4399影视免费观看高清直播| 亚洲精品A在线观看| 亚洲AV无码久久久久网站蜜桃 | 亚洲国产精品yw在线观看| 亚洲免费一区二区| 日本大片在线看黄a∨免费| 亚洲欧洲自拍拍偷综合| 成在线人免费无码高潮喷水| 国产网站在线免费观看| 亚洲三级视频在线| 日韩精品无码一区二区三区免费| 久久精品国产亚洲精品| 精品久久久久亚洲| 毛片a级毛片免费播放100| 久久久久久亚洲AV无码专区| 成人网站免费大全日韩国产| 免费看小12萝裸体视频国产| 亚洲中文字幕乱码熟女在线| 亚洲视频免费在线播放| 亚洲AV无码欧洲AV无码网站| 一级毛片免费一级直接观看| 国产乱色精品成人免费视频| 亚洲中文字幕久久精品无码A| 91热成人精品国产免费| 亚洲日本精品一区二区| 野花香高清在线观看视频播放免费 | 精品免费国产一区二区| 亚洲乱码一二三四区国产| 免费A级毛片无码A∨中文字幕下载| 亚洲色欲久久久综合网| 一级特黄aaa大片免费看| 免费日本黄色网址| 国产综合成人亚洲区| 最新69国产成人精品免费视频动漫 | 国产精品免费在线播放| 亚洲精品成人在线| 男人和女人高潮免费网站| 国产成人青青热久免费精品| 亚洲精品无码久久久久A片苍井空|