【多線程 四】線程間的通信

1、爲什麼要處理線程間通信 :

當我們需要多個線程共同協作完成一件任務,並且希望他們有規律的執行,那麼此時就需要線程之間進行通信。爲了能達到此種目的我們需要引入一個機制——等待喚醒機制。

2、 等待喚醒機制

這是多個線程間的一種協作機制。
就是在一個線程進行了規定操作後 ,就進入等待狀態 (wait() ), 等待其他線程執行完他們的指定代碼過後 再將 其喚醒 (notify() );在有多個線程進行等待時, 如果需要 ,可以使用 notifyAll()來喚醒所有的等待線程。

2.1 wait() 與notify() 和notifyAll()
wait():令當前線程掛起並放棄CPU、同步資源並等待
  • 在當前線程中調用方法: 對象名.wait()
  • 使當前線程進入等待(某對象)狀態,直到另一線程對該對象發出notify (或notifyAll) 爲止。
  • 調用方法的必要條件:當前線程必須具有對該對象的監控權(加鎖)
  • 調用此方法後,當前線程將釋放對象監控權,然後進入等待
  • 在當前線程被notify後,要重新獲得監控權,然後從斷點處繼續代碼的執行。
notify()/notifyAll()
  • 在當前線程中調用方法: 對象名.notify() 或者 對象名.notifyAll()

  • 功能:喚醒等待該對象監控權的一個或者所有線程。

  • 調用方法的必要條件:當前線程必須調用了wait()

2.2 面試題:

編寫一個程序,開啓三個線程,這三個線程的名字分別爲A,B,C 每個線程將自己的名字打印10次,交替打印,如ABCABCABCABCABCABC…

方法1:jdk1.5 前:wait()、notify()
代碼:

//兩個線程交替執行
public class TestABABAB {
    public static int flag = 1;
    public static void main(String[] args) {
        // 1、線程通信,需要wait notify  但是這兩個必須和synchronize共同使用
        Object objA = new Object();
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 1) {
                            try {
                                objA.wait();             
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 2;
                        objA.notifyAll();
                    }
                }
            }
        }, "A").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 2) {
                            try {
                                objA.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 3;
                        objA.notifyAll();
                    }
                }
            }
        }, "B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (objA) {
                    for (int i = 0; i < 10; i++) {
                        while (flag != 3) {
                            try {
                                objA.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 1;
                        objA.notifyAll();
                    }
                }
            }
        }, "C").start();
    }
}

執行結果:
在這裏插入圖片描述

jdk1.5後 lock() 和condition
Condition 接口描述了可能會與鎖有關聯的條件變量。這些變量在用 法上與使Object.wait 訪問的隱式監視器類似,但提供了更強大的 功能。需要特別指出的是,單個 Lock 可能與多個 Condition 對象關 聯。爲了避免兼容性問題,Condition 方法的名稱與對應的 Object 版 本中的不同。

在 Condition 對象中,與 wait、notify 和 notifyAll 方法對應的分別是 await、signal 和 signalAll。

Condition 實例實質上被綁定到一個鎖上。要爲特定 Lock 實例獲得 Condition 實例,請使用其 newCondition() 方法。

代碼:

public class TestABABAB1 {
    public static int flag = 1;

    public static void main(String[] args) {
        // 1、線程通信,需要wait notify  但是這兩個必須和synchronize共同使用
        Lock lock = new ReentrantLock();
        Condition conditionA = lock.newCondition();
        Condition conditionB = lock.newCondition();
        Condition conditionC = lock.newCondition();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 2) {
                            try {
                                conditionB.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 3;
                        conditionC.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "B").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 3) {
                            try {
                                conditionC.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 1;
                        conditionA.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "C").start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    lock.lock();
                    try {
                        if (flag != 1) {
                            try {
                                conditionA.await();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println(Thread.currentThread().getName());
                        flag = 2;
                        conditionB.signal();
                    } finally {
                        lock.unlock();
                    }
                }
            }
        }, "A").start();
    }
}

下面給一個鏈接:https://www.jianshu.com/p/40078ed436b4 下面是這道題目的四種優雅寫法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章