Java多线程:3.多线程的停止

一、如何正确的停止线程

使用interrupt来通知,而不是强制。
interrupt,即中断,需要停止线程时,需要另外一个线程向该线程通知你该中断了,而何时中断,停不停止,是由该线程自己决定的,外部并没有方法直接操作它。
线程何时会停止:

  • run()方法中的代码都已经执行完毕了。
  • 线程进行业务逻辑处理时抛出异常了。

二、使用interrupt停止线程

1.普通情况下停止线程

先尝试使用thread.interrupt()中断该线程。

/**
 * 普通情况下停止线程
 */
public class StopThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Work());
        thread.start();

        // 线程启动后1s,通知中断
        Thread.sleep(1000);
        thread.interrupt();
    }
}

// 任务:打印出小于999999999的所有1000的倍数的数
class Work implements Runnable{
    @Override
    public void run() {
        for(int num=0; num < 999999999; num ++){
            if(num % 1000 == 0){
                System.out.println(num);
            }
        }
        System.out.println("任务完成");
    }
}

发现即使调用了thread.interrupt(),线程并没有中断。因为线程中没有对这个中断进行响应,需要在线程中添加一些响应中断的代码:

// 任务:打印出小于999999999的所有1000的倍数的数
class Work implements Runnable{
    @Override
    public void run() {
        for(int num=0; num < 999999999; num ++){
            // 判断中断
            if(Thread.currentThread().isInterrupted()){
                break;
            }

            if(num % 1000 == 0){
                System.out.println(num);
            }
        }
        System.out.println("任务完成");
    }
}
2.在阻塞的情况下停止线程

线程在sleep阻塞时,收到主线程发来的中断通知:

/**
 * 线程中有sleep阻塞的情况下停止线程
 */
public class StopThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Work());
        thread.start();

        // 线程启动后1s,通知中断
        Thread.sleep(500);
        thread.interrupt();
    }
}

// 任务:打印出小于300的数
class Work implements Runnable{
    @Override
    public void run() {
        for(int num=0; num < 300; num ++){
            // 判断中断
            if(Thread.currentThread().isInterrupted()){
                break;
            }

            System.out.println(num);
        }

        // 阻塞等待其他业务逻辑
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("任务完成");
    }
}

会发现抛出了异常,即sleep时收到中断
在这里插入图片描述

3.在每次迭代后都阻塞的情况下停止线程

每次迭代都有sleep阻塞,而阻塞的特点就是它本身就能响应中断而抛出异常去停止线程,这种情况下我们就不需要手动去写响应中断的代码了。

/**
 * 线程中每次循环都会有sleep阻塞的情况下停止线程
 */
public class StopThreadTest {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new Work());
        thread.start();

        // 线程启动后1s,通知中断
        Thread.sleep(2000);
        thread.interrupt();
    }
}

// 任务:打印出小于10000的数
class Work implements Runnable{
    @Override
    public void run() {
        try {
            for(int num=0; num < 10000; num ++){
                System.out.println(num);

                Thread.sleep(10);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("任务完成");
    }
}

在这里插入图片描述

4.sleep会清除中断标志的问题

如果 try{ sleep }catch 放在循环内,当sleep响应中断后,会清除中断标志位,所以即使我们使用Thread.currentThread().isInterrupted()来手动响应中断,也不会停止线程。

// 任务:打印出小于10000的数
class Work implements Runnable{
    @Override
    public void run() {
        for(int num=0; num < 10000; num ++){
            // 手动响应
            if(Thread.currentThread().isInterrupted()){
                break;
            }

            System.out.println(num);

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        System.out.println("任务完成");
    }
}

在这里插入图片描述


三、实际开发中最好的两种停止线程的方法

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