Java,
Java,
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()时,会先重新获取锁定,再抛出异常.在获取锁定之前,是无法抛出异常的.
相关文章
- 暂无相关文章
用户点评