Java多線程-線程間通信

一,等待/通知機制  實現線程間的通信

舉個例子:我們去飯店就餐,飯店上餐的時間不確定,如果我們一直去詢問前臺,是不是很煩,我麼這時就處於等待(wait)狀態,但是 飯店肯定會有人肯定會通知 (notify),那個桌的菜已經做好了,前臺就會通知這桌的人,菜來了。

1,主要的方法wait() /notify() 這個兩個方法時Object類本地方法 都要在同步方法中調用

          1),wait() 使執行當前代碼的線程進行等待,執行完畢後,線程就會釋放鎖,以便別的線程可以獲得鎖。

           2),notify(),隨機挑選一個處於wait()的線程,讓他獲得鎖,但這個方法不會立即釋放當前線程的對象鎖,只有程序執行完畢後,纔會釋放鎖。

           3)sleep()方法,這個方法也是不是放鎖的 ,那麼別的線程要獲取這個鎖就會處於等待狀態。

           4),在調用wait()方法後,使線程處於wait狀態,這時如果調用interrupt()就會出現InterrruptedException異常

           5),notify()方法一次只會通知一個線程。notifyAll()通知所有的線程

二,使用等待/通知機制,實現生產者/消費者模式

/**
 * 通知等待機制 實現消費者者/生產者模式
 */
public class PCDemo {
    //消費品
    public static class Data{
        public static String value = " ";
    }
    //生產者
    public static class Producer{
        private String lock;
        public Producer(String value){
            this.lock = value;
        }
        public void setValue() throws Exception{
           synchronized (lock){
               if (!Data.value.equals(" ")){  //說明value沒有被消費
                   lock.wait();
               }else{
                   String s = System.currentTimeMillis()+" ";
                   System.out.println("設置的value = " + s+"  當前線程的Name = "+Thread.currentThread().getName());
                   Data.value = s;//生產數據
                   lock.notify();//通知等待的消費者去消費
               }
           }
        }
    }
    //消費者
    public static class Consumer{
        private String lock;
        public Consumer(String lock){
            this.lock = lock;
        }
        public void getValue() throws Exception{
            synchronized (lock){
                if (Data.value.equals(" ")){ //說明生產者沒有生產數據
                    lock.wait();//消費者等待
                }else {
                    System.out.println("消費者獲得的值 "+ Data.value+"  當前線程的Name = "+Thread.currentThread().getName());
                    Data.value = " ";//模擬把數據消費了
                    lock.notify();//通知生產者趕快生產數據 ,我已經消費完了
                }
            }
        }
    }

    //生產者線程
    public static class ProThread implements Runnable{
        private Producer producer;
        public ProThread(Producer p){
            this.producer = p;
        }

        @Override
        public void run() {
            while (true){
                try {
                    producer.setValue();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    //消費者線程

    public static class ConThread implements Runnable{
        private Consumer consumer;
        public ConThread(Consumer consumer){
            this.consumer = consumer;
        }
        @Override
        public void run() {
            try {
                while (true){
                    consumer.getValue();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws Exception{
        String lock = new String(" ");//使用同一個鎖對象
        Thread p = new Thread(new ProThread(new Producer(lock)));
        Thread c = new Thread(new ConThread(new Consumer(lock)));
        p.setName("Producer");
        c.setName("Consumer");
        p.start();
        c.start();
    }
}

運行部分截圖

這時一個生產者,一個消費者的情況,兩個線程交替執行。

若果有多個消費者,多個生產者,則有可能產生“假死”現象,就是所有的線程都處於waitting,因爲notify()方法一次只能使一個處於waitting狀態的線程掉起來。解決辦法使用notifiyAll()方法即可。

三,join():等待線程對象銷燬,一個主線程要等待子線程結束在自行結束。

1,join()內部其實使用的是wait(),

 public final synchronized void join(long millis)
    throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

join()方法具有使線程排隊執行的作用,類似與同步的效果,但和synchroized的原理不同,後者使用 “對象監視器”原理

 

 

 

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