天天看點

java多線程中等待/通知機制

一個線程做了修改對象值(或其他)操作,另一個線程感覺到了變化,然後進行相應操作,整個過程開始于一個線程,最終執行又是另外一個線程。前者是生産者,後者是消費者,這種模式隔離了“做什麼”和“怎麼做”,實作了業務上的解耦。

其具體實作方式是線程A調用了對象O的wait()方法進入等待狀态,另一個線程B調用對象B的notify() or notifyAll()方法,線程A收到通知後從對象O的wait()方法傳回,進而執行後續操作 。其邏輯流程如下:

thread 得到object 的 monitor, 調用 object.wait() 
  - 釋放object 的 monitor, thread wait;

thread 得到 object 的 monitor, 調用 object.notify() 
  - 激活thread, 釋放object 的 monitor;

thread 得到 object 的 monitor, 從object.wait()傳回, thread接着執行.
           

示範demo如下:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

public class WaitNotify {
    static boolean flag = true;
    static Object lock = new Object();

    public static void main(String[] args) throws Exception {
        Thread waitThread = new Thread(new Wait(), "WaitThread");
        waitThread.start();
        TimeUnit.SECONDS.sleep(1);

        Thread notifyThread = new Thread(new Notify(), "NotifyThread");
        notifyThread.start();
    }

    static class Wait implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                while (flag) {
                    try {
                        System.out.println(Thread.currentThread() + " flag is true. wait @ "
                                + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                        lock.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(Thread.currentThread() + " flag is false. running @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            }
        }
    }

    static class Notify implements Runnable {
        @Override
        public void run() {
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock. notify @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                lock.notifyAll();
                flag = false;
                SleepUtils.second(5);
            }
            synchronized (lock) {
                System.out.println(Thread.currentThread() + " hold lock again. sleep @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                SleepUtils.second(5);
            }
        }
    }
}
           

繼續閱讀