java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java线程取消

Java线程取消的三种方式

作者:louisgeek

文章介绍了 Java 线程取消的 3 种方式,不推荐使用 stop 方法和 volatile 设标记位停止线程,线程中断机制是协作式的,一个线程请求中断,另一线程响应,线程可检查自身中断状态或捕获 InterruptedException 来合适处理以响应中断,确保安全有序停止,避免资源泄露等问题

Java 线程取消的 3 种方式

强制停止线程

设置 volatile 标记位来停止线程

协作式中断线程

线程任务执行完后正常结束

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            //模拟线程执行任务
            for (int i = 0; i < 100000; i++) {
               System.out.println("线程运行中 i=" + i);
            }
            //在执行完所有任务后线程正常结束
            System.out.println("---- 线程结束 ----");
        }
    };
    thread.start();
}

加入请求线程中断的逻辑

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            //模拟线程执行任务
            for (int i = 0; i < 100000; i++) {
               System.out.println("线程运行中 i=" + i);
            }
            //虽然调用了 Thread#interrupt 方法请求线程中断但还是会执行完所有的任务
            System.out.println("---- 线程结束 ----");
        }
    };
    thread.start();
    //演示逻辑
    try {
        //等待一段时间后去中断 thread 线程
        Thread.sleep(10);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("请求线程中断");
    //对 thread 线程请求线程中断
    thread.interrupt();
}

说明仅仅只改变中断状态是达不到取消线程的效果,需要继续加入响应中断的逻辑

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            //模拟线程执行任务
            for (int i = 0; i < 100000; i++) {
                //目的就是让线程在适当的时候检查自身的中断状态,并完成响应中断请求的逻辑
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("线程检测到自身的中断状态为 true ,于是准备停止");
                    //释放资源并结束线程
                    break; //这里用 return 也行
                }
                System.out.println("线程运行中 i=" + i);
            }
            //
            System.out.println("---- 线程结束 ----");
        }
    };
    thread.start();
    //演示逻辑
    try {
        //等待一段时间后去中断 thread 线程
        Thread.sleep(10);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("请求线程中断");
    //对 thread 线程请求线程中断
    thread.interrupt();
}

存在阻塞状态(比如 Object#wait、Thread#sleep、Thread#join 或 Condition#await 等方法调用产生的)下的响应中断

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            //模拟线程执行任务
            for (int i = 0; i < 100000; i++) {
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    //当一个线程在阻塞状态时如果调用了该线程的 interrupt 方法的话,那么阻塞方法就会抛出 InterruptedException 异常,类似于线程检测到自身的中断状态为 true,也就意味着这里需要加入响应中断的逻辑了
                    //这里抛出 InterruptedException 异常的设计是为了线程可以从阻塞状态恢复(唤醒)过来(表示阻塞操作由于中断而提前结束),能在线程结束前有机会去处理中断请求
                    //另外抛出 InterruptedException 异常的同时会清除线程的中断标志位(中断状态被重置为 false)
                    //所以这里可以做一些停止线程任务继续执行的逻辑(比如直接退出循环)或者也可以在这里再次调用 Thread#interrupt 重设中断状态(标记回中断状态为 true)然后和适当位置的 Thread#isInterrupted() 判断配合来完成响应中断请求的逻辑
                    break;
                }
                System.out.println("线程运行中 i=" + i);
            }
            //
            System.out.println("---- 线程结束 ----");
        }
    };
    thread.start();
    //演示逻辑
    try {
        //等待一段时间后去中断 thread 线程
        Thread.sleep(10);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("请求线程中断");
    //对 thread 线程请求线程中断
    thread.interrupt();
}

线程在阻塞状态下也能正确响应中断请求

public static void main(String[] args) {
    Thread thread = new Thread() {
        @Override
        public void run() {
            //模拟线程执行任务
            for (int i = 0; i < 100000; i++) {
                //适当位置检查自身的中断状态,并完成响应中断请求的逻辑
                if (Thread.currentThread().isInterrupted()) {
                    System.out.println("线程检测到自身的中断状态为 true ,于是准备停止");
                    //释放资源并结束线程
                    break; //这里用 return 也行
                }
                try {
                    Thread.sleep(2);
                } catch (InterruptedException e) {
                    //抛出 InterruptedException 异常的同时会清除中断标志位(中断状态被重置为 false)
                    //所以这里要特别注意,可以按需重设中断标志位,就能做到即使线程在阻塞状态下也能够正确地响应中断请求了(不然很容易错过外部设置的那一次中断请求)
                    Thread.currentThread().interrupt();
                }
                System.out.println("线程运行中 i=" + i);
            }
            //
            System.out.println("---- 线程结束 ----");
        }
    };
    thread.start();
    //演示逻辑
    try {
        //等待一段时间后去中断 thread 线程
        Thread.sleep(10);
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("请求线程中断");
    //对 thread 线程请求线程中断
    thread.interrupt();
}

总结

以上就是Java线程取消的三种方式的详细内容,更多关于Java线程取消的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文