多线程之如何打断线程

一、概述

打断线程,你想到了什么?Thread.stop()方法吗?但是这个方法已经被废弃掉了,使用这个方法会产生很多问题。Thread.interrupt()方法呢?遗憾的是,这个方法并不能打断线程,只是提供一个信号量而已,要想通过这个方法来打断线程,还需要自己去判断这个信号量,然后用这几的逻辑来打断线程。

二、interrupt方法抛出异常

在多线程中,有些方法天生接收打断信号量,如果发生打断指令,会抛出异常,比如:sleep(long tiome)、wait(long time) 、join()等。这些方法在执行中,如果被打断,会抛出InterruptedException异常,从而结束这些方法,但是并没有打断线程,线程接着运行后面的逻辑。

public class InterruptThread {
    private static Thread thread;

    //线程方法
    public static void worker() {
        thread = new Thread(() -> {
            try {
                Thread.sleep(500000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程被打断了....");
        });
        thread.start();
    }

    public static void main(String[] args) {
        worker();
        //打断线程
        thread.interrupt();
    }
}

结果显示,“线程被打断了…”,所以线程并没有真正的被打断。所以,如果将上面的方法改成while(true)循环,按照上面的逻辑,线程是不能被结束掉的。

三、通过interrupt方式打断线程

线程调用interrupt方法打断线程,然后通过方法interrupted方法,可以获取到打断信号。通过这个信号,可以在代码逻辑中停止线程。

public class ThreadInterruptGracefulLearn {
    private static class Work extends Thread {
        @Override
        public void run() {
            while (true) {
                System.out.println("子线程运行中.....");
                if(Thread.interrupted()) {
                    System.out.println("子线程被打断.....");
                    break;
                }
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Work work = new Work();
        work.start();
        //等待子线程运行100毫秒,如果100毫秒没有运行结束,那么就打断线程
        work.join(100L);
        work.interrupt();
        Thread.sleep(1000L);
        System.out.println("主线程结束.....");
    }
}

四、通过开关的方式打断线程

通过开关的方式打断异常时,需要定义一个volatile标识的变量,通过判断这个变量来打断线程

public class ThreadInterruptGracefulLearn01 {

    private static class Work extends Thread {
        //注意volatile关键字,保证变量的可见性
        private volatile boolean start = true;

        @Override
        public void run() {
            while (start) {
                System.out.println("子线程在运行中.....");
            }
        }

        public void shutDown() {
            this.start = false;
            System.out.println("子线程被停止.....");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Work work = new Work();
        work.start();
        //主线程等待3秒,3秒之后work还没有执行完成,那么就停止它
        work.join(3000L);
        if(work.isAlive()) {
            work.shutDown();
        }
        System.out.println("主线程结束.....");
    }
}

五、暴力打断线程

将工作线程设置为守护线程,那么主线程结束的是时候,守护线程也就结束了。

/**
 * 强制关闭线程:可以将工作线程设置为守护线程,
 * 只要主线程结束了,那么守护线程也结束了,
 * 算是暴力停止线程的一种方式
 */
public class ForceInterruptThread {
    public static void main(String[] args) {
        //超时打断
        WorkThread workThread1 = new WorkThread();
        workThread1.execute(() -> {
            while (true){}
        });
        workThread1.shutdown(3000L);

        //正常结束
        WorkThread workThread2 = new WorkThread();
        workThread2.execute(() -> {
            try {
                Thread.sleep(2000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        workThread2.shutdown(3000L);
        System.out.println("主线程结束.....");
    }
}

class WorkThread {
    private Thread executeThread;
    //用来判断守护线程中的任务是否运行完成,如果运行结束了,那么可以将主线程打断
    private volatile boolean flag = false;

    public void execute(Runnable runnable) {
        executeThread = new Thread(() -> {
            Thread workerThread = new Thread(runnable);
            //工作线程设置为守护线程
            workerThread.setDaemon(true);
            //启动工作线程
            workerThread.start();
            /*
             * 主线程等待工作线程执行完成,使用join()方法,如果在
             * join的过程中,线程被打断,那么主线程(executeThread)将结束,
             * 当然守护线程也就结束了
             */
            try {
                workerThread.join();
                //守护线程工作完成
                flag = true;
                System.out.println("任务完成,正常退出......");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        executeThread.start();
    }

    /**
     * 超时停止线程,
     */
    public void shutdown(long mili) {
        //定义开始时间和结束时间
        long startTime = System.currentTimeMillis();
        long endTime = System.currentTimeMillis();
        while (!flag) {
            //如果超时,打断主线程
            if(endTime - startTime > mili) {
                System.out.println("任务超时打断......");
                executeThread.interrupt();
                break;
            }
            try {
                Thread.sleep(100L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            endTime = System.currentTimeMillis();
        }
    }
}
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值