Java<优雅地理解线程interrupt、isInterrupted、interrupted>

1.什么是线程的中断

线程中断可以简单地理解为线程(Thread)有一个属性叫做“中断”,可以通过调用很多方法来查看该线程的这个属性的状态(TRUE、FALSE)

2.我调用这些方法的之后线程会立即中断么?

来看个例子:

public class MyThread extends Thread {
    @Override
    public void run() {
        super.run();
        for (int i = 0; i < 50000; i++) {
            System.out.println(i);
        }
    }
}
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(1000);
        //调用线程Mythread的实例的中断方法
        thread.interrupt();
   }
}

在main线程挂起1秒之后,然后main线程给Mythread的实例(这里简写为MTH)发送了一个消息,告诉他“你把你的中断属性设置为TRUE”,但是MTH收到了这个消息之后只是单存地把这个自己的属性设置为TRUE,”然后并不中断自己”。

控制台打印1-49999:

49993
49994
49995
49996
49997
49998
49999

Process finished with exit code 0

到这里答案已经很明显了,线程并不会因为简单地收到了其他线程的消息而中断自己

!!!如果要中断自己还要有附加操作

这些额外的操作是什么?

//Interrupted的经典使用代码    
    public void run(){    
            try{    
                 ....    
                 while(!Thread.currentThread().isInterrupted()&& more work to do){    
                        // do more work;    
                 }    
            }catch(InterruptedException e){    
                        // thread was interrupted during sleep or wait    
            }    
            finally{    
                       // cleanup, if required    
            }    
    }    

Thread.currentThread().isInterrupted()可以用来检测当前线程的中断属性
while循环有一个决定因素就是需要不停的检查自己的中断状态。当外部线程调用该线程的interrupt 时,使得中断状态置位即变为true。这是该线程将终止循环,不在执行循环中的do more work了。

3.interrupt()

这个方法是线程的一个内部方法,是由其他线程调用的,比如我在main方法中让main线程来调用MTH的interrupt()方法.
比如下面这个代码:

public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyThread thread = new MyThread();
        thread.start();
        Thread.sleep(1000);
        //调用线程Mythread的实例的中断方法
        thread.interrupt();
   }
}

这段代码会将MTH(如果你忘记了声明是MTH,网上翻)的中断属性为TRUE,仅此而已。

引申一下:

 public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().interrupt();
}

如果我在main方法里调用了上面这行代码,会怎么样?
答案是:main线程的中断位会被设置为TRUE

4.isInterrupted()

这个方法主要用来获取当前线程的“中断”属性的状态,是TRUE还是FALSE。仅此而已。

套用上面的代码:

  public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().interrupt();
        System.out.println("isInterrupted " +                Thread.currentThread().isInterrupted());
}

这里有一个点需要注意:在上面的代码中
Thread.currentThread()得到的是当前正在执行main方法的线程(也就是main线程)

控制台会输出什么?

TRUE

线程默认的中断位是FALSE,main线程调用了interrupt()之后,其中断位为TRUE,
isInterrupted()方法获取到的当然是TRUE

5.interrupted()

调用该线程的方法的中断位会被重置为FALSE

 Thread.currentThread().interrupt();
        System.out.println("isInterrupted " + Thread.currentThread().isInterrupted());
        new MyThread().interrupted();//因为是Main线程执行这个方法,这个方法内部会把正在执行他的线程的中断标志位设置为false
        System.out.println("isInterrupted " + Thread.currentThread().isInterrupted());

以上的代码的执行的结果是:

isInterrupted true
isInterrupted false

原因很简单,Thread.currentThread().isInterrupted()方法执行之后main线程的中断位会被置为TRUE;
之后new MyThread().interrupted()执行,那么这行代码是谁在执行?当然是main线程在执行,也就是说执行interrupted()方法的线程是main。之前说了谁执行了interrupted()方法谁的中断位就会被置为FALSE,那现在main的中断位自然就会被置为FALSE了。

上面的话可能有点绕口,如果你不理解这段话,请看下面这个小例子:

public class DemoThread {
    static class MThread extends Thread {
        public MThread() {
            System.out.println("执行Mthread的线程是  :" + Thread.currentThread().getName());
        }
    }
    public static void main(String[] args) {
        new MThread();
    }
}

这时候控制台的输出是:

执行Mthread的线程是  :main

因为是main线程创建了子线程,自然子线程的构造函数是被main线程调用的。
如果你还看不懂,请反复看,这很关键。

如果我要修改main线程的中断位,我只用通过new MyThread().interrupted()方法么?答案是否定的,下面的代码也可做到

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().interrupt();//false--->TRUE
        System.out.println("isInterrupted " + Thread.currentThread().isInterrupted());
        Thread.interrupted();//true-->false
        System.out.println("isInterrupted " + Thread.currentThread().isInterrupted());

    }
}

* interrupted()的返回值:*
interrupted()会将标志位被自己置为之前的状态作为返回值然后,在置位标志位,看下面的代码:

public class Run {
    public static void main(String[] args) throws InterruptedException {
        Thread.currentThread().interrupt();
        System.out.println(Thread.currentThread().interrupted());
        System.out.println(Thread.currentThread().isInterrupted());
    }
}

控制台的输出是:

true
false

因为Thread.currentThread().interrupt();将main线程置为了TRUE(FALSE->TRUE),然后System.out.println(Thread.currentThread().interrupted());将TRUE返回,然后在将中断位修改为FALSE,最后Thread.currentThread().isInterrupted()返回的就是FALSE了。

6.sleep() & interrupt()

如果线程MTH线程循环调用了sleep(10000),main线程想要让mth放弃Sleep状态,然后抛出异常

public class FindDiffInArray {
    static class BusyThread extends Thread {
        @Override
        public void run() {
            System.out.println("我是无相关线程");
        }
    }

    static class MTH extends Thread {
        @Override
        public void run() {
            try {
                System.out.println("RUN begin");
                Thread.sleep(2000000);
                System.out.println("RUN end");
            } catch (InterruptedException e) {
                System.out.println("在沉睡中被停止 " + this.isInterrupted());
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MTH mth = new MTH();
        mth.start();
        Thread.sleep(200);
        mth.interrupt();
        System.out.println(mth.isInterrupted());
    }
}

控制台的输出:

RUN begin
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at FindDiffInArray$MTH.run(FindDiffInArray.java:28)
在沉睡中被停止 false
false

可以看到mth.interrupt();被执行之前mth一直在循环执行sleep()函数,接着是接收到中断信号,但是由于此时mth没有占用CPU时间片,没有占用CPU运行的线程是不可能给自己的中断状态置位的。这就会产生一个InterruptedException异常。
但是抛出异常之后,mth的中断位并没有被置为TRUE(从控制台的打印信息来看)

7.join() & interrupt().

当线程以join()等待其他线程结束时,当它被调用interrupt(),它与sleep()时一样, 会马上跳到catch块里.
注意,是对谁调用interrupt()方法,一定是调用被阻塞线程的interrupt方法.如在线程a中调用来线程t.join().则a会等t执行完后在执行t.join后的代码,当在线程b中调用来 a.interrupt()方法,则会抛出InterruptedException,当然join()也就被取消了。

8. wait() & interrupt()

线程A调用了wait()进入了等待状态,也可以用interrupt()取消.
不过这时候要小心锁定的问题.线程在进入等待区,会把锁定解除,当对等待中的线程调用interrupt()时,会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值