Java線程中斷的三種方法


多線程編程中耗時線程是很常見的情況,有時候我們不得不在一個線程中去終止另一個耗時線程。JDK並不推薦直接停止比如this.stop(),這會導致一些異常,比如鎖未釋放程序一直死鎖。JDK推薦使用一個線程去通知耗時線程該結束線程了,耗時線程做退出前的回收處理然后自己結束線程。

自定義標志位終止

使用volatile 修飾的變量isExit控制線程的退出,這種方法需要不斷及時判斷isExit的值

public class FinishThreadLearn {
    public static void main(String[] args) throws InterruptedException {
        InterruptStopThread threadA = new InterruptStopThread("A");
        threadA.start();
        Thread.sleep(100);
        System.out.println("終止線程");
        threadA.isExit=true;
    }
}

class InterruptStopThread extends Thread {
    private String name;
    public volatile boolean isExit = false;

    public InterruptStopThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        while (!isExit) {
            System.out.println("Thead:" + this.name + "正在運行");
        }
        System.out.println("線程結束運行");
    }
}

輸出結果可以看到,線程並未立即終止,結束循環體后才最終結束線程。

 

 

 

interrupt() 方式終止

正常執行的代碼

public class FinishThreadLearn {
    public static void main(String[] args) throws InterruptedException {
        InterruptStopThread threadA = new InterruptStopThread("A");
        threadA.start();
        Thread.sleep(100);
        System.out.println("終止線程");
        threadA.interrupt();
    }
}

class InterruptStopThread extends Thread {
    private String name;
    public volatile boolean isExit = false;

    public InterruptStopThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        while (!isInterrupted()) {
            System.out.println("Thead:" + this.name + "正在運行");
        }
        System.out.println("線程結束運行");
    }
}

執行結果

 

處於阻塞休眠的代碼

這里有點不一樣,interrupt()方式中斷阻塞會把標志位清除並報出InterruptedException異常,所以要在catch的時候退出。

public class FinishThreadLearn {
    public static void main(String[] args) throws InterruptedException {
        InterruptStopThread threadA = new InterruptStopThread("A");
        threadA.start();
        Thread.sleep(2000);
        System.out.println("終止線程");
        threadA.interrupt();
    }
}

class InterruptStopThread extends Thread {
    private String name;
    public volatile boolean isExit = false;

    public InterruptStopThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        while (true) {
            System.out.println("Thead:" + this.name + "正在運行");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                break;
            }
        }
        System.out.println("線程結束運行");
    }
}

執行結果

 

 

 

stop()強行停止

public class FinishThreadLearn {
    public static void main(String[] args) throws InterruptedException {
        InterruptStopThread threadA = new InterruptStopThread("A");
        threadA.start();
        Thread.sleep(100);
        System.out.println("終止線程");
        threadA.stop();
    }
}

class InterruptStopThread extends Thread {
    private String name;
    public volatile boolean isExit = false;

    public InterruptStopThread(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        while (!isInterrupted()) {
            System.out.println("Thead:" + this.name + "正在運行");
        }
        System.out.println("線程結束運行");
    }
}

從執行結果可以看到,run方法並未完全執行完就結束了,所以這種方法不推薦使用

 

 

源碼分析

Thread源碼中使用了一個volatile修飾的標志位控制終止信號

public class Thread implements Runnable {
    ...
    /* Interrupt state of the thread - read/written directly by JVM */
    private volatile boolean interrupted;
    ...
}

interrupt方法會使標志位變為true

 

判斷線程是否終止JDK提供了兩種方式

Thread.interrupted():測試當前線程是否已經中斷
this.isInterrupted():測試線程是否已經中斷

 this.isInterrupted()

調用isInterrupted會返回該標志位

 

 Thread.interrupted()

 調用interrupted會返回該標志位,如果為ture會將標志位清空,且這個方法為靜態方法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM