多线程开发之终结任务(中断)

中断

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

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

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

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

  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) 方法就可以中断线程。

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

猜你喜欢

转载自www.cnblogs.com/czsy/p/10532044.html