Java线程的中断(Interruption)

/ 并发编程 / 1 条评论 / 507人围观

任务和线程的启动很容易。在大多数时候,我们都会让它们运行直到结束,或者让它们自行停止。然而,有时候我们希望提前结束任务或线程,或许是因为用户取消了操作,或者应用程序需要被快速闭要使任务和线程能安仝、快速、可靠地停止下来,并不是一件容易的事。Java的Thread类为我们提供了stop(),suspend()等停止挂起线程的方法,但是由于安全问题目前都已被弃用。Java并没有提供一种安全的抢占式方法来停止线程,但它提供了中断(Interruption),这是一种协作机制,采用协作式的方式使一个线程终止另一个线程的当前工作。 这种协作式的方法是必要的,我们很少希望某个任务、线程或服务立即停止,因为这种立即停止会使共享的数据结构处于不一致的状态。相反,在编写任务和服务时可以使用一种协作的方式:当需要停止时,它们首先会清除当前正在执行的工作,然后再结束。这提供了更好的灵活性,因为任务本身的代码比发出取消请求的代码更清楚如何执行清除工作。 生命周期结束(End-of-Lifecycle)的问题会使任务、服务以及程序的设计和实现等过程变得复杂,而这个在程序设计中非常重要的要素却经常被忽略。一个在行为良好的软件与勉强运行的软件之间的最主要区别就是,行为良好的软件能很完善地处理失败、关闭和取消等过程。


如何设计一种协作机制,让线程可以安全的中断呢?我们可以设置一个取消标志,在工作线程会被中断的地方去检查这个标志,当检查到这个中断标志被设置为已取消时,工作线程便开始做取消工作。

public class CancelableThread implements Runnable {
    //线程取消标志,volatile修饰,保证内存可见性
    private volatile boolean isCanceled = false;
    @Override
    public void run() {
        while (!isCanceled) {//在工作线程中轮询检测这个取消标志
            System.out.println("The current thread is doing something...");
            System.out.println(Thread.currentThread().getName() + " cancel flag is " + isCanceled);
        }
        //当取消标志被设置为true,执行以下代码,可以做一些取消工作
        System.out.println(Thread.currentThread().getName() + "The current thread Has been cancelled");
    }

    private void cancel() {
        isCanceled = true;
    }
}
public class Main {
    public static void main(String[] args) throws Exception {
        CancelableThread cancelableThread = new CancelableThread();
        new Thread(cancelableThread).start();
        try {
            Thread.sleep(1);
        } finally {
            //设置标志位为true,中断线程  
      cancelableThread.cancel();
        }
    }
}
Thread-0 cancel flag is false
The current thread is doing something...
Thread-0 cancel flag is false
The current thread is doing something...
Thread-0 cancel flag is false
The current thread is doing something...
Thread-0 cancel flag is false
The current thread is doing something...
Thread-0 cancel flag is true
Thread-0The current thread Has been cancelled 
public void interrupt() {
  //...  省略相关代码
  interrupt0();           // Just to set the interrupt flag       
  //...  省略相关代码
}
public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
    return isInterrupted(false);
}
public class InterruptTest {
    static class InnerThread extends Thread{
        @Override
        public void run() {
            while(!isInterrupted()){
                System.out.println(Thread.currentThread().getName()+" cancle flag is "+isInterrupted());
                try {
                    Thread.sleep(100);
                }catch (InterruptedException e){
                    e.printStackTrace();
                    //抛出InterruptedException,中断标志位被清除,再次调用 interrupt();
                    interrupt();
                }
            }
            System.out.println(Thread.currentThread().getName()+" cancle flag is "+isInterrupted());
        }
    }


    public static void main(String[] args) {
        InnerThread innerThread = new InnerThread();
        innerThread.start();
        try {
            Thread.sleep(1000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        innerThread.interrupt();
//        InnerThread innerThread2 = new InnerThread();
//        innerThread2.start();
//        innerThread2.interrupt();
    }
}
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
Thread-0 cancle flag is false
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at InterruptTest$InnerThread.run(InterruptTest.java:13)
Thread-0 cancle flag is true

注:文章出处-https://www.cnblogs.com/perkins/p/9052139.html

  1. 234234

    回复