重学Java之线程的中断

开启线程都知道了,怎么中断一个线程呢?

这里的中断也叫终止、停止,意思都是停止一个正在运行的线程。

1.设置中断标志位

在线程的执行逻辑中添加标志位判断,

需要中断线程时,修改该标志位,让线程执行逻辑结束。

public class StopThreadTest {

    public static void main(String[] args) throws InterruptedException {

        FThread fThread = new FThread();
        fThread.start();
        Thread.sleep(3000);
        fThread.setFlag(true);
    }
}
class FThread extends Thread{

    private boolean flag_stop = false;

    @Override
    public void run() {
        super.run();
        for (int t = 0; t < 10000; t++){
            if (flag_stop) {
                break;
            }
            System.out.println("FThread[" + Thread.currentThread().getName() + "] working , t = " + t);
            
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // real function
            
        }
        System.out.println("FThread[" + Thread.currentThread().getName() + "] finish");
    }

    public void setFlag(boolean flag){ this.flag_stop = flag; }
}

2.使用 interrupt 方法

在线程的执行逻辑中添加对中断的判断,判断方法是 isInterrupted()

需要中断某个线程时,调用 interrupt 方法。

interrupt 方法的 API 说明:

Interrupts this thread.
Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an InterruptibleChannel then the channel will be closed, the thread’s interrupt status will be set, and the thread will receive a java.nio.channels.ClosedByInterruptException.
If this thread is blocked in a java.nio.channels.Selector then the thread’s interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector’s wakeup method were invoked.
If none of the previous conditions hold then this thread’s interrupt status will be set.
Interrupting a thread that is not alive need not have any effect.
Throws:
SecurityException – if the current thread cannot modify this thread

概括:

  • 用于中断此线程。
  • 如果线程不是自己中断的,就会调用 checkAccess 方法,这可能导致 SecurityException 异常。
  • 如果线程阻塞(处于 wait(), wait(long), or wait(long, int) ,join(), join(long), join(long, int), sleep(long), or sleep(long, int) 状态),它的中断状态将被清除,并且它会出现一个 InterruptedException 异常
  • 如果此线程在 InterruptibleChannel 上的 I/O 操作中被阻塞,则通道将关闭,线程的中断状态将被设置,线程将 收到java.nio.channels.ClosedByInterruptException 异常。
  • 如果该线程在 java.nio.channels.Selector 中被阻塞,则该线程的中断状态将被设置,并且它将立即从选择操作中返回,可能具有非零值,就像调用了选择器的唤醒方法一样。
  • 如果前面的条件都不成立,则将设置此线程的中断状态。

2.1 直接调用

直接用试试,

public class StopThreadTest {

    public static void main(String[] args) throws InterruptedException {

        CalculateThread thread1 = new CalculateThread("thread1");
        thread1.start();
        thread1.interrupt();
    }
}

class CalculateThread extends Thread{

    private String name;

    public CalculateThread(String name) {
        super(name);
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10000 ; i++){
            if (this.isInterrupted()) {
                System.out.println("Thread[" + name + "] isInterrupted, exit");
                break;
            }

            System.out.println("Thread[" + name + "] is running, i = " + i);
        }

        System.out.println("Thread[" + name + "] finish");
    }
}

运行结果,

Thread[thread1] isInterrupted, exit
Thread[thread1] finish

一开始就中断,太快了,没看清,加个延时试试。

2.2 带 sleep() 的调用

假设线程中有用 sleep() 方法,看看有什么不一样

public class StopThreadTest {

    public static void main(String[] args) throws InterruptedException {

        CalculateThread thread1 = new CalculateThread("thread1");
        thread1.start();
        Thread.sleep(2000);
        thread1.interrupt();
    }
}


class CalculateThread extends Thread{

    private String name;

    public CalculateThread(String name) {
        super(name);
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10000 ; i++){
            if (this.isInterrupted()) {
                System.out.println("Thread[" + name + "] isInterrupted, exit");
                break;
            }

            System.out.println("Thread[" + name + "] is running, i = " + i);

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException");
                e.printStackTrace();
            }
        }

        System.out.println("Thread[" + name + "] finish");
    }
}

运行结果,

Thread[thread1] is running, i = 0
InterruptedException
Thread[thread1] is running, i = 1
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.lah.thread.CalculateThread.run(StopThreadTest.java:68)
Thread[thread1] is running, i = 2
Thread[thread1] is running, i = 3
Thread[thread1] is running, i = 4
Thread[thread1] is running, i = 5
Thread[thread1] is running, i = 6
//后面的继续执行,没成功,省略了

在 sleep() 时被中断,发生了 InterruptedException 异常,和 API 中说明的一样。

解决办法:做好异常处理逻辑

本例,直接在异常时 break 退出即可,

class CalculateThread extends Thread{

    private String name;

    public CalculateThread(String name) {
        super(name);
        this.name = name;
    }

    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 10000 ; i++){
            if (this.isInterrupted()) {
                System.out.println("Thread[" + name + "] isInterrupted, exit");
                break;
            }

            System.out.println("Thread[" + name + "] is running, i = " + i);

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                System.out.println("InterruptedException");
                e.printStackTrace();
                break; // 这里
            }
        }

        System.out.println("Thread[" + name + "] finish");
    }
}

再次运行就可以中断线程了,

Thread[thread1] is running, i = 0
Thread[thread1] is running, i = 1
InterruptedException
Thread[thread1] finish
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.lah.thread.CalculateThread.run(StopThreadTest.java:68)

3.使用 stop 方法(不推荐)

线程的 stop() 方法是弃用的 API ,不推荐使用。

你可能感兴趣的:(Java,多线程,java,interrupt)