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

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

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

    xylz,imxylz

    關(guān)注后端架構(gòu)、中間件、分布式和并發(fā)編程

       :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      111 隨筆 :: 10 文章 :: 2680 評(píng)論 :: 0 Trackbacks

    前面的章節(jié)主要談?wù)勗硬僮鳎劣谂c原子操作一些相關(guān)的問(wèn)題或者說(shuō)陷阱就放到最后的總結(jié)篇來(lái)整體說(shuō)明。從這一章開(kāi)始花少量的篇幅談?wù)勬i機(jī)制。

    上一個(gè)章節(jié)中談到了鎖機(jī)制,并且針對(duì)于原子操作談了一些相關(guān)的概念和設(shè)計(jì)思想。接下來(lái)的文章中,盡可能的深入研究鎖機(jī)制,并且理解里面的原理和實(shí)際應(yīng)用場(chǎng)合。

    盡管synchronized在語(yǔ)法上已經(jīng)足夠簡(jiǎn)單了,在JDK 5之前只能借助此實(shí)現(xiàn),但是由于是獨(dú)占鎖,性能卻不高,因此JDK 5以后就開(kāi)始借助于JNI來(lái)完成更高級(jí)的鎖實(shí)現(xiàn)。

    JDK 5中的鎖是接口java.util.concurrent.locks.Lock。另外java.util.concurrent.locks.ReadWriteLock提供了一對(duì)可供讀寫并發(fā)的鎖。根據(jù)前面的規(guī)則,我們從java.util.concurrent.locks.Lock的API開(kāi)始。

     

    void lock();

    獲取鎖。

    如果鎖不可用,出于線程調(diào)度目的,將禁用當(dāng)前線程,并且在獲得鎖之前,該線程將一直處于休眠狀態(tài)。

    void lockInterruptibly() throws InterruptedException;

    如果當(dāng)前線程未被中斷,則獲取鎖。

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

    如果鎖不可用,出于線程調(diào)度目的,將禁用當(dāng)前線程,并且在發(fā)生以下兩種情況之一以前,該線程將一直處于休眠狀態(tài):

    • 鎖由當(dāng)前線程獲得;或者
    • 其他某個(gè)線程中斷當(dāng)前線程,并且支持對(duì)鎖獲取的中斷。

    如果當(dāng)前線程:

    • 在進(jìn)入此方法時(shí)已經(jīng)設(shè)置了該線程的中斷狀態(tài);或者
    • 在獲取鎖時(shí)被中斷,并且支持對(duì)鎖獲取的中斷,
    則將拋出 InterruptedException,并清除當(dāng)前線程的已中斷狀態(tài)。

    Condition newCondition();

    返回綁定到此 Lock 實(shí)例的新 Condition 實(shí)例。下一小節(jié)中會(huì)重點(diǎn)談Condition,此處不做過(guò)多的介紹。

    boolean tryLock();

    僅在調(diào)用時(shí)鎖為空閑狀態(tài)才獲取該鎖。

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

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

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

    如果鎖在給定的等待時(shí)間內(nèi)空閑,并且當(dāng)前線程未被中斷,則獲取鎖。

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

    • 鎖由當(dāng)前線程獲得;或者
    • 其他某個(gè)線程中斷當(dāng)前線程,并且支持對(duì)鎖獲取的中斷;或者
    • 已超過(guò)指定的等待時(shí)間

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

    如果當(dāng)前線程:

    • 在進(jìn)入此方法時(shí)已經(jīng)設(shè)置了該線程的中斷狀態(tài);或者
    • 在獲取鎖時(shí)被中斷,并且支持對(duì)鎖獲取的中斷,
    則將拋出 InterruptedException,并會(huì)清除當(dāng)前線程的已中斷狀態(tài)。

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

    void unlock();

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

     

    相對(duì)于比較空洞的API,來(lái)看一個(gè)實(shí)際的例子。下面的代碼實(shí)現(xiàn)了一個(gè)類似于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是線程安全的,此結(jié)構(gòu)中大量使用了Lock對(duì)象的lock/unlock方法對(duì)。同樣可以看到的是對(duì)于自增和自減操作使用了++/--。之所以能夠保證線程安全,是因?yàn)長(zhǎng)ock對(duì)象的lock()方法保證了只有一個(gè)線程能夠只有此鎖。需要說(shuō)明的是對(duì)于任何一個(gè)lock()方法,都需要一個(gè)unlock()方法與之對(duì)于,通常情況下為了保證unlock方法總是能夠得到執(zhí)行,unlock方法被置于finally塊中。另外這里使用了java.util.concurrent.locks.ReentrantLock.ReentrantLock對(duì)象,下一個(gè)小節(jié)中會(huì)具體描述此類作為L(zhǎng)ock的唯一實(shí)現(xiàn)是如何設(shè)計(jì)和實(shí)現(xiàn)的。

    盡管synchronized實(shí)現(xiàn)Lock的相同語(yǔ)義,并且在語(yǔ)法上比Lock要簡(jiǎn)單多,但是前者卻比后者的開(kāi)銷要大得多。做一個(gè)簡(jiǎn)單的測(cè)試。

    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;

     

    在這個(gè)例子中每次啟動(dòng)10個(gè)線程,每個(gè)線程計(jì)算100000次自增操作,重復(fù)測(cè)試10次,下面是某此測(cè)試的結(jié)果:

    cost1: 624071136

    cost2: 2057847833

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



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

    評(píng)論

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

    ------------------
    Mac OS x 10.6
    jdk 1.6  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機(jī)制 part 1 2010-11-03 07:54 hephaistos
    呵呵,我測(cè)試了下
    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

    應(yīng)該樓上的相反結(jié)果是由于cpu的多線程運(yùn)算能力不同而有所差異吧  回復(fù)  更多評(píng)論
      

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

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

    這是他的測(cè)試方法,請(qǐng)參考一下:(該方法是測(cè)試各個(gè)map的,他測(cè)試重入鎖跟固有鎖的方法也是一樣的)
    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.)
      回復(fù)  更多評(píng)論
      

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

    # re: 深入淺出 Java Concurrency (6): 鎖機(jī)制 part 1 2012-10-11 11:46 nestle
    請(qǐng)問(wèn)blog主你這里的休眠指的是什么  回復(fù)  更多評(píng)論
      

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

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

    # re: 深入淺出 Java Concurrency (6): 鎖機(jī)制 part 1 2014-06-19 13:24 imxylz
    @徐敏
    鎖數(shù)據(jù)結(jié)構(gòu)的實(shí)現(xiàn),便于程序開(kāi)發(fā)。鎖也是基于CAS原子操作實(shí)現(xiàn)的,但是CAS難以使用。  回復(fù)  更多評(píng)論
      

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

    synchronized int incrementAndGet(){
    i++;
    return i;
    }
    }  回復(fù)  更多評(píng)論
      

    # re: 深入淺出 Java Concurrency (6): 鎖機(jī)制 part 1 2014-07-03 15:06 imxylz
    JDK6以后對(duì)synchronized進(jìn)行了很多優(yōu)化,而Lock基本上沒(méi)有什么可優(yōu)化的空間。在某些操作系統(tǒng)和JDK實(shí)現(xiàn)上,這種簡(jiǎn)單的測(cè)試結(jié)果可能都不一樣。但通常情況下,高并發(fā)和長(zhǎng)時(shí)間任務(wù)執(zhí)行上,Lock的性能比synchronized的更優(yōu)。  回復(fù)  更多評(píng)論
      


    ©2009-2014 IMXYLZ
    主站蜘蛛池模板: 日韩免费高清大片在线| 国产精品亚洲综合网站| 亚洲电影一区二区| 久久精品亚洲综合| 精品亚洲综合久久中文字幕| 亚洲一区AV无码少妇电影☆| 亚洲最大激情中文字幕| 久久久久亚洲AV综合波多野结衣| 久久亚洲AV永久无码精品| 国产福利电影一区二区三区,亚洲国模精品一区 | 国产成人无码精品久久久免费 | 国产美女视频免费观看的网站| 一个人看的免费观看日本视频www| 免费看美女午夜大片| 无码的免费不卡毛片视频| 一区二区三区免费在线观看| 中文字幕在线视频免费观看| 一区二区三区无码视频免费福利| 免费观看男人吊女人视频| 99久久国产免费中文无字幕| 黄+色+性+人免费| 91免费资源网站入口| 免费毛片在线播放| 亚洲av无码成人精品区在线播放 | 国产大片91精品免费观看男同| 午夜国产大片免费观看| 亚洲国产精品综合久久网络| 亚洲色中文字幕无码AV| 亚洲成人激情在线| 国产日本亚洲一区二区三区| 免费亚洲视频在线观看| 国产裸体美女永久免费无遮挡| 8x网站免费入口在线观看| 成人女人A级毛片免费软件| 国产成人高清精品免费鸭子| 中文字幕无码精品亚洲资源网| 亚洲黑人嫩小videos| 亚洲精品理论电影在线观看| 黄色短视频免费看| 四虎在线免费视频| 亚洲AV成人潮喷综合网|