<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

    前面的章節主要談談原子操作,至于與原子操作一些相關的問題或者說陷阱就放到最后的總結篇來整體說明。從這一章開始花少量的篇幅談談鎖機制。

    上一個章節中談到了鎖機制,并且針對于原子操作談了一些相關的概念和設計思想。接下來的文章中,盡可能的深入研究鎖機制,并且理解里面的原理和實際應用場合。

    盡管synchronized在語法上已經足夠簡單了,在JDK 5之前只能借助此實現,但是由于是獨占鎖,性能卻不高,因此JDK 5以后就開始借助于JNI來完成更高級的鎖實現。

    JDK 5中的鎖是接口java.util.concurrent.locks.Lock。另外java.util.concurrent.locks.ReadWriteLock提供了一對可供讀寫并發的鎖。根據前面的規則,我們從java.util.concurrent.locks.Lock的API開始。

     

    void lock();

    獲取鎖。

    如果鎖不可用,出于線程調度目的,將禁用當前線程,并且在獲得鎖之前,該線程將一直處于休眠狀態。

    void lockInterruptibly() throws InterruptedException;

    如果當前線程未被中斷,則獲取鎖。

    如果鎖可用,則獲取鎖,并立即返回。

    如果鎖不可用,出于線程調度目的,將禁用當前線程,并且在發生以下兩種情況之一以前,該線程將一直處于休眠狀態:

    • 鎖由當前線程獲得;或者
    • 其他某個線程中斷當前線程,并且支持對鎖獲取的中斷。

    如果當前線程:

    • 在進入此方法時已經設置了該線程的中斷狀態;或者
    • 在獲取鎖時被中斷,并且支持對鎖獲取的中斷,
    則將拋出 InterruptedException,并清除當前線程的已中斷狀態。

    Condition newCondition();

    返回綁定到此 Lock 實例的新 Condition 實例。下一小節中會重點談Condition,此處不做過多的介紹。

    boolean tryLock();

    僅在調用時鎖為空閑狀態才獲取該鎖。

    如果鎖可用,則獲取鎖,并立即返回值 true。如果鎖不可用,則此方法將立即返回值 false

    通常對于那些不是必須獲取鎖的操作可能有用。

    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;

    如果鎖在給定的等待時間內空閑,并且當前線程未被中斷,則獲取鎖。

    如果鎖可用,則此方法將立即返回值 true。如果鎖不可用,出于線程調度目的,將禁用當前線程,并且在發生以下三種情況之一前,該線程將一直處于休眠狀態:

    • 鎖由當前線程獲得;或者
    • 其他某個線程中斷當前線程,并且支持對鎖獲取的中斷;或者
    • 已超過指定的等待時間

    如果獲得了鎖,則返回值 true

    如果當前線程:

    • 在進入此方法時已經設置了該線程的中斷狀態;或者
    • 在獲取鎖時被中斷,并且支持對鎖獲取的中斷,
    則將拋出 InterruptedException,并會清除當前線程的已中斷狀態。

    如果超過了指定的等待時間,則將返回值 false。如果 time 小于等于 0,該方法將完全不等待。

    void unlock();

    釋放鎖。對應于lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,如果成功的話應該對應著一個unlock(),這樣可以避免死鎖或者資源浪費。

     

    相對于比較空洞的API,來看一個實際的例子。下面的代碼實現了一個類似于AtomicInteger的操作。

    package xylz.study.concurrency.lock;

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class AtomicIntegerWithLock {

        private int value;

        private Lock lock = new ReentrantLock();

        public AtomicIntegerWithLock() {
            super();
        }

        public AtomicIntegerWithLock(int value) {
            this.value = value;
        }

        public final int get() {
            lock.lock();
            try {
                return value;
            } finally {
                lock.unlock();
            }
        }

        public final void set(int newValue) {
            lock.lock();
            try {
                value = newValue;
            } finally {
                lock.unlock();
            }

        }

        public final int getAndSet(int newValue) {
            lock.lock();
            try {
                int ret = value;
                value = newValue;
                return ret;
            } finally {
                lock.unlock();
            }
        }

        public final boolean compareAndSet(int expect, int update) {
            lock.lock();
            try {
                if (value == expect) {
                    value = update;
                    return true;
                }
                return false;
            } finally {
                lock.unlock();
            }
        }

        public final int getAndIncrement() {
            lock.lock();
            try {
                return value++;
            } finally {
                lock.unlock();
            }
        }

        public final int getAndDecrement() {
            lock.lock();
            try {
                return value--;
            } finally {
                lock.unlock();
            }
        }

        public final int incrementAndGet() {
            lock.lock();
            try {
                return ++value;
            } finally {
                lock.unlock();
            }
        }

        public final int decrementAndGet() {
            lock.lock();
            try {
                return --value;
            } finally {
                lock.unlock();
            }
        }

        public String toString() {
            return Integer.toString(get());
        }
    }

    AtomicIntegerWithLock是線程安全的,此結構中大量使用了Lock對象的lock/unlock方法對。同樣可以看到的是對于自增和自減操作使用了++/--。之所以能夠保證線程安全,是因為Lock對象的lock()方法保證了只有一個線程能夠只有此鎖。需要說明的是對于任何一個lock()方法,都需要一個unlock()方法與之對于,通常情況下為了保證unlock方法總是能夠得到執行,unlock方法被置于finally塊中。另外這里使用了java.util.concurrent.locks.ReentrantLock.ReentrantLock對象,下一個小節中會具體描述此類作為Lock的唯一實現是如何設計和實現的。

    盡管synchronized實現Lock的相同語義,并且在語法上比Lock要簡單多,但是前者卻比后者的開銷要大得多。做一個簡單的測試。

    public static void main(String[] args) throws Exception{
         final int max = 10;
         final int loopCount = 100000;
         long costTime = 0;
         for (int m = 0; m < max; m++) {
             long start1 = System.nanoTime();
             final AtomicIntegerWithLock value1 = new AtomicIntegerWithLock(0);
             Thread[] ts = new Thread[max];
             for(int i=0;i<max;i++) {
                 ts[i] = new Thread() {
                     public void run() {
                         for (int i = 0; i < loopCount; i++) {
                             value1.incrementAndGet();
                         }
                     }
                 };
             }
             for(Thread t:ts) {
                 t.start();
             }
             for(Thread t:ts) {
                 t.join();
             }
             long end1 = System.nanoTime();
             costTime += (end1-start1);
         }
         System.out.println("cost1: " + (costTime));
         //
         System.out.println();
         costTime = 0;
         //
         final Object lock = new Object();
         for (int m = 0; m < max; m++) {
             staticValue=0;
             long start1 = System.nanoTime();
             Thread[] ts = new Thread[max];
             for(int i=0;i<max;i++) {
                 ts[i] = new Thread() {
                     public void run() {
                         for (int i = 0; i < loopCount; i++) {
                             synchronized(lock) {
                                 ++staticValue;
                             }
                         }
                     }
                 };
             }
             for(Thread t:ts) {
                 t.start();
             }
             for(Thread t:ts) {
                 t.join();
             }
             long end1 = System.nanoTime();
             costTime += (end1-start1);
         }
         //
         System.out.println("cost2: " + (costTime));
    }


    static int staticValue = 0;

     

    在這個例子中每次啟動10個線程,每個線程計算100000次自增操作,重復測試10次,下面是某此測試的結果:

    cost1: 624071136

    cost2: 2057847833

    盡管上面的例子不是非常正式的測試案例,但上面的例子在于說明,Lock的性能比synchronized的要好得多。如果可以的話總是使用Lock替代synchronized是一個明智的選擇。



    ©2009-2014 IMXYLZ |求賢若渴
    posted on 2010-07-05 13:37 imxylz 閱讀(42228) 評論(11)  編輯  收藏 所屬分類: J2EE

    評論

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2010-08-10 11:09 strong liu
    呵呵,這個系列寫的真不錯
    不過有個小問題,好像在jdk6中, synchronized和lock的開銷差不多了吧
    另外,文中的例子,我把這兩個變量改成
    final int max = 100;
    final int loopCount = 10000;
    之后,得到了截然相反的結果:
    cost1: 5410924000
    cost2: 4069950000

    ------------------
    Mac OS x 10.6
    jdk 1.6  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2010-11-03 07:54 hephaistos
    呵呵,我測試了下
    final int max = 100;
    final int loopCount = 1000;
    --------------------------------
    cost1: 861453448

    cost2: 1536178939
    --------------------------------
    final int max = 100;
    final int loopCount = 10000;
    --------------------------------
    cost1: 4082896955

    cost2: 15547632560
    --------------------------------
    Win7 x64
    JDK 1.6
    i7-850

    應該樓上的相反結果是由于cpu的多線程運算能力不同而有所差異吧  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2010-11-03 09:24 xylz
    @hephaistos
    要充分利用多核CPU的特性,需要開啟-server模式,這樣效果會比較明顯。  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2011-03-07 13:04 snake
    我覺得這是由于測試方法不太全面導致的把
    根據《Java Concurrency in Practice》中的描述,從1.6開始,固有鎖的效率跟重入鎖的效率就差不多了

    這是他的測試方法,請參考一下:(該方法是測試各個map的,他測試重入鎖跟固有鎖的方法也是一樣的)
    Figure 11.3 illustrates the differences in scalability between several Map implementations: ConcurrentHashMap, ConcurrentSkipListMap, and HashMap and treeMap wrapped with synchronizedMap. The first two are thread-safe by design; the latter two are made thread-safe by the synchronized wrapper. In each run, N threads concurrently execute a tight loop that selects a random key and attempts to retrieve the value corresponding to that key. If the value is not present, it is added to the Map with probability p = .6, and if it is present, is removed with probability p = .02. The tests were run under a pre-release build of Java 6 on an 8-way Sparc V880, and the graph displays throughput normalized to the onethread case for ConcurrentHashMap. (The scalability gap between the concurrent and synchronized collections is even larger on Java 5.0.)
      回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2012-02-27 19:43 紅淚
    這個系列不錯,最近在看多線程,就看到這個了,呵呵。  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2012-10-11 11:46 nestle
    請問blog主你這里的休眠指的是什么  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1[未登錄] 2013-03-03 14:58 teasp
    synchronized使用的內置鎖和ReentrantLock這種顯式鎖在java6以后性能沒多大差異,在更新的版本中內置鎖只會比顯式鎖性能更好。這兩種鎖都是獨占鎖,java5以前內置鎖性能低的原因是它沒做任何優化,直接使用系統的互斥體來獲取鎖。顯式鎖除了CAS的時候利用的是本地代碼以外,其它的部分都是Java代碼實現的,在后續版本的Java中,顯式鎖不太可能會比內置鎖好,只會更差。使用顯式鎖的唯一理由是要利用它更多的功能。  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2014-06-19 13:19 徐敏
    我想知道不是已經有原子操作了嗎?為什么還要使用這種獨占鎖的機制的,希望樓主解答一下。  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2014-06-19 13:24 imxylz
    @徐敏
    鎖數據結構的實現,便于程序開發。鎖也是基于CAS原子操作實現的,但是CAS難以使用。  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1[未登錄] 2014-07-03 14:47 巴比豬
    我的結果也是截然相反,用關鍵字的反而更快
    private static class SynchroInteger{
    private int i;

    synchronized int incrementAndGet(){
    i++;
    return i;
    }
    }  回復  更多評論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機制 part 1 2014-07-03 15:06 imxylz
    JDK6以后對synchronized進行了很多優化,而Lock基本上沒有什么可優化的空間。在某些操作系統和JDK實現上,這種簡單的測試結果可能都不一樣。但通常情況下,高并發和長時間任務執行上,Lock的性能比synchronized的更優。  回復  更多評論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 中文在线观看永久免费| 看亚洲a级一级毛片| 巨胸喷奶水www永久免费| 四虎永久免费网站免费观看| 亚洲综合一区二区三区四区五区| 性xxxxx免费视频播放 | 久久91亚洲人成电影网站| 一级美国片免费看| 亚洲真人日本在线| 中国好声音第二季免费播放| 亚洲色爱图小说专区| 国产成人免费视频| 97久久精品亚洲中文字幕无码| 亚洲免费二区三区| 亚洲欧美日韩一区二区三区在线| 国产精品免费综合一区视频| 日韩电影免费在线观看网址| 区久久AAA片69亚洲| 三年片在线观看免费大全电影| 亚洲国产精品综合久久2007| 午夜一级免费视频| 日本一区二区三区在线视频观看免费 | 四虎永久免费地址在线观看| 日本高清免费中文在线看| 亚洲欧洲精品无码AV| 久久99国产乱子伦精品免费| 亚洲熟女乱色一区二区三区| 亚洲av片一区二区三区| 毛片在线播放免费观看| 亚洲videosbestsex日本| 免费中文字幕在线| 日韩免费无码视频一区二区三区| 国产成人亚洲合集青青草原精品| 麻豆精品国产免费观看| 成人免费一区二区三区 | 中文字幕亚洲综合久久男男| 蜜桃成人无码区免费视频网站| 国产亚洲精品成人AA片| 在线观看亚洲天天一三视| 国产h肉在线视频免费观看| 亚洲AV无码片一区二区三区|