Java多線程學(xué)習(xí)四 Lock的使用

一、 配合Condition使用

Condition的await()方法相當(dāng)于Object的wait()方法,signal相當(dāng)于notify,signalAll相當(dāng)于notifyAll,且它們都必須在持有鎖的時(shí)候才能調(diào)用。

public class MyService {
    private Lock lock=new ReentrantLock();
    private Condition condition=lock.newCondition();

    public void await(){
        try {
            System.out.println("wait begin"+System.currentTimeMillis());
            lock.lock();
            condition.await();
            System.out.println("wait end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signal(){
        try {
            lock.lock();
            System.out.println("signal時(shí)間為:"+System.currentTimeMillis());
            condition.signal();
        }finally {
            lock.unlock();
        }
    }
}
public class MyThread extends Thread {
    private MyService myService;

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

    @Override
    public void run() {
        myService.await();
    }
}

public class TestMain {
    public static void main(String[] args) throws InterruptedException {
        MyService myService=new MyService();
        MyThread myThread=new MyThread(myService);
        myThread.start();
        Thread.sleep(3000);
        myService.signal();
    }
}

如果在調(diào)用Condition的await方法沒有持有鎖的話會(huì)報(bào)異常,和調(diào)用Object的wait方法一樣

    public void await(){
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException
    at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.fullyRelease(AbstractQueuedSynchronizer.java:1723)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2036)
    at com.yjj.chapter04.test02_condition.MyService.await(MyService.java:29)
    at com.yjj.chapter04.test02_condition.MyThread.run(MyThread.java:18)

二、使用多個(gè)Condition通知部分線程

package com.yjj.chapter04.test03_condition2;

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

/**
 * @Description:
 * @Author: YinJunjie
 * @CreateDate: 2018/9/27 15:45
 * @Version: 1.0
 */
public class MyService {
    private Lock lock=new ReentrantLock();
    private Condition conditionA=lock.newCondition();
    private Condition conditionB=lock.newCondition();

    public void awaitA(){
        try {
            System.out.println("waitA begin"+System.currentTimeMillis());
            lock.lock();
            conditionA.await();
            System.out.println("waitA end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void awaitB(){
        try {
            System.out.println("waitB begin"+System.currentTimeMillis());
            lock.lock();
            conditionB.await();
            System.out.println("waitB end"+System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalA(){
        try {
            lock.lock();
            System.out.println("signalA時(shí)間為:"+System.currentTimeMillis());
            conditionA.signal();
        }finally {
            lock.unlock();
        }
    }

    public void signalB(){
        try {
            lock.lock();
            System.out.println("signalB時(shí)間為:"+System.currentTimeMillis());
            conditionB.signal();
        }finally {
            lock.unlock();
        }
    }
}

public class MyThreadA extends Thread {
    private MyService myService;

    public MyThreadA(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitA();
    }
}

public class MyThreadB extends Thread {
    private MyService myService;

    public MyThreadB(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.awaitB();
    }
}
    public static void main(String[] args) throws InterruptedException {
        MyService myService=new MyService();
        MyThreadA myThreadA =new MyThreadA(myService);
        MyThreadB myThreadB =new MyThreadB(myService);
        myThreadB.start();
        myThreadA.start();
        Thread.sleep(3000);
        myService.signalA();
        Thread.sleep(3000);
        myService.signalB();
    }

三、公平鎖與非公平鎖

公平鎖:線程獲取說的順序是按照線程加鎖的順序來分配的,即先來先得FIFO先進(jìn)先出順序。
非公平鎖:獲取鎖是隨機(jī)的,由各線程搶奪,先來的不一定閑的,這個(gè)方式可能造成某些線程一直拿不到鎖。
創(chuàng)建公平鎖:Lock lock=new ReentrantLock(true)
非公平鎖:Lock lock=new ReentrantLock(false)

四、Lock常用方法

  1. int getHoldCount()
    查詢當(dāng)前線程保持次鎖定的個(gè)數(shù),也就是調(diào)用lock()方法的次數(shù)
  2. int getQueueLength()
    返回正等待獲取此鎖的線程的估計(jì)數(shù)
  3. int getWaitQueueLength(Condition condition)
    返回等待與此鎖相關(guān)的給定條件Condition的線程估計(jì)數(shù)
  4. boolean hasQueuedThread(Thread thread)
    查詢指定的線程是否正在等待獲取此鎖
  5. boolean hasQueuedThreads()
    查詢是否有線程正在等待獲取此鎖
  6. boolean hasWaiters(Condition condition)
    查詢是否有現(xiàn)成正在等待與此鎖有關(guān)的condition條件
  7. boolean isFair()
    判斷是不是公平鎖
  8. boolean isHeldByCurrentThread()
    查詢當(dāng)前線程是否保持此鎖定
  9. boolean isLocked()
    查詢此鎖是否由任意線程保持
  10. void lockInterruptibly()
    如果當(dāng)前線程未被中斷,則獲取鎖定,如果已經(jīng)被中斷則出現(xiàn)異常。
  11. boolean tryLock()
    成功獲取了鎖的情況下才會(huì)返回true,如果別的線程當(dāng)前正持有鎖,則會(huì)立即返回false
  12. boolean tryLock(long timeOut,TimeUnit unit)
    如果鎖在給定等待時(shí)間內(nèi)沒有被另一個(gè)線程保持,且當(dāng)前線程未被中斷,則獲取該鎖。
    ...省略好幾個(gè)方法,去看jdk api吧

五、讀寫鎖

public class MyService {
    private ReentrantReadWriteLock lock=new ReentrantReadWriteLock();

    public void read(){
        try {
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"讀啊讀");
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.readLock().unlock();
            System.out.println(Thread.currentThread().getName()+"讀完了");
        }
    }

    public void write(){
            try {
                lock.writeLock().lock();
                System.out.println(Thread.currentThread().getName()+"寫啊寫");
                Thread.sleep(1000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }finally {
                lock.writeLock().unlock();
                System.out.println(Thread.currentThread().getName()+"寫完了");
            }
        }
}
public class ReadThread extends Thread {
    private MyService myService;

    public ReadThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.read();
    }
}
public class WriteThread extends Thread {
    private MyService myService;

    public WriteThread(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        myService.write();
    }
}

讀讀不互斥

        MyService myService = new MyService();
        ReadThread readThread1 = new ReadThread(myService);
        ReadThread readThread2 = new ReadThread(myService);
        readThread1.setName("read1");
        readThread2.setName("read2");
        readThread1.start();
        readThread2.start();
read1讀啊讀
read2讀啊讀
read1讀完了
read2讀完了

讀寫互斥

        MyService myService=new MyService();
        ReadThread readThread=new ReadThread(myService);
        WriteThread writeThread=new WriteThread(myService);
        readThread.setName("read");
        writeThread.setName("write");
        readThread.start();
        writeThread.start();
read讀啊讀
read讀完了
write寫啊寫
write寫完了

寫寫互斥 略

注意:

ReentrantLock也是可重入的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容