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

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

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

    xylz,imxylz

    關注后端架構、中間件、分布式和并發編程

       :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評論 :: 0 Trackbacks

    常見的并發陷阱

    volatile

    volatile只能強調數據的可見性,并不能保證原子操作和線程安全,因此volatile不是萬能的。參考指令重排序

    volatile最常見于下面兩種場景。

    a. 循環檢測機制

    volatile boolean done = false;


        while( ! done ){
            dosomething();
        }


    b. 單例模型 (http://www.tkk7.com/xylz/archive/2009/12/18/306622.html)

    public class DoubleLockSingleton {

        
    private static volatile DoubleLockSingleton instance = null;

        
    private DoubleLockSingleton() {
        }

        
    public static DoubleLockSingleton getInstance() {
            
    if (instance == null) {
                
    synchronized (DoubleLockSingleton.class) {
                    
    if (instance == null) {
                        instance 
    = new DoubleLockSingleton();
                    }
                }
            }
            
    return instance;
        }
    }

     


    synchronized/Lock

    看起來Lock有更好的性能以及更靈活的控制,是否完全可以替換synchronized?

    鎖的一些其它問題中說過,synchronized的性能隨著JDK版本的升級會越來越高,而Lock優化的空間受限于CPU的性能,很有限。另外JDK內部的工具(線程轉儲)對synchronized是有一些支持的(方便發現死鎖等),而對Lock是沒有任何支持的。

    也就說簡單的邏輯使用synchronized完全沒有問題,隨著機器的性能的提高,這點開銷是可以忽略的。而且從代碼結構上講是更簡單的。簡單就是美。

    對于復雜的邏輯,如果涉及到讀寫鎖、條件變量、更高的吞吐量以及更靈活、動態的用法,那么就可以考慮使用Lock。當然這里尤其需要注意Lock的正確用法。

    Lock lock = 
    lock.lock();
    try{
        //do something
    }finally{
        lock.unlock();
    }


    一定要將Lock的釋放放入finally塊中,否則一旦發生異常或者邏輯跳轉,很有可能會導致鎖沒有釋放,從而發生死鎖。而且這種死鎖是難以排查的。

    如果需要synchronized無法做到的嘗試鎖機制,或者說擔心發生死鎖無法自恢復,那么使用tryLock()是一個比較明智的選擇的。

    Lock lock = 
    if(lock.tryLock()){
        try{
            //do something
        }finally{
            lock.unlock();
        }
    }

     

    甚至可以使用獲取鎖一段時間內超時的機制Lock.tryLock(long,TimeUnit)。 鎖的使用可以參考前面文章的描述和建議。

    鎖的邊界

    一個流行的錯誤是這樣的。

    ConcurrentMap<String,String> map = new ConcurrentHashMap<String,String>();

    if(!map.containsKey(key)){
        map.put(key,value);
    }


    看起來很合理的,對于一個線程安全的Map實現,要存取一個不重復的結果,先檢測是否存在然后加入。 其實我們知道兩個原子操作和在一起的指令序列不代表就是線程安全的。 割裂的多個原子操作放在一起在多線程的情況下就有可能發生錯誤。

    實際上ConcurrentMap提供了putIfAbsent(K, V)的“原子操作”機制,這等價于下面的邏輯:

    if(map.containsKey(key)){
        return map.get(key);
    }else{
        return map.put(k,v);
    }


    除了putIfAbsent還有replace(K, V)以及replace(K, V, V)兩種機制來完成組合的操作。

    提到Map,這里有一篇談HashMap讀寫并發的問題。

    構造函數啟動線程

    下面的實例是在構造函數中啟動一個線程。

    public class Runner{
       int x,y;
       Thread thread;
       public Runner(){
          this.x=1;
          this.y=2;
          this.thread=new MyThread();
          this.thread.start();
       }
    }


    這里可能存在的陷阱是如果此類被繼承,那么啟動的線程可能無法正確讀取子類的初始化操作。

    因此一個簡單的原則是,禁止在構造函數中啟動線程,可以考慮但是提供一個方法來啟動線程。如果非要這么做,最好將類設置為final,禁止繼承。

    丟失通知的問題

    這篇文章里面提到過notify丟失通知的問題。

    對于wait/notify/notifyAll以及await/singal/singalAll,如果不確定到底是否能夠正確的收到消息,擔心丟失通知,簡單一點就是總是通知所有。

    如果擔心只收到一次消息,使用循環一直監聽是不錯的選擇。

    非常主用性能的系統,可能就需要區分到底是通知單個還是通知所有的掛起者。

    線程數

    并不是線程數越多越好,在下一篇文章里面會具體了解下性能和可伸縮性。 簡單的說,線程數多少沒有一個固定的結論,受限于CPU的內核數,IO的性能以及依賴的服務等等。因此選擇一個合適的線程數有助于提高吞吐量。

    對于CPU密集型應用,線程數和CPU的內核數一致有助于提高吞吐量,所有CPU都很繁忙,效率就很高。 對于IO密集型應用,線程數受限于IO的性能,某些時候單線程可能比多線程效率更高。但通常情況下適當提高線程數,有利于提高網絡IO的效率,因為我們總是認為網絡IO的效率比較低。

    對于線程池而言,選擇合適的線程數以及任務隊列是提高線程池效率的手段。

    public ThreadPoolExecutor(
        int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler)

     


    對于線程池來說,如果任務總是有積壓,那么可以適當提高corePoolSize大小;如果機器負載較低,那么可以適當提高maximumPoolSize的大小;任務隊列不長的情況下減小keepAliveTime的時間有助于降低負載;另外任務隊列的長度以及任務隊列的拒絕策略也會對任務的處理有一些影響。

     



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2011-12-30 17:25 imxylz 閱讀(6920) 評論(0)  編輯  收藏 所屬分類: Java Concurrency

    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 中文字幕一区二区免费| 免费大片黄在线观看| 1000部无遮挡拍拍拍免费视频观看 | 亚洲精品电影在线| 5g影院5g天天爽永久免费影院| 亚洲av无码国产精品夜色午夜| 免费人成在线观看视频高潮| 久久91亚洲精品中文字幕| 七色永久性tv网站免费看| 91精品国产亚洲爽啪在线观看| 99精品视频在线视频免费观看 | 日本系列1页亚洲系列| 免费萌白酱国产一区二区| 特级做a爰片毛片免费看| 亚洲男女内射在线播放| 免费看无码特级毛片| 亚洲欧洲日产国产最新| 成年男女免费视频网站| 黄色毛片视频免费| 国产亚洲av片在线观看16女人| 在线成人爽a毛片免费软件| 亚洲av无码不卡久久| 国产男女猛烈无遮挡免费视频| 一级做a免费视频观看网站| 亚洲成a人片77777kkkk| 国产人在线成免费视频| 色偷偷噜噜噜亚洲男人| 激情综合色五月丁香六月亚洲| 99久久精品国产免费| 老牛精品亚洲成av人片| 亚洲AV日韩AV永久无码绿巨人 | 18pao国产成视频永久免费| 亚洲欧洲无码AV不卡在线| 国产精品亚洲w码日韩中文| 在线观看的免费网站无遮挡| 亚洲AV无码AV日韩AV网站| 亚洲AV无码久久| 午夜视频在线观看免费完整版| 中文字幕在线视频免费| 国产成人亚洲精品| 国产美女亚洲精品久久久综合|