Java: Java終止線程的幾種方式


首先說明,使用stop方法終止的方式已經在很久之前就被廢棄了,在加鎖的情況下有可能會造成死鎖,這里不做討論。

1. 使用標志位終止線程

在run()方法執行完畢后,該線程就終止了。但是在某些特殊的情況下,希望run()方法中的代碼一直循環執行。比如在服務端程序中可能會使用 while(true) { ... } 這樣的循環結構來不斷的接收來自客戶端的請求。此時就可以用修改標志位的方式來結束 run() 方法。例:

public class ServerThread extends Thread {
    //volatile修飾符用來保證其它線程讀取的總是該變量的最新的值
    public volatile boolean exit = false; 

    @Override
    public void run() {
        ServerSocket serverSocket = new ServerSocket(8080);
        while(!exit){
            serverSocket.accept(); //阻塞等待客戶端消息
            ...
        }
    }
    
    public static void main(String[] args) {
        ServerThread t = new ServerThread();
        t.start();
        ...
        t.exit = true; //修改標志位,退出線程
    }
}

Note:一定要給標志位加上volatle 關鍵字!詳細原因可參考:https://www.cnblogs.com/yongdaimi/p/9566332.html 或者 https://www.cnblogs.com/dolphin0520/p/3920373.html 。 

2. 使用interrupt()方法來終止線程

interrupt()方法用於中斷線程,調用該方法的線程狀態將會被置為“中斷狀態”。
Note: 線程中斷僅僅是置線程的中斷狀態位,不會停止線程。需要用戶自己去監視線程的狀態為並做處理。java中的那些支持線程中斷的方法(也就是線程中斷后會拋出interruptedException的方法)就是在監視線程的中斷狀態,一旦線程的中斷狀態被置為“中斷狀態”,就會拋出中斷異常。

調用這種方式去終止的線程存在兩種情況:

第一種情況:該線程循環執行不會存在阻塞
比如,在while 循環中循環打印一句話:這樣的話調用interrupt()會立即終止該線程。例:

package com.yongdaimi.java.demo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Test3 {
    
    
    public static void main(String[] args) {
        NotInterruptThread mNotInterruptThread = new NotInterruptThread();
        mNotInterruptThread.start();
        
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        mNotInterruptThread.interrupt();
    }

    
    static class NotInterruptThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                System.out.println("=============NotInterruptThread execute... =============");
            }
        }
        
    }
    
}

運行結果:

=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
=============NotInterruptThread execute... =============
5 秒后,打印就會停止。

第二種情況:該線程循環執行存在阻塞狀態
比如,在線程中存在sleep()、await()、wait(long) 這種能夠拋出:interruptedException 異常的方法,這種情況調用interrupt()方法后將會觸發這些異常,可以選擇在觸發異常后調用break來終止線程。例:

package com.yongdaimi.java.demo;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Test3 {
    
    
    private static Object sLock = new Object();
    

    private static ReentrantLock sReentrantLock = new ReentrantLock();
    private static Condition sSuspendCondition = sReentrantLock.newCondition();
    
    public static void main(String[] args) {
        /*NotInterruptThread mNotInterruptThread = new NotInterruptThread();
        mNotInterruptThread.start();
        
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        mNotInterruptThread.interrupt();
        */
        
        
        InterruptThread interruptThread = new InterruptThread();
        interruptThread.start();
        
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        interruptThread.interrupt();
        
        
        /*InterruptThread1 interruptThread1 = new InterruptThread1();
        interruptThread1.start();
        
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
        interruptThread1.interrupt();*/
        
        /*InterruptThread2 interruptThread2 = new InterruptThread2();
        interruptThread2.start();
        
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }
        
        interruptThread2.interrupt();*/
        
        /*sReentrantLock.lock();
        try {
            sSuspendCondition.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            sReentrantLock.unlock();
        }*/
        
        
    }

    
    

    static class NotInterruptThread extends Thread {
        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                System.out.println("=============NotInterruptThread execute... =============");
            }
        }
        
    }
    
    
    static class InterruptThread extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                System.out.println("=============InterruptThread execute... =============");
                try {
                    Thread.sleep(50000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        }
    }
    
    
    static class InterruptThread1 extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                synchronized (sLock) {
                    System.out.println("=============InterruptThread execute... =============");
                    try {
                        sLock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
        }
    }
    

    
    static class InterruptThread2 extends Thread {

        @Override
        public void run() {
            super.run();
            while (!isInterrupted()) {
                sReentrantLock.lock();
                try {
                    System.out.println("=============InterruptThread execute... =============");
                    sSuspendCondition.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                } finally {
                    sReentrantLock.unlock();
                }
            }
        }
    }
    
    
}

我這里分別演示了使用sleep()、wait()、await()的方式來阻塞線程,然后在主線程休眠一段時間后嘗試去中斷,子線程中收到異常后調用break退出循環,實際試驗都可以正常退出循環。

參考鏈接:

1. interrupt、interrupted 、isInterrupted 區別

2. Java終止線程的三種方法

 


免責聲明!

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



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