【Java多線程】wait()和join()被中斷的過程

目錄

1 wait()被中斷的過程

1.1 代碼示例

1.2 結果分析

2 join()被中斷過程

2.1 代碼示例

2.2 結果分析


1 wait()被中斷的過程

1.1 代碼示例

開啓兩個線程,一個線程等待,另一個線程獲取鎖後打印信息,打印期間對等待線程進行中斷,通過打印的控制檯信息來查看中斷過程。

public class Test3 {
    static Object lock = new Object();      // 同步鎖和等待鎖

    public static void main(String[] args) throws InterruptedException {
        MyThread myThread1 = new MyThread("線程1", true);
        MyThread myThread2 = new MyThread("線程2", false);

        myThread1.start();
        Thread.sleep(100);              // 給myThread1啓動留時間
        myThread2.start();              // 給myThread2啓動留時間
        Thread.sleep(100);
        System.out.println(myThread1.getName()+":狀態爲"+myThread1.getState());
        myThread1.interrupt();
        Thread.sleep(100);              // 給中斷操作留時間
        System.out.println(myThread1.getName()+":被中斷");
        System.out.println(myThread1.getName()+":狀態爲"+myThread1.getState());
    }

    private static class MyThread extends Thread{
        volatile boolean wait;              // 等待標誌,true則線程會在run()中等待

        MyThread(String name, boolean wait){
            super(name);
            this.wait = wait;
        }

        @Override
        public void run() {
            synchronized (lock){
                if (wait){
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        System.out.println(this.getName()+":被中斷後的打印信息");
                    }
                }else{
                    int i = 3;
                    while (i-- > 0){                        // 每隔1s打印,打印3次
                        try {
                            Thread.sleep(1000);
                            System.out.println("printInfo");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                System.out.println(this.getName()+":釋放鎖");
            }
        }
    }
}

打印結果如下:

線程1:狀態爲WAITING
線程1:被中斷
線程1:狀態爲BLOCKED
printInfo
printInfo
printInfo
線程2:釋放鎖
線程1:被中斷後的打印信息
線程1:釋放鎖

Process finished with exit code 0

1.2 結果分析

顯然,對wait的線程進行中斷首先將線程從等待隊列移到阻塞隊列(線程狀態由WAITING——>BLOCKED),然後等待鎖被釋放,釋放後才拋出InterruptedException,打印catch中的信息。

2 join()被中斷過程

2.1 代碼示例

在join線程執行期間,對joined線程進行中斷。

public class Test4 {
    public static void main(String[] args) throws InterruptedException {
        MyThread join = new MyThread("join線程", false, null);
        join.start();
        MyThread interruptThread = null;
        for (int i=1;i<=10;++i){                        // 創建10個線程
            MyThread joined = new MyThread("joined線程"+i, true, join);
            joined.start();
            if (i == 5){                                // 中斷第5個線程
                interruptThread = joined;
            }
        }
        Thread.sleep(1000);                             // 留出時間給join線程運行
        interruptThread.interrupt();
        System.out.println(interruptThread.getName()+":被中斷");
    }

    private static class MyThread extends Thread{
        boolean joined;                             // true表示該線程是joined線程,false爲join線程
        Thread joinThread;

        MyThread(String name , boolean joined , Thread joinThread){
            super(name);
            this.joined = joined;
            this.joinThread = joinThread;
        }

        @Override
        public void run() {
            if (joined){
                try {
                    joinThread.join();
                    System.out.println(this.getName()+":被notify後的打印信息");
                } catch (InterruptedException e) {
                    System.out.println(this.getName()+":被中斷後的打印信息");
                }
            }else{
                int i = 3;
                while (i-- > 0){                        // 每隔0.5s打印,打印3次
                    try {
                        Thread.sleep(500);
                        System.out.println(this.getName()+":printInfo");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

打印結果如下:

join線程:printInfo
joined線程5:被中斷
joined線程5:被中斷後的打印信息
join線程:printInfo
join線程:printInfo
joined線程10:被notify後的打印信息
joined線程6:被notify後的打印信息
joined線程2:被notify後的打印信息
joined線程1:被notify後的打印信息
joined線程9:被notify後的打印信息
joined線程7:被notify後的打印信息
joined線程3:被notify後的打印信息
joined線程8:被notify後的打印信息
joined線程4:被notify後的打印信息

Process finished with exit code 0

2.2 結果分析

顯然,被中斷的joined線程在join線程運行期間直接返回並拋出了InterruptedException。其實join()就相當於joined線程在synchronized中執行了join線程對象的wait(),因爲join方法被synchronized關鍵字修飾了,執行join()必須獲取到join線程對象這個鎖,與wait()中斷的過程一模一樣。

在上面例子中,因爲join線程對象沒有在我們代碼其它地方作爲synchronized的鎖被其它線程持有,所以joined線程5被中斷之後能立刻獲取鎖從join()返回。Thread.join()如下:

public final synchronized void join(long millis) throws InterruptedException {
    ...
    while (isAlive()) {
        wait(0);
    }
    ...
}

 

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