JUC之執行緒間定製化通訊

xbhog發表於2022-01-01

執行緒通訊之定製化

之前文章中寫了下Condition的使用,這裡我們詳細說下其中的用法:

首先使用Condition需要例項化Lock

private Lock lock = new ReentrantLock();   //建立鎖

使用lock裡面的newCondition方法建立Condition物件:

private Condition c1 = lock.newCondition();

其優點:比synchronized更安全、更高效。

選自:廖雪峰的官網-Java教程

Condition提供的await()signal()signalAll()原理和synchronized鎖物件的wait()notify()notifyAll()是一致的,並且其行為也是一樣的:

  • await()會釋放當前鎖,進入等待狀態;
  • signal()會喚醒某個等待執行緒;
  • signalAll()會喚醒所有等待執行緒;
  • 喚醒執行緒從await()返回後需要重新獲得鎖。

需要注意的是上面signal\signalAll與await方法的對應關係;

通過一個例子來理解執行緒間的定製化:

要求:

image-20211230213747403

實現程式碼:

package com.JUC;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
//執行緒間的定製化通訊
class ShareRewsource {
    private int flag = 1;  //1表示執行緒AAA,2表示執行緒BBB,3表示執行緒CCC

    private Lock lock = new ReentrantLock();   //建立鎖
    //代替Object中的等待、喚醒等操作,更加的安全高效
    private Condition c1 = lock.newCondition();  //對標AAA執行緒
    private Condition c2 = lock.newCondition();  //對標BBB執行緒
    private Condition c3 = lock.newCondition();  //對標CC執行緒

    //建立方法
    public void print5(int loop) {
        lock.lock();
        try {
            while (flag != 1) {
                c1.await();
            }
            //操作
            for (int i = 1; i <= 5; i++) {
                System.out.println(Thread.currentThread().getName() + "-----" + i + "::" + loop);
            }
            flag = 2;
            c2.signal();  //通知BBB執行緒  喚醒BBB執行緒,喚醒後在BBB執行緒的await後繼續執行;

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    //建立方法
    public void print10(int loop) {
        lock.lock();
        try {
            while (flag != 2) {
                c2.await();
            }
            //操作
            for (int i = 1; i <= 10; i++) {
                System.out.println(Thread.currentThread().getName() + "-----" + i + "::" + loop);
            }
            flag = 3;
            c3.signal();  //通知CCC執行緒

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

    //建立方法
    public void print15(int loop) {
        lock.lock();
        try {
            while (flag != 3) {
                c3.await();
            }
            //操作
            for (int i = 1; i <= 15; i++) {
                System.out.println(Thread.currentThread().getName() + "-----" + i + "::" + loop);
            }
            flag = 1;
            c1.signal();  //通知AAA執行緒

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }

}

public class ThreadPrivateDemo {
    public static void main(String[] args) {
        ShareRewsource rewsource = new ShareRewsource();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                rewsource.print5(i);
            }
        }, "AAA").start();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                rewsource.print10(i);
            }
        }, "BBB").start();
        new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                rewsource.print15(i);
            }
        }, "CCC").start();
    }
}

其中對應關係:注意喚醒和等待所在的程式碼段

c2.signal() --> c2.await()

c3.signal() --> c3.await()

c1.signal() --> c1.await()

相關文章