一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Java高級:線程同步lock與unlock使用

 lguo001 2016-05-07


來源:伯樂在線專欄作者-陶邦仁


一、Lock與Synchronized區(qū)別


Java中可以使用Lock和Synchronized的可以實(shí)現(xiàn)對某個共享資源的同步,同時也可以實(shí)現(xiàn)對某些過程的原子性操作。


Lock可以使用Condition進(jìn)行線程之間的調(diào)度,Synchronized則使用Object對象本身的notify, wait, notityAll調(diào)度機(jī)制,這兩種調(diào)度機(jī)制有什么異同呢?


Condition是Java5以后出現(xiàn)的機(jī)制,它有更好的靈活性,而且在一個對象里面可以有多個Condition(即對象監(jiān)視器),則線程可以注冊在不同的Condition,從而可以有選擇性的調(diào)度線程,更加靈活。


Synchronized就相當(dāng)于整個對象只有一個單一的Condition(即該對象本身)所有的線程都注冊在它身上,線程調(diào)度的時候之后調(diào)度所有得注冊線程,沒有選擇權(quán),會出現(xiàn)相當(dāng)大的問題 。


所以,Lock 實(shí)現(xiàn)提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實(shí)現(xiàn)允許更靈活的結(jié)構(gòu),可以具有差別很大的屬性,可以支持多個相關(guān)的 Condition 對象。


鎖是控制多個線程對共享資源進(jìn)行訪問的工具。通常,鎖提供了對共享資源的獨(dú)占訪問。一次只能有一個線程獲得鎖,對共享資源的所有訪問都需要首先獲得鎖。不過,某些鎖可能允許對共享資源并發(fā)訪問,如 ReadWriteLock 的讀取鎖。


synchronized 方法或語句的使用提供了對與每個對象相關(guān)的隱式監(jiān)視器鎖的訪問,但卻強(qiáng)制所有鎖獲取和釋放均要出現(xiàn)在一個塊結(jié)構(gòu)中:當(dāng)獲取了多個鎖時,它們必須以相反的順序釋放,且必須在與所有鎖被獲取時相同的詞法范圍內(nèi)釋放所有鎖。


雖然 synchronized 方法和語句的范圍機(jī)制使得使用監(jiān)視器鎖編程方便了很多,而且還幫助避免了很多涉及到鎖的常見編程錯誤,但有時也需要以更為靈活的方式使用鎖。例如,某些遍歷并發(fā)訪問的數(shù)據(jù)結(jié)果的算法要求使用 “hand-over-hand” 或 “chain locking”:獲取節(jié)點(diǎn) A 的鎖,然后再獲取節(jié)點(diǎn) B 的鎖,然后釋放 A 并獲取 C,然后釋放 B 并獲取 D,依此類推。Lock 接口的實(shí)現(xiàn)允許鎖在不同的作用范圍內(nèi)獲取和釋放,并允許以任何順序獲取和釋放多個鎖,從而支持使用這種技術(shù)。


二、java.util.concurrent.locks類結(jié)構(gòu)



上圖中,LOCK的實(shí)現(xiàn)類其實(shí)都是構(gòu)建在AbstractQueuedSynchronizer上,為何圖中沒有用UML線表示呢,這是每個Lock實(shí)現(xiàn)類都持有自己內(nèi)部類Sync的實(shí)例,而這個Sync就是繼承AbstractQueuedSynchronizer(AQS)。為何要實(shí)現(xiàn)不同的Sync呢?這和每種Lock用途相關(guān)。另外還有AQS的State機(jī)制。


基于AQS構(gòu)建的Synchronizer包括ReentrantLock,Semaphore,CountDownLatch, ReetrantRead WriteLock,FutureTask等,這些Synchronizer實(shí)際上最基本的東西就是原子狀態(tài)的獲取和釋放,只是條件不一樣而已。


ReentrantLock:需要記錄當(dāng)前線程獲取原子狀態(tài)的次數(shù),如果次數(shù)為零,那么就說明這個線程放棄了鎖(也有可能其他線程占據(jù)著鎖從而需要等待),如果次數(shù)大于1,也就是獲得了重進(jìn)入的效果,而其他線程只能被park住,直到這個線程重進(jìn)入鎖次數(shù)變成0而釋放原子狀態(tài)。以下為ReetranLock的FairSync的tryAcquire實(shí)現(xiàn)代碼解析:



Semaphore:則是要記錄當(dāng)前還有多少次許可可以使用,到0,就需要等待,也就實(shí)現(xiàn)并發(fā)量的控制,Semaphore一開始設(shè)置許可數(shù)為1,實(shí)際上就是一把互斥鎖。以下為Semaphore的FairSync實(shí)現(xiàn):



CountDownLatch:閉鎖則要保持其狀態(tài),在這個狀態(tài)到達(dá)終止態(tài)之前,所有線程都會被park住,閉鎖可以設(shè)定初始值,這個值的含義就是這個閉鎖需要被countDown()幾次,因?yàn)槊看蜟ountDown是sync.releaseShared(1),而一開始初始值為10的話,那么這個閉鎖需要被countDown()十次,才能夠?qū)⑦@個初始值減到0,從而釋放原子狀態(tài),讓等待的所有線程通過。



FutureTask:需要記錄任務(wù)的執(zhí)行狀態(tài),當(dāng)調(diào)用其實(shí)例的get方法時,內(nèi)部類Sync會去調(diào)用AQS的acquireSharedInterruptibly()方法,而這個方法會反向調(diào)用Sync實(shí)現(xiàn)的tryAcquireShared()方法,即讓具體實(shí)現(xiàn)類決定是否讓當(dāng)前線程繼續(xù)還是park,而FutureTask的tryAcquireShared方法所做的唯一事情就是檢查狀態(tài),如果是RUNNING狀態(tài)那么讓當(dāng)前線程park。而跑任務(wù)的線程會在任務(wù)結(jié)束時調(diào)用FutureTask 實(shí)例的set方法(與等待線程持相同的實(shí)例),設(shè)定執(zhí)行結(jié)果,并且通過unpark喚醒正在等待的線程,返回結(jié)果。



以上4個AQS的使用是比較典型,然而有個問題就是這些狀態(tài)存在哪里呢?并且是可以計數(shù)的。從以上4個example,我們可以很快得到答案,AQS提供給了子類一個int state屬性。并且暴露給子類getState()和setState()兩個方法(protected)。這樣就為上述狀態(tài)解決了存儲問題,RetrantLock可以將這個state用于存儲當(dāng)前線程的重進(jìn)入次數(shù),Semaphore可以用這個state存儲許可數(shù),CountDownLatch則可以存儲需要被countDown的次數(shù),而Future則可以存儲當(dāng)前任務(wù)的執(zhí)行狀態(tài)(RUNING,RAN,CANCELL)。其他的Synchronizer存儲他們的一些狀態(tài)。


AQS留給實(shí)現(xiàn)者的方法主要有5個方法,其中tryAcquire,tryRelease和isHeldExclusively三個方法為需要獨(dú)占形式獲取的synchronizer實(shí)現(xiàn)的,比如線程獨(dú)占ReetranLock的Sync,而tryAcquireShared和tryReleasedShared為需要共享形式獲取的synchronizer實(shí)現(xiàn)。

ReentrantLock內(nèi)部Sync類實(shí)現(xiàn)的是tryAcquire,tryRelease, isHeldExclusively三個方法(因?yàn)楂@取鎖的公平性問題,tryAcquire由繼承該Sync類的內(nèi)部類FairSync和NonfairSync實(shí)現(xiàn))Semaphore內(nèi)部類Sync則實(shí)現(xiàn)了tryAcquireShared和tryReleasedShared(與CountDownLatch相似,因?yàn)楣叫詥栴},tryAcquireShared由其內(nèi)部類FairSync和NonfairSync實(shí)現(xiàn))。CountDownLatch內(nèi)部類Sync實(shí)現(xiàn)了tryAcquireShared和tryReleasedShared。FutureTask內(nèi)部類Sync也實(shí)現(xiàn)了tryAcquireShared和tryReleasedShared。


其實(shí)使用過一些JAVA synchronizer的之后,然后結(jié)合代碼,能夠很快理解其到底是如何做到各自的特性的,在把握了基本特性,即獲取原子狀態(tài)和釋放原子狀態(tài),其實(shí)我們自己也可以構(gòu)造synchronizer。如下是一個LOCK API的一個例子,實(shí)現(xiàn)了一個先入先出的互斥鎖。



三、lock與unlock使用


下面是一個場景,針對這個場景提出兩種解決方案。 一個中轉(zhuǎn)站,可以接納貨物,然后發(fā)出貨物,這是需要建一個倉庫,相當(dāng)于一個緩沖區(qū),當(dāng)倉庫滿的時候,不能接貨,倉庫空的時候,不能發(fā)貨。


第一種,用一個Condition去解決,有可能會出問題。


package com.zxx;

 

import java.util.Random; 

import java.util.concurrent.ExecutorService; 

import java.util.concurrent.Executors; 

import java.util.concurrent.locks.Condition; 

import java.util.concurrent.locks.Lock; 

import java.util.concurrent.locks.ReentrantLock;

 

/** 

* 單個Condition去控制一個緩沖區(qū),多線程對緩沖區(qū)做讀寫操作,要保證緩沖區(qū)滿的時侯不會 

* 被寫,空的時候不會被讀;單個Condition控制會出錯誤: 當(dāng)緩沖區(qū)還有一個位置時,多個寫線程 

* 同時訪問,則只有一個寫線程可以對其進(jìn)行寫操作,操作完之后,喚醒在這個condition上等待的 

* 其他幾個寫線程,如果判斷用IF語句的話就會出現(xiàn)繼續(xù)向緩沖區(qū)添加。 

* @author Administrator 

*/

public class ConditionError { 

    Lock lock = new ReentrantLock(); 

    Condition condition = lock.newCondition(); 

    String[] container = new String[10]; 

    int index = 0; 

    public static void main(String[] args) { 

        ConditionError conditionError = new ConditionError(); 

        conditionError.test(); 

    } 

    public void test(){ 

        ExecutorService threadPool = Executors.newCachedThreadPool(); 

        for(int i = 0; i < 14;="">

            threadPool.execute(new Runnable(){

 

                @Override

                public void run() { 

                    put(); 

                } 

            }); 

        } 

        Executors.newSingleThreadExecutor().execute(new Runnable(){//用一個線程去取,則會通知4個阻塞的寫線程工作,此時 

                                                                //會有一個線程向緩沖區(qū)寫,寫完后去通知在這個condition上等待 

                                                                //的取線程,這是它的本意,但是它喚醒了寫線程,因?yàn)橹挥幸粋€condition 

                                                                //不能有選擇的喚醒寫取線程,此時就需要有多個Condition 

            @Override

            public void run() { 

                try { 

                    Thread.sleep(10000); 

                } catch (InterruptedException e) { 

                    e.printStackTrace(); 

                } 

                get(); 

            } 

        }); 

    } 

    /** 

     * 向緩沖去寫數(shù)據(jù) 

     */

    public void put(){ 

        lock.lock(); 

        try{ 

            System.out.println(Thread.currentThread().getName() + '當(dāng)前位置:' + index + '-----------------------------'); 

            while(index == 10){ 

                try { 

                    System.out.println(Thread.currentThread().getName() + '處于阻塞狀態(tài)!'); 

                    condition.await(); 

//                    index = 0; 

                } catch (InterruptedException e) { 

                    e.printStackTrace(); 

                } 

            } 

            container[index] = new String(new Random().nextInt() + ''); 

            condition.signalAll(); 

            index ++; 

        } finally { 

            lock.unlock(); 

        } 

    } 

    /** 

     * 從緩沖區(qū)拿數(shù)據(jù) 

     */

    public void get(){ 

        lock.lock(); 

        try{ 

            while(index == 0){ 

                try { 

                    System.out.println('get--------' + Thread.currentThread().getName() + '處于阻塞'); 

                    condition.await(); 

                } catch (InterruptedException e) { 

                    e.printStackTrace(); 

                } 

            } 

            index --; 

            System.out.println('get---------' + Thread.currentThread().getName() + '喚醒阻塞'); 

            condition.signalAll(); 

        } finally { 

            lock.unlock(); 

        } 

    } 

}


第二種解決方案,用java api中的 一個例子 。



專欄作者簡介

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    av在线免费观看一区二区三区| 老司机亚洲精品一区二区| 欧美乱码精品一区二区三| 国产免费一区二区三区av大片| 国产一级不卡视频在线观看| 欧美高潮喷吹一区二区| 日本本亚洲三级在线播放| 国产二级一级内射视频播放 | 亚洲中文在线观看小视频| 久久三级国外久久久三级| 麻豆在线观看一区二区| 好吊一区二区三区在线看| 中文字幕中文字幕在线十八区| 日韩一区二区免费在线观看| a久久天堂国产毛片精品| 男女激情视频在线免费观看| 亚洲人午夜精品射精日韩| 美国女大兵激情豪放视频播放| 99久久人妻中文字幕| 色播五月激情五月婷婷| 黄片在线免费观看全集| 成人国产激情福利久久| 国产精品不卡一区二区三区四区 | 精品熟女少妇一区二区三区| 99久热只有精品视频最新| 久久人妻人人澡人人妻| 精品久久少妇激情视频| 欧美一区二区三区高潮菊竹 | 日本午夜乱色视频在线观看| 午夜视频成人在线观看| 国产日韩中文视频一区| 亚洲av日韩一区二区三区四区 | 老司机精品在线你懂的| 亚洲中文在线中文字幕91| 午夜福利黄片免费观看| 亚洲天堂国产精品久久精品| 日韩人妻少妇一区二区| 中文文精品字幕一区二区| 日本成人三级在线播放| 欧美日韩亚洲综合国产人| 亚洲一级在线免费观看|