1. 程式人生 > 其它 >Java多執行緒06:執行緒通訊

Java多執行緒06:執行緒通訊

Synchronized實現了同步,但不能用實現不同執行緒之間的訊息傳遞

  • wait()方法表示執行緒一直等待,直到其他執行緒通知,與sleep()不同,wait()會釋放鎖

  • notify()方法喚醒一個處於等待的執行緒

  • notifyAll()方法喚醒同一個物件上所有呼叫wait()方法的執行緒,優先順序高的執行緒優先排程

  • 只能在Synchronized同步方法和同步塊中使用,否則丟擲異常

管程法

import java.util.ArrayList;

public class Hello {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList();
        Consumer consumer = new Consumer(arrayList);
        Producer producer = new Producer(arrayList);

        //生產消費各十次(注意不能在run()方法裡迴圈十次,不然會生產完所有蘋果再消費)
        for (int i = 0; i < 10; i++) {
            new Thread(consumer).start();
            new Thread(producer).start();
        }
    }
}

//定義消費者類
class Consumer implements Runnable{
    //定義列表集合放置蘋果
    ArrayList<Integer> arrayList;

    public Consumer(ArrayList arrayList){
        this.arrayList = arrayList;
    }

    @Override
    public void run() {
        //wait()和notify()方法只能在同步塊和同步方法中使用
        synchronized (arrayList) {
            if (arrayList.size() == 0) {
                System.out.println("蘋果沒有了,需要生產");
                try {
                    //wait()方法讓執行緒進入等待,釋放鎖給生產執行緒
                    //沒有蘋果時消費者進入等待,收到喚醒後才會繼續執行後續的程式碼
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
			
            //為了避免生產完立即被消費,設定一個延時
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (arrayList.size() != 0){
                arrayList.remove(0);
                System.out.println("消費了一個蘋果,還剩" + arrayList.size() + "個");
            }
            //notify()方法喚醒生產執行緒
            arrayList.notify();
        }
    }
}

//定義生產者類
class Producer implements Runnable{
    ArrayList<Integer> arrayList;
    //定義盤子滿的數量
    int max = 10;

    public Producer(ArrayList arrayList){
        this.arrayList = arrayList;
    }

    @Override
    public void run() {
        synchronized (arrayList) {
            if (arrayList.size() == max) {
                System.out.println("盤子滿了,需要消費");
                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            arrayList.add(1);
            System.out.println("生產了一個蘋果,還剩" + arrayList.size() + "個");
            arrayList.notify();
        }
    }
}

訊號燈法

import java.util.ArrayList;

public class Hello {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList();
        //定義一個標誌,為了保證其他執行緒指向的是同一個標誌,需要使用包裝類建立引用物件
        Boolean flag = new Boolean(true);
        Consumer consumer = new Consumer(arrayList, flag);
        Producer producer = new Producer(arrayList, flag);
        for (int i = 0; i < 10; i++) {
            new Thread(consumer).start();
            new Thread(producer).start();
        }
    }
}

//定義消費者類
class Consumer implements Runnable{
    ArrayList<Integer> arrayList;
    Boolean flag = new Boolean(true);

    public Consumer(ArrayList arrayList, boolean flag){
        this.arrayList = arrayList;
        this.flag = flag;
    }

    @Override
    public void run() {
        synchronized (arrayList) {
            if (flag) {
                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //當列表長度不為0時,可以消費蘋果
            if (arrayList.size() != 0){
                arrayList.remove(0);
                System.out.println("消費了一個蘋果,還剩" + arrayList.size() + "個");
            }
			
            //反轉標誌位,讓生產者執行緒執行
            flag = false;
            arrayList.notify();
        }
    }
}

//定義生產者類
class Producer implements Runnable{
    ArrayList<Integer> arrayList;
    Boolean flag = new Boolean(true);

    public Producer(ArrayList arrayList, boolean flag){
        this.arrayList = arrayList;
        this.flag = flag;
    }

    @Override
    public void run() {
        synchronized (arrayList) {
            if (!flag) {
                try {
                    arrayList.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            arrayList.add(1);
            System.out.println("生產了一個蘋果,還剩" + arrayList.size() + "個");
            flag = true;
            arrayList.notify();
        }
    }
}