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

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

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

    kxbin
    成功留給有準(zhǔn)備的人
    posts - 10,  comments - 35,  trackbacks - 0

    大家使用多線程無(wú)非是為了提高性能,但如果多線程使用不當(dāng),不但性能提升不明顯,而且會(huì)使得資源消耗更大。下面列舉一下可能會(huì)造成多線程性能問(wèn)題的點(diǎn):

    • 死鎖
    • 過(guò)多串行化
    • 過(guò)多鎖競(jìng)爭(zhēng)
    • 切換上下文
    • 內(nèi)存同步

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

    死鎖

    關(guān)于死鎖,我們?cè)趯W(xué)習(xí)操作系統(tǒng)的時(shí)候就知道它產(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)盡量不要在釋放鎖之前競(jìng)爭(zhēng)其他鎖

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

    2)順序索取鎖資源

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

    3)嘗試定時(shí)鎖

    Java 5提供了更靈活的鎖工具,可以顯式地索取和釋放鎖。那么在索取鎖的時(shí)候可以設(shè)定一個(gè)超時(shí)時(shí)間,如果超過(guò)這個(gè)時(shí)間還沒(méi)索取到鎖,則不會(huì)繼續(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的方式來(lái)識(shí)別死鎖的方式,可以通過(guò)操作系統(tǒng)的命令來(lái)向JVM發(fā)送thread dump的信號(hào),這樣可以查詢哪些線程死鎖。

    過(guò)多串行化

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

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

    過(guò)多鎖競(jìng)爭(zhēng)

    過(guò)多鎖競(jìng)爭(zhēng)的危害是不言而喻的,那么看看有哪些辦法來(lái)降低鎖競(jìng)爭(zhēng)

    1)縮小鎖的范圍

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

    2)減小鎖的粒度

    Java 5提供了顯式鎖后,可以更為靈活的來(lái)保護(hù)共享變量。synchronized關(guān)鍵字(用在方法上)是默認(rèn)把整個(gè)對(duì)象作為鎖,實(shí)際上很多時(shí)候沒(méi)有必要用這么大一個(gè)鎖,這會(huì)導(dǎo)致這個(gè)類所有synchronized都得串行執(zhí)行??梢愿鶕?jù)真正需要保護(hù)的共享變量作為鎖,也可以使用更為精細(xì)的策略,目的就是要在真正需要串行的時(shí)候串行,舉一個(gè)例子:

     

    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. }  

     

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

    3)減少共享資源的依賴

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

    4)使用讀寫(xiě)分離鎖來(lái)替換獨(dú)占鎖

    Java 5提供了一個(gè)讀寫(xiě)分離鎖(ReadWriteLock)來(lái)實(shí)現(xiàn)讀-讀并發(fā),讀-寫(xiě)串行,寫(xiě)-寫(xiě)串行的特性。這種方式更進(jìn)一步提高了可并發(fā)性,因?yàn)橛行﹫?chǎng)景大部分是讀操作,因此沒(méi)必要串行工作。關(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. }  

     

    切換上下文

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

    內(nèi)存同步

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

    posted on 2011-10-13 16:04 kxbin 閱讀(326) 評(píng)論(0)  編輯  收藏 所屬分類: java基礎(chǔ)
    你恨一個(gè)人是因?yàn)槟銗?ài)他;你喜歡一個(gè)人,是因?yàn)樗砩嫌心銢](méi)有的;你討厭一個(gè)人是因?yàn)樗砩嫌心阌械臇|西;你經(jīng)常在別人面前批評(píng)某人,其實(shí)潛意識(shí)中是想接近他。

    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    常用鏈接

    留言簿(5)

    隨筆檔案

    文章分類

    文章檔案

    相冊(cè)

    收藏夾

    J2EE

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

    Linux

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

    數(shù)據(jù)庫(kù)

    電影網(wǎng)站

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

    搜索

    •  

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 美女被吸屁股免费网站| 免费一级成人毛片| 亚洲日韩乱码中文无码蜜桃臀| 成全动漫视频在线观看免费高清版下载| 亚洲中文字幕丝袜制服一区| 日产久久强奸免费的看| 亚洲成a人一区二区三区| 人妻无码中文字幕免费视频蜜桃| 全部免费a级毛片| 免费一级做a爰片久久毛片潮| 免费又黄又爽的视频| 免费的黄网站男人的天堂 | 亚洲三级视频在线观看| free哆啪啪免费永久| 亚洲另类古典武侠| 欧美日韩国产免费一区二区三区| 亚洲www77777| 免费毛片网站在线观看| 蜜臀亚洲AV无码精品国产午夜.| 国产成人免费高清在线观看| 黄人成a动漫片免费网站| 亚洲色偷偷狠狠综合网| 高清永久免费观看| 无码专区—VA亚洲V天堂| 最近免费视频中文字幕大全| 亚洲国产福利精品一区二区| 国产精品视频永久免费播放| 日本亚洲欧美色视频在线播放| 亚洲av区一区二区三| 久久www免费人成精品香蕉| 日韩va亚洲va欧洲va国产| 99久久久国产精品免费牛牛四川 | 两性色午夜免费视频| 久久久久亚洲精品无码系列| 久视频精品免费观看99| 国产亚洲福利在线视频| 啊v在线免费观看| 中文字幕在线免费看线人| 亚洲综合日韩中文字幕v在线| 福利免费观看午夜体检区| 亚洲αⅴ无码乱码在线观看性色|