首頁 > Java > java教程 > 中ReentrantLock 類別的用法介紹

中ReentrantLock 類別的用法介紹

不言
發布: 2019-03-30 10:40:28
轉載
2562 人瀏覽過

這篇文章帶給大家的內容是關於Java中ReentrantLock 類別的用法介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

在Java 多執行緒中, 可以使用 synchronized 關鍵字來實現多執行緒之間同步互斥, 但在JDK 1.5 中新增加了ReentrantLock 類別也能達到同樣的效果, 並且在擴充功能上也更強大, 例如具有嗅探鎖定, 多路分支通知, 公平鎖和非公平鎖等(預設)功能, 而且在使用上也比 synchronized 更加的靈活.

使用ReentrantLock 實現同步

public class MyService {
    private Lock lock = new ReentrantLock();
    public void testMethod() {
        lock.lock();
        for (int i = 0; i < 10; i++){
            System.out.println("ThreadName=" + Thread.currentThread().getName() + (" " + (i + 1)));
        }
        lock.unlock();
    }
}
登入後複製
public class MyThread extends Thread {
    private MyService myService;
    public MyThread(MyService myService) {
        this.myService = myService;
    }
    @Override
    public void run() {
        myService.testMethod();
    }
}
登入後複製
public static void main(String[] args) throws IOException, InterruptedException {
MyService myService = new MyService();
MyThread myThreadA = new MyThread(myService);
        MyThread myThreadB = new MyThread(myService);
        MyThread myThreadC = new MyThread(myService);
        MyThread myThreadD = new MyThread(myService);
        MyThread myThreadE = new MyThread(myService);

        myThreadA.start();
        myThreadB.start();
        myThreadC.start();
        myThreadD.start();
        myThreadE.start();

    }
登入後複製

呼叫 ReentrantLock 物件的 lock() 方法取得鎖定, 呼叫 unLock() 方法釋放鎖定.

#從運行結果來看, 當前執行緒列印完畢之後將鎖定進行釋放, 其他的線程才可以繼續打印. 線程打印的數據是分組打印, 因為當前線程已經持有鎖, 但線程之間打印的順序是隨機的.

使用Condition 實現等待/通知

關鍵字 synchronized 與 wait() 和 notify() / notifyall() 方法結合可以實現等待/通知模式, 只不過在使用時, 呼叫 notify() 方法JVM 會隨機選擇一個WAITNG 狀態的執行緒來執行.

而使用Condition 則可以更加靈活, 可以實現"選擇性通知", 可以指定的選擇喚醒哪些線程, 哪些線程繼續等待.

public class MyService {

    private Lock lock = new ReentrantLock();
    public Condition conditionA = lock.newCondition();
    public Condition conditionB = lock.newCondition();

    public void awaitA() throws InterruptedException {
        lock.lock();

        System.out.println("begin awaitA 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        conditionA.await();

        System.out.println("end awaitA 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        lock.unlock();
    }

    public void awaitB() throws InterruptedException {
        lock.lock();

        System.out.println("begin awaitB 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        conditionB.await();

        System.out.println("end awaitB 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        lock.unlock();
    }

    public void  signalAll_A() throws InterruptedException {
        lock.lock();
        System.out.println("begin signalAll_A 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        conditionA.signalAll();

        lock.unlock();
    }

    public void  signalAll_B() throws InterruptedException {
        lock.lock();
        System.out.println("begin signalAll_B 时间" + System.currentTimeMillis() + "ThreadName=" + Thread.currentThread().getName());

        conditionB.signalAll();

        lock.unlock();
    }
}
登入後複製
public class ThreadA extends Thread {

    private MyService myService;
    public ThreadA(MyService myService) {
        this.myService = myService;
    }

    @Override
    public void run() {
        try {
            myService.awaitA();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
登入後複製
public class ThreadB extends Thread {

    private MyService myService;

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

    @Override
    public void run() {
        try {
            myService.awaitB();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
登入後複製
    public static void main(String[] args) throws IOException, InterruptedException {

        MyService myService = new MyService();

        ThreadA threadA = new ThreadA(myService);
        threadA.setName("a");
        threadA.start();

        ThreadB threadB = new ThreadB(myService);
        threadB.setName("b");
        threadB.start();

        Thread.sleep(3000);
        myService.signalAll_A();

    }
登入後複製
  • #Object 類別中的wait() 方法相當於Condition 類別中的await() 方法.
  • Object 類別中的wait(long timeout) 方法相當於Condition 類別中的await(long time, TimeUnit unit) 方法.
  • Object 類別中的notify() 方法相當於Condition 類別中的signal() 方法.
  • Object 類別中的notifyAll() 方法相當於Condition 類別中的signalAll() 方法.

從執行結果來看, a 和b 執行緒被暫停, 當執行 myService.signalAll_A() 方法時, a 執行緒繼續執行, 而b 執行緒仍然是等待狀態.

#常用方法

ReentrantLock 類別

int getHoldCount() 查詢呼叫lock() 方法的次數.

final int getQueueLength() 估計等待鎖定的執行緒數. 例如有5個執行緒, 1個執行緒先執行await() 方法, 那麼在呼叫此方法後回傳值是4, 說明有4個執行緒同時在等待lock的釋放.

int getWaitQueueLength(Condition condition) 傳回與此鎖定相關聯給定條件等待的執行緒數的估計. 例如有5個執行緒, 每個執行緒都執行了同一個condition 物件的await() 方法, 則呼叫此方法時傳回的值是5.

final boolean hasQueuedThreads() 判斷是否有執行緒等待此鎖定.

final boolean hasQueuedThread(Thread thread) 判斷指定執行緒是否等待取得此鎖定.

boolean hasWaiters(Condition condition) 有沒有呼叫await() 方法.

void lockInterruptibly() throws InterruptedException 取得鎖, 除非目前執行緒為interrupted.

Condition 類別

void awaitUninterruptibly() 和#Condition 類別

void awaitUninterruptibly() 和#Condition 類別 ) 差異就是當呼叫 interrupt() 方法時不會拋出 InterrputedException 異常.

本篇文章到這裡就已經全部結束了,更多其他精彩內容可以關注PHP中文網的

Java視頻教程###專欄! ##########

以上是中ReentrantLock 類別的用法介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:segmentfault.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板