zoukankan      html  css  js  c++  java
  • 多线程开发之终结任务(中断)

    中断

    一个线程在执行完毕之后会自动结束,如果在运行过程中发生异常也会提前结束

    一个线程可能处于以下四种状态之一:

    • 新建
    • 就绪
    • 阻塞
    • 死亡

    一个任务进入阻塞状态可能有以下原因:

    1. 调用sleep()使任务进入休眠状态,这种情况下,任务在指定的时间内不会运行
    2. 调用wait()使线程挂起。直到线程得到了notify()和notifyAll()消息,线程才会进入就绪状态
    3. 任务在等待某个输入输出完成
    4. 任务视图在某个对象上调用其同步控制方法,但是对象锁不可用,因为另一个任务已经获取了这个锁

    一些阻塞可以中断,但是一些阻塞不可中断。

    InterruptedException:

    通过调用一个线程的 interrupt() 来中断该线程,如果该线程处于阻塞、限期等待或者无限期等待状态,那么就会抛出 InterruptedException,从而提前结束该线程。但是不能中断 I/O 阻塞和 synchronized 锁阻塞。

    /**
     * interrupted
     * */
    
    public class InterruptedTest implements Runnable{
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                System.out.println("the end");
            } catch (InterruptedException e) {//由于主线程内调用了中断,这里抛异常,睡眠以下的语句不会执行
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread(new InterruptedTest());
            thread.start();
            thread.interrupt();//调用中断
            System.out.println("main end");
        }
    }

    interrupted:

    如果一个线程的 run() 方法执行一个无限循环,并且没有执行 sleep() 等会抛出 InterruptedException 的操作,那么调用线程的 interrupt() 方法就无法使线程提前结束。

    但是调用 interrupt() 方法会设置线程的中断标记,此时调用 interrupted() 方法会返回 true。因此可以在循环体中使用 interrupted() 方法来判断线程是否处于中断状态,从而提前结束线程。

    /**
     * interrupted
     * */
    public class interruptedTest2 implements Runnable{
    
        @Override
        public void run() {
            while (!Thread.interrupted()){
    
            }
            System.out.println("Thread end");
        }
    
        public static void main(String[] args) {
            Thread thread = new Thread(new interruptedTest2());
            thread.start();
            thread.interrupt();//如果将该句注释掉,该进程就会一直卡在死循环中出不来
            System.out.println("main end");
        }
    }

    Executor 的中断操作:

    调用 Executor 的 shutdown() 方法会等待线程都执行完毕之后再关闭,但是如果调用的是 shutdownNow() 方法,则相当于调用每个线程的 interrupt() 方法。

    /**
     * Executor Interrupted
     * */
    public class ExecuutorTest implements Runnable{
    
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
                System.out.println("ExecutorTest");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public static void main(String[] args) {
            ExecutorService exec = Executors.newCachedThreadPool();
            for (int i = 0; i < 5; i++) {
                exec.execute(new ExecuutorTest());
            }
            exec.shutdownNow();
            System.out.println("main end");
        }
    }

    如果只想中断 Executor 中的一个线程,可以通过使用 submit() 方法来提交一个线程,它会返回一个 Future<?> 对象,通过调用该对象的 cancel(true) 方法就可以中断线程。

    共同学习共同进步,如果错误,欢迎指正

  • 相关阅读:
    Padding和父子继承宽高之间的关系
    Js实例——模态框弹出层
    Java——异常谜题
    BZOJ 2743 【HEOI2012】 采花
    BZOJ 4614 【WF2016】 Oil
    BZOJ 1004 【HNOI2008】 Cards
    codevs 2495 水叮当的舞步
    BZOJ 1227 【SDOI2009】 虔诚的墓主人
    BZOJ 3505 【CQOI2014】 数三角形
    BZOJ 4423 【AMPPZ2013】 Bytehattan
  • 原文地址:https://www.cnblogs.com/czsy/p/10532044.html
Copyright © 2011-2022 走看看