4.Lock的使用

1.ReentrantLock

在Java多線(xiàn)程中,可以使用synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)線(xiàn)程之間的同步互斥枕荞。但是在Java 1.5中新增了ReentrantLock類(lèi)也能達(dá)到同樣的效果斥季。并且擴(kuò)展了許多功能锦溪。比synchronized更加靈活。

  • 代碼演示

  • 新建業(yè)務(wù)類(lèi)

public class Business {
    private Lock lock = new ReentrantLock();

    public void print() {
        //lock.lock();
        for (int i = 0; i < 5; i++) {
            System.out.println(String.format("%s:%d", Thread.currentThread().getName(), i));
        }
        //lock.unlock();
    }
}
  • 新建線(xiàn)程A
public class ThreadA extends Thread {
    private Business business;

    public ThreadA(Business business) {
        super();
        this.business = business;
    }

    @Override
    public void run() {
        business.print();
    }
}
  • 新建線(xiàn)程B
public class ThreadB extends Thread {

    private Business business;

    public ThreadB(Business business){
        this.business=business;
    }

    @Override
    public void run() {
        business.print();
    }
}

  • Client
public class Client {
    public static void main(String[] args) {
        Business business = new Business();
        ThreadA a = new ThreadA(business);
        ThreadB b = new ThreadB(business);
        a.start();
        b.start();
    }
}
  • 沒(méi)加鎖的結(jié)果
線(xiàn)程B:0
線(xiàn)程B:1
線(xiàn)程B:2
線(xiàn)程B:3
線(xiàn)程B:4
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
線(xiàn)程A:3
線(xiàn)程A:4
  • 加鎖后的結(jié)果
線(xiàn)程B:0
線(xiàn)程B:1
線(xiàn)程B:2
線(xiàn)程B:3
線(xiàn)程B:4
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
線(xiàn)程A:3
線(xiàn)程A:4

由此可看出综苔,ReentrantLock實(shí)現(xiàn)了synchronized的同步的功能惩系。lock.lock()是獲取鎖。lock.unlock()是釋放鎖如筛。

1.1結(jié)合Condition實(shí)現(xiàn)wait與notify功能

關(guān)鍵字synchronized與wait及notify結(jié)合堡牡,可以實(shí)現(xiàn)等待、通知模式杨刨。而ReentrantLock與Condition結(jié)合也可以實(shí)現(xiàn)同樣的功能晤柄。

  • 代碼演示

  • 新建業(yè)務(wù)類(lèi)

public class Business {
    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();

    private int num;

    public void print() {
        try {
            lock.lock();
            for (int i = 0; i < 5; i++) {
                System.out.println(String.format("%s:%d", Thread.currentThread().getName(), i));
                num = i;
                if (i == 2){
                    condition.await();
                    System.out.println("接受到信號(hào),執(zhí)行完畢");
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    public void notifyPrint() {
        lock.lock();
        if (num == 2)
            condition.signal();
        lock.unlock();
    }
}

  • 新建線(xiàn)程A
public class ThreadA extends Thread {
    private Business business;

    public ThreadA(Business business) {
        super();
        this.business = business;
    }

    @Override
    public void run() {
        business.print();
    }
}
  • 新建線(xiàn)程B
public class ThreadB extends Thread {

    private Business business;

    public ThreadB(Business business) {
        this.business = business;
    }

    @Override
    public void run() {
        business.notifyPrint();
    }
}
  • Client
public class Client {
    public static void main(String[] args) throws InterruptedException {
        Business business = new Business();
        ThreadA a = new ThreadA(business);
        a.setName("線(xiàn)程A");
        ThreadB b = new ThreadB(business);
        b.setName("線(xiàn)程B");
        a.start();
        Thread.sleep(2000);
        b.start();
    }
}
  • 結(jié)果
Connected to the target VM, address: '127.0.0.1:62623', transport: 'socket'
線(xiàn)程A:0
線(xiàn)程A:1
線(xiàn)程A:2
Disconnected from the target VM, address: '127.0.0.1:62623', transport: 'socket'
接受到信號(hào)妖胀,執(zhí)行完畢
線(xiàn)程A:3
線(xiàn)程A:4

下面圖標(biāo)表示Object里面的類(lèi)的方法與Condition類(lèi)的方法對(duì)比

Object Condition
wait() await()
wait(long timeout) await(long time, TimeUnit unit)
notify() signal()
notifyAll() signalAll()

1.2 Condition的部分喚醒

在服務(wù)類(lèi)中創(chuàng)建多個(gè)Condition實(shí)例芥颈。進(jìn)行對(duì)其分組操作。

private Condition condition = lock.newCondition();

private Condition condition2 = lock.newCondition();

1.3公平鎖與非公平鎖

公平鎖:線(xiàn)程獲取鎖的順序是按照線(xiàn)程加鎖的順序來(lái)分配的赚抡。即先進(jìn)先出的順序(FIFO)爬坑。

非公平鎖:獲取鎖的搶占機(jī)制,是隨機(jī)獲得鎖的涂臣。

  • ReentrantLock的構(gòu)造函數(shù)
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

傳入true為公平鎖妇垢,傳入false為非公平鎖。

1.4ReentrantLock及Condition其他重要方法

  • 1.getHoldCount

查詢(xún)當(dāng)前線(xiàn)程保持鎖定的個(gè)數(shù),也就是調(diào)用lock()的次數(shù)

public int getHoldCount() {
    return sync.getHoldCount();
}
  • 2.getQueueLength

計(jì)算正等待獲取此鎖定的線(xiàn)程數(shù)闯估。比如一個(gè)線(xiàn)程在鎖內(nèi)休眠灼舍,其他9個(gè)線(xiàn)程正在等待,那么調(diào)用此方法返回9涨薪。

public final int getQueueLength() {
    return sync.getQueueLength();
}
  • 3.getWaitQueueLength

返回給定條件的Condition相關(guān)的等待此鎖的線(xiàn)程數(shù)骑素。

public int getWaitQueueLength(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
  • 4.hasQueuedThread

查詢(xún)指定的線(xiàn)程是否正在等待獲取此鎖

public final boolean hasQueuedThread(Thread thread) {
    return sync.isQueued(thread);
}
  • 5.hasQueuedThreads

查詢(xún)是否有線(xiàn)程正在等待獲取此鎖

public final boolean hasQueuedThreads() {
    return sync.hasQueuedThreads();
}
  • 6.hasWaiters

根據(jù)Condition條件去查詢(xún)是否有線(xiàn)程正在等待獲取此鎖

public boolean hasWaiters(Condition condition) {
    if (condition == null)
        throw new NullPointerException();
    if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
        throw new IllegalArgumentException("not owner");
    return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
  • 7.isFair

判斷是不是公平鎖

public final boolean isFair() {
    return sync instanceof FairSync;
}
  • 8.isHeldByCurrentThread

查詢(xún)當(dāng)前是否保持鎖定

public boolean isHeldByCurrentThread() {
    return sync.isHeldExclusively();
}
  • 9.isLocked

判斷當(dāng)前鎖是否由任意線(xiàn)程鎖定

public boolean isLocked() {
    return sync.isLocked();
}
  • 10.lockInterruptibly

如果當(dāng)前線(xiàn)程未被中斷,則獲取獲取鎖定刚夺,(相當(dāng)于lock())如果已經(jīng)中斷則拋出異常

public void lockInterruptibly() throws InterruptedException {
    sync.acquireInterruptibly(1);
}
  • 11.tryLock

當(dāng)鎖沒(méi)有被其他線(xiàn)程占用献丑,則獲取鎖定。

public boolean tryLock() {
    return sync.nonfairTryAcquire(1);
}
  • 12.tryLock(long timeout, TimeUnit unit)

在給定的時(shí)間內(nèi)侠姑,鎖沒(méi)有被其他線(xiàn)程占用创橄,則獲取鎖

public boolean tryLock(long timeout, TimeUnit unit)
        throws InterruptedException {
    return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
  • 13.awaitUninterruptibly

線(xiàn)程在等待的時(shí)候,線(xiàn)程若主動(dòng)拋出異常莽红,則相對(duì)應(yīng)的程序也不會(huì)拋出異常妥畏。

public final void awaitUninterruptibly() {
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    boolean interrupted = false;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if (Thread.interrupted())
            interrupted = true;
    }
    if (acquireQueued(node, savedState) || interrupted)
        selfInterrupt();
}
  • 14.awaitUntil

某線(xiàn)程在指定的時(shí)間內(nèi)處于等待狀態(tài),超過(guò)時(shí)間安吁,自動(dòng)運(yùn)行線(xiàn)程醉蚁。

public final boolean awaitUntil(Date deadline)
        throws InterruptedException {
    long abstime = deadline.getTime();
    if (Thread.interrupted())
        throw new InterruptedException();
    Node node = addConditionWaiter();
    int savedState = fullyRelease(node);
    boolean timedout = false;
    int interruptMode = 0;
    while (!isOnSyncQueue(node)) {
        if (System.currentTimeMillis() > abstime) {
            timedout = transferAfterCancelledWait(node);
            break;
        }
        LockSupport.parkUntil(this, abstime);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null)
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
    return !timedout;
}

2.ReentrantReadWriteLock

ReentrantLock具有完全互斥排他的效果,即同一時(shí)間只有一個(gè)線(xiàn)程在執(zhí)行ReentrantLock.Lock()方法后面的任務(wù)鬼店。

這樣雖然保證了實(shí)例變量的線(xiàn)程安全性网棍,但是效率卻是低下的。這時(shí)候就誕生了讀寫(xiě)鎖ReentrantReadWriteLock妇智。

讀寫(xiě)鎖有兩個(gè)鎖:

  • 1.共享鎖:讀操作相關(guān)的鎖
  • 2.排他鎖:寫(xiě)操作相關(guān)的鎖
private ReentrantReadWriteLock lock1 = new ReentrantReadWriteLock();

lock1.writeLock().lock();
lock1.writeLock().unlock();

lock1.readLock().lock();
lock1.readLock().unlock();

同一個(gè)類(lèi)中滥玷,有兩個(gè)及兩個(gè)以上的方法。一個(gè)使用讀鎖巍棱,一個(gè)使用寫(xiě)鎖罗捎。那么它們是互斥的。只有所有的方法是讀鎖拉盾,才是不相互干擾,不排斥的豁状。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捉偏,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子泻红,更是在濱河造成了極大的恐慌夭禽,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谊路,死亡現(xiàn)場(chǎng)離奇詭異讹躯,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)潮梯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)骗灶,“玉大人,你說(shuō)我怎么就攤上這事秉馏“业” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵萝究,是天一觀的道長(zhǎng)免都。 經(jīng)常有香客問(wèn)我,道長(zhǎng)帆竹,這世上最難降的妖魔是什么绕娘? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮栽连,結(jié)果婚禮上险领,老公的妹妹穿的比我還像新娘。我一直安慰自己升酣,他們只是感情好舷暮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著噩茄,像睡著了一般下面。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上绩聘,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天沥割,我揣著相機(jī)與錄音,去河邊找鬼凿菩。 笑死机杜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的衅谷。 我是一名探鬼主播椒拗,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼获黔!你這毒婦竟也來(lái)了蚀苛?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤玷氏,失蹤者是張志新(化名)和其女友劉穎堵未,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盏触,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渗蟹,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年块饺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雌芽。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡授艰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膘怕,到底是詐尸還是另有隱情想诅,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布岛心,位于F島的核電站来破,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏忘古。R本人自食惡果不足惜徘禁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望髓堪。 院中可真熱鬧送朱,春花似錦、人聲如沸干旁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)争群。三九已至回怜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間换薄,已是汗流浹背玉雾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留轻要,地道東北人复旬。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像冲泥,于是被迫代替她去往敵國(guó)和親驹碍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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