Java併發學習(二)-線程通信

線程通信

    線程間通信的模型有兩種:共享內存和消息傳遞;

    (1)共享內存

         使用 volatile 關鍵字來實現線程間相互通信是使用共享內存的思想,大致意思就是多個線程同時監聽一個變量,當這個變量發生變化的時候 ,線程能夠感知並執行相應的業務。 volatile 關鍵字對於保證操作的原子性具有非常大的幫助,但是需要注意的是,volatile 關鍵字並不能替代鎖,它也無法保證一些複合操作的原子性。

    (2)消息傳遞

         Object類提供了線程間通信的方法:wait()notify()notifyaAll(),它們是多線程通信的基礎。

         wait():等待,一旦一個線程執行到wait(),就釋放當前的鎖

         notify()notifyaAll():隨機喚醒wait()的一個或所有的線程。

         注意: wait和 notify必須配合synchronized使用。必須包含在對應的synchronized語句中。

 

案例

     下面通過以下案例,使用上述兩種方式實現線程之間的通信。

     案例:使用兩個線程交替打印1-100。

    (方式一)使用 volatile 關鍵字

package com.test.communication;

/**
 * 通過關鍵字volatile,實現使用兩個線程交替打印1-100
 *
 * @author Anna.
 */
public class ThreadCommunicationTest01 {
    volatile static int num = 1;
    volatile static boolean flag = true;
    public static void main(String[] args) {

        Thread th = new Thread(new Runnable(){
            @Override
            public void run() {
                while (true) {
                    if (flag) {
                        if (num <= 100) {
                            System.out.println(Thread.currentThread().getName() + ":" + num);
                            num++;
                            flag = !flag;
                        }
                    }
                }
            }
        });

        Thread th2 = new Thread(new Runnable(){
            @Override
            public void run() {
                while (true) {
                    if (!flag) {
                        if (num <= 100) {
                            System.out.println(Thread.currentThread().getName() + ":" + num);
                            num++;
                            flag = !flag;
                        }
                    }  
                }
            }
        });

        th.setName("甲");
        th2.setName("乙");
        th.start();
        th2.start();
    }
}

打印結果:

如果去掉關鍵字,那麼線程甲執行完成後,線程乙無法得知,flag的值發生改變,那麼打印結果如下:

    (方式二)使用 wait()、notify()、notifyaAll()消息傳遞的方式

package com.test.communication;

/**
 * 使用 wait()、notify()、notifyaAll()消息傳遞的方式,實現使用兩個線程交替打印1-100
 *
 * @author Anna.
 */
public class ThreadCommunicationTest02 {

    public static void main(String[] args) {
        PrintNum pm = new PrintNum(1);
        Thread th = new Thread(pm);
        Thread th2 = new Thread(pm);
        th.setName("甲");
        th2.setName("乙");
        th.start();
        th2.start();
    }
}

class PrintNum implements Runnable{
    int num;
    public PrintNum(int num){
        this.num = num;
    }
    @Override
    public synchronized void run() {

        while (true) {
            notify();
            if (num <= 100) {
                System.out.println(Thread.currentThread().getName() + ":" + num);
                num++;
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

打印結果:

如果去掉synchronized關鍵字,將拋出IllegalMonitorStateException異常,如下:

 

 

 

 

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