《Java多線程編程核心技術(shù)_高洪巖 著》讀后整理04

第4章 Lock的使用

在Java多線程中, 可以使用synchronized關(guān)鍵字來實(shí)現(xiàn)線程之間同步互斥,但在JDK1.5中新增加了ReentrantLock類也能達(dá)到同樣的效果,并且在擴(kuò)展功能上也更加強(qiáng)大。

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

/**
 */
public class MyService {

    private Lock lock = new ReentrantLock();

    public void testMethod() {
        lock.lock();
        for (int i = 0; i < 5; i++) 
            System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
        lock.unlock();
    }
}

class MyThread extends Thread {
    private MyService service;

    public MyThread(MyService service) {
        this.service = service;
    }

    @Override
    public void run() {
        service.testMethod();
    }
}

class Run {
    public static void main(String[] args) {
        MyService service = new MyService();
        
        MyThread t1 = new MyThread(service);
        MyThread t2 = new MyThread(service);
        MyThread t3 = new MyThread(service);
        MyThread t4 = new MyThread(service);
        MyThread t5 = new MyThread(service);
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();
    }
}

OUTPUT:
ThreadName=Thread-0 1
ThreadName=Thread-0 2
ThreadName=Thread-0 3
ThreadName=Thread-0 4
ThreadName=Thread-0 5
ThreadName=Thread-2 1
ThreadName=Thread-2 2
ThreadName=Thread-2 3
ThreadName=Thread-2 4
ThreadName=Thread-2 5
ThreadName=Thread-3 1
ThreadName=Thread-3 2
ThreadName=Thread-3 3
ThreadName=Thread-3 4
ThreadName=Thread-3 5
ThreadName=Thread-4 1
ThreadName=Thread-4 2
ThreadName=Thread-4 3
ThreadName=Thread-4 4
ThreadName=Thread-4 5
ThreadName=Thread-1 1
ThreadName=Thread-1 2
ThreadName=Thread-1 3
ThreadName=Thread-1 4
ThreadName=Thread-1 5
  • 調(diào)用lock.lock()代碼的線程就持有了“對象監(jiān)視器”,其他線程只有等待鎖被釋放時(shí)再次爭搶。效果和使用synchronized關(guān)鍵字一樣,線程之間執(zhí)行的順序是隨機(jī)的。

  • Condition對象的await()方法,使當(dāng)前執(zhí)行任務(wù)的線程進(jìn)入了等待WAITING狀態(tài)。

  • Condition實(shí)現(xiàn)等待 / 通知

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

//在調(diào)用condition.await()方法之前需調(diào)用lock.lock()代碼獲得同步監(jiān)視器
public class MyService3 {
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void await() {
        try {
            lock.lock();
            System.out.println("A");
            condition.await();//等待
            System.out.println("B");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void single() {
        try {
            lock.lock();
            condition.signal();//喚醒
        } finally {
            lock.unlock();
        }
    }
}

class Run3 {
    public static void main(String[] args) throws InterruptedException {
        final MyService3 service = new MyService3();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                service.await();
            }
        });
        thread.start();

        System.out.println(Thread.currentThread().getName());
        Thread.sleep(1);

        service.single();
    }
}
  • 在使用notify()/notifyAll()方法進(jìn)行通知時(shí),被通知的線程卻是由JVM隨機(jī)選擇的。但使用ReentrantLock結(jié)合Condition類是可以實(shí)現(xiàn)"選擇性通知“。

Object類中的wait()方法相當(dāng)于Condition類中的await()方法

Object類中的wait(long timeout)方法相當(dāng)于Condition類中的`await(long time, TimeUnit unit)方法

Object類中的notify()方法相當(dāng)于Condition類中的signal()方法。

Object類中的notifyAll()方法相當(dāng)于Condition類中的signalAll()方法。

  • 公平與非wcguqim:鎖Lock分為“公平鎖”和“非公平鎖”, 公平鎖表示線程獲取鎖的順序是按照線程加鎖的順序來分配的,即先來先得的FIFO先進(jìn)先出順序。而非公平鎖就是一種獲取鎖的搶占機(jī)制,是隨機(jī)獲得鎖的,和公平鎖不一樣的就是先來不一定先得到鎖,這個(gè)方式可能造成某些線程一直拿不鎖,結(jié)果也就是不公平的了。

getHoldCount(), getQueueLength(), getWaitQueueLength()
  • 方法int getHoldCount()的作用是查詢當(dāng)前線程保持此鎖定的個(gè)數(shù),也就是調(diào)用lock()方法的次數(shù)。
lock.getHoldCount();
  • 方法int getQueueLength()的作用是返回正等待獲取此鎖定的線程估計(jì)數(shù),比如有5個(gè)線程,1個(gè)線程首先執(zhí)行await()方法,那么在調(diào)用getQueueLength()方法反返回值是4,說明有4個(gè)線程同時(shí)在等待lock的釋放。
lock.getQueueLength();
  • 方法int getWaitQueueLength(Condition condition)的作用是返回等待與此鎖定相關(guān)的給定條件Condition的線程估計(jì)數(shù),比如有5個(gè)線程,每個(gè)線程都執(zhí)行了同一個(gè)condition對象的await()方法,則調(diào)用getWaitQueueLength(Condition condition)方法時(shí)返回的int值是5。

hasQueuedThread(), hasQueuedThreads(), hasWaiters()
  • 方法boolean hasQueuedThread(thtread thread)的作用是查詢指定的線程是否正在等待獲取此鎖定。

  • 方法boolean hasQueuedThreads()的作用是查詢是否有線程正在等待獲取此鎖定。

lock.hasQueuedThread(threadA);
lock.hasQueuedThreads();
  • 方法boolean hasWaiters(Condition condition)的作用是查詢是否有線程正在等待與此鎖定有關(guān)的condition條件。
lock.hasWaiters(newConditino);

isFair(), isHeldByCurrentThread(), isLocked()
  • 方法boolean isFair()的作用是判斷是不是公平鎖。在默認(rèn)的情況下,ReentrantLock類使用的是非公平鎖。
lock.isFair();
  • 方法boolean isHeldByCurrentThread()的作用是查詢當(dāng)前線程是否保持此鎖定。
lock.isHeldByCurrentThread();
  • 方法boolean isLocked()的作用是查詢此鎖定是否由任意線程保持。
lock.isLocked();

lockInterruptibly(), tryLock(), tryLock(long timeout,TimeUnit unit)
  • 方法void lockInterruptibly()的作用是:如果當(dāng)前線程未衩中斷,則獲取鎖定,如果已經(jīng)被中斷則出現(xiàn)異常。

  • 方法boolean tryLock()的作用是,僅在調(diào)用時(shí)鎖定未被另一個(gè)線程保持的情況下,才獲取該鎖定。

  • 方法boolean tryLock(long timeout, TimeUnit unit)的作用是,如果鎖定在給定等待時(shí)間內(nèi)沒有被別一個(gè)線程保持,且當(dāng)前線程未被中斷,則獲取該鎖定。


ReentrantReadWriteLock
  • 類ReentrantLock具有完全互斥排他的效果,即同一時(shí)間只有一個(gè)線程在執(zhí)行ReentrantLock.lock()方法后面的任務(wù)。這樣做雖然保證了實(shí)例變量的線程安全性,但效率卻是非常低下的。

  • 所以在JDK中提供了一種讀寫鎖ReentrantReadWriteLock類,使用它可以加快運(yùn)行效率,在某些不需要操作實(shí)例變量的方法中,完全可以使用讀寫鎖ReentratnReadWriteLock來提升該方法的代碼運(yùn)行速度。

  • 永定鎖表示也有兩個(gè)鎖,一個(gè)是讀操作相關(guān)的鎖,也稱為共享鎖;另一個(gè)是寫操作相關(guān)的鎖,也叫排他鎖。也就是多個(gè)讀鎖之間不互斥,寫寫、寫讀互斥。

...
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
...
lock.writeLock().lock();
lock.readLock().lock();
...
lock.wirteLock().unlock();
lock.readLock().unlock();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,247評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,520評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,362評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,805評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,541評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,896評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,887評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,062評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,608評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,356評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,555評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,077評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,769評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,175評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,489評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,289評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,516評論 2 379

推薦閱讀更多精彩內(nèi)容