多線程簡單入門之如何實現通訊

多線程簡單入門之如何實現通訊?

一.什麼是多線程之間通訊?

        多個線程操作同一資源,操作的動作不同。例如某個對某個對象的讀和寫,相當於兩個線程操作該對象作不同的動作。

        該需求代碼如下

/**
 * 多線程之間通訊
 * 2019/11/27
 */

class PeopleTest {
    public String name;

    public String sex;
}

class InputPeople extends Thread {
    private PeopleTest people;

    // 構造函數
    public InputPeople(PeopleTest people) {
        this.people = people;
    }

    @Override
    public void run() {
        int num = 0;
        while (true) {
            if (num == 0) {
                people.name = "莫吊";
                people.sex = "男";
            } else {
                people.name = "翠花";
                people.sex = "女";
            }
            num = (num + 1) % 2;
        }
    }
}

class OutPeople extends Thread {
    private PeopleTest people; // 共享資源實體類對象

    // 構造函數
    public OutPeople(PeopleTest people) {
        this.people = people;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(people.name + "性別--" + people.sex);
        }
    }
}

public class ThreadTest1 extends Thread {
    public static void main(String[] args) {
        PeopleTest people = new PeopleTest();
        InputPeople inputPeople = new InputPeople(people);
        OutPeople outPeople = new OutPeople(people);
        inputPeople.start();
        outPeople.start();
    }
}

運行部門結果如下:

如圖運行結果會出現此情況,是因爲讀和寫兩個線程共享同一資源導致的線程不安全現象。

二.wait()、notify()、notifyAll()方法

        wait()方法和sleep()方法類似,但是wait會釋放鎖和synchronize與notify一起使用。

        他們都在Object類中,對象鎖也就是類鎖,他們都是Object的子類,所以方便所以類都能使用該方法。

        代碼如下:

/**
 * 多線程之間通訊
 * 2019/11/27
 */

class PeopleTest {
    public String name;

    public String sex;

    public boolean aa=false;
}

class InputPeople extends Thread {
    private PeopleTest people;

    // 構造函數
    public InputPeople(PeopleTest people) {
        this.people = people;
    }

    @Override
    public void run() {
        int num = 0;
        while (true) {
            synchronized (people) {
                if (people.aa) {
                    try {
                        // 當前線程等待 可以釋放鎖
                        people.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                if (num == 0) {
                    people.name = "莫吊";
                    people.sex = "男";
                } else {
                    people.name = "翠花";
                    people.sex = "女";
                }
                num = (num + 1) % 2;
                people.aa = true;
                people.notify(); // 喚醒線程
            }
        }
    }
}

class OutPeople extends Thread {
    private PeopleTest people; // 共享資源實體類對象

    // 構造函數
    public OutPeople(PeopleTest people) {
        this.people = people;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (people) {
                if (!people.aa) {
                    try {
                        people.wait();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(people.name + "性別--" + people.sex);
                people.aa = false;
                people.notify();
            }
        }
    }
}

public class ThreadTest1 extends Thread {
    public static void main(String[] args) {
        PeopleTest people = new PeopleTest();
        InputPeople inputPeople = new InputPeople(people);
        OutPeople outPeople = new OutPeople(people);
        inputPeople.start();
        outPeople.start();
    }
}

運行部門如下:

這樣實現了邊寫邊讀的情況,這樣線程不會出現操作錯誤。

三.JDK1.5 lock鎖。

  JDK1.5提供了併發包,lock鎖、線程池Executor。lock獲取鎖資源,unlock釋放鎖。與synchronize類似的同步功能,但不同於synchronize自動獲取鎖、釋放鎖,lock需要手動獲取和釋放鎖。

部分代碼如下:

定義在實體類中是因爲後面需要用到同一把lock鎖

運行結果如下:

現在需要解決的是線程安全問題。 

使用condition的await和signal方法獲取和釋放鎖。

部分代碼如下:

 

實現效果如下: 

達到了邊寫邊讀的要求, 這樣就解決了線程安全問題。

三.怎麼停止線程?

       使用stop方法強行終止線程,但不推薦使用,因爲根據現在的api提示可能會發生不可預料的結果。我們可以使用退出標誌,讓線程正常退出,當run方法完成後終止。

代碼如下:

class StopThread2 extends  Thread{
    /**
     * 多線程通訊 停止線程
     * 2019/11/27
     */
    public boolean aa=true;
    @Override
    public void run(){
        while(aa) {
            System.out.println(Thread.currentThread().getName()+"----這是一個子線程");
        }
    }

    public void Stop(){
        aa=false;
        System.out.println(getName()+"線程停止了。");
    }
}

public class StopThread{
    public static void main(String[] args) {
        StopThread2 stopThread1 = new StopThread2();
        StopThread2 stopThread2 = new StopThread2();
        stopThread1.start();
        stopThread2.start();
        for (int i=0;i<30;i++) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("這是一個主線程..");
            if (i == 29) {
                stopThread1.Stop();
                stopThread2.Stop();
            }

        }
        }
}
運行結果如下:

注:這裏是因爲線程被停止了,還是還在執行,但是這樣還是不合理,應中斷線程。 

四.怎樣中斷線程?

代碼如下:

class StopThread2 extends  Thread{
    /**
     * 多線程通訊 停止線程
     * 2019/11/27
     */
    public boolean aa=true;
    @Override
    public synchronized void run(){
        while(aa) {
            try{
                wait();
            }catch (Exception e){
               Stop();
            }
            System.out.println(Thread.currentThread().getName()+"----這是一個子線程");
        }
    }

    public void Stop(){
        aa=false;
        System.out.println(getName()+"線程停止了。");
    }
}

public class StopThread{
    public static void main(String[] args) {
        StopThread2 stopThread1 = new StopThread2();
        StopThread2 stopThread2 = new StopThread2();
        stopThread1.start();
        stopThread2.start();
        for (int i=0;i<30;i++) {
            try {
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println("這是一個主線程..");
            if (i == 29) {
                stopThread1.interrupt();
                stopThread2.interrupt();
            }

        }
        }
}

注:這裏我沒有拋異常,調用的stop方法。 

運行結果:

線程被中斷了。 

五.怎樣守護線程?

  java中有兩種線程:一種守護線程(主線程);一種用戶線程。

  當進程不存在或主線程停止,守護線程也會被停止。 使用setDaemon(true)方法設置爲守護線程。

注:該博客純個人學習筆記,歡迎交流

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