interrupt()、interrupted()、isInterrupted()的区别

interrupt() 方法在Java中是设置一个线程的中断状态,那它可以中断一个线程吗?我们看下面的代码:

/**
 * 消息生产者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:31
 * @since 1.0.0
 */
public class MessageServer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 10; i++) {
            System.out.println(String.format("i:%s", i));
        }
    }
}
/**
 * 消息消费者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:41
 * @since 1.0.0
 */
public class MessageClient {
    public static void main(String[] args) throws InterruptedException {
        MessageServer messageServer = new MessageServer();
        Thread thread = new Thread(messageServer);
        thread.start();
        thread.interrupt();
        System.out.println("停止当前线程");
    }
}
停止当前线程
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
i:10

看输出信息interrupt()方法并没有中断一个线程。那么设置一个线程的中断状态到底是什么意思呢?原来线程开启时如果设置了interrupt()方法,那JVM就会把当前线程中断状态设置为true。此时我们可以用interrupted()和isInterrupted()来检测当前线程的中断状态来做一些业务处理如暂停线程或停止一个线程。那这两个方法都有什么区别呢,分别看下面的代码。

interrupted()

/**
 * 消息生产者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:31
 * @since 1.0.0
 */
public class MessageServer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            if (i % 5 == 0) {
                if (Thread.interrupted()) {
                    for (int z = 5; z > 0; z--) {
                        System.out.println(String.format("倒计时:%s", z));
                    }
                }
            }
            System.out.println(String.format("i:%s", i));
        }
    }
}
/**
 * 消息消费者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:41
 * @since 1.0.0
 */
public class MessageClient {
    public static void main(String[] args) throws InterruptedException {
        MessageServer messageServer = new MessageServer();
        Thread thread = new Thread(messageServer);
        thread.start();
        thread.interrupt();
    }
}
i:1
i:2
i:3
i:4
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
i:5
i:6
i:7
i:8
i:9
i:10
i:11
i:12
i:13
i:14
i:15
i:16
i:17
i:18
i:19
i:20

isInterrupted()

/**
 * 消息生产者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:31
 * @since 1.0.0
 */
public class MessageServer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            if (i % 5 == 0) {
                if (Thread.currentThread().isInterrupted()) {
                    for (int z = 5; z > 0; z--) {
                        System.out.println(String.format("倒计时:%s", z));
                    }
                }
            }
            System.out.println(String.format("i:%s", i));
        }
    }
}
/**
 * 消息消费者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:41
 * @since 1.0.0
 */
public class MessageClient {
    public static void main(String[] args) throws InterruptedException {
        MessageServer messageServer = new MessageServer();
        Thread thread = new Thread(messageServer);
        thread.start();
        thread.interrupt();
    }
}
i:1
i:2
i:3
i:4
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
i:5
i:6
i:7
i:8
i:9
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
i:10
i:11
i:12
i:13
i:14
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
i:15
i:16
i:17
i:18
i:19
倒计时:5
倒计时:4
倒计时:3
倒计时:2
倒计时:1
i:20

我们将客户端的

thread.interrupt();

方法注释在执行上述代码看一下效果。

interrupted()

/**
 * 消息消费者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:41
 * @since 1.0.0
 */
public class MessageClient {
    public static void main(String[] args) throws InterruptedException {
        MessageServer messageServer = new MessageServer();
        Thread thread = new Thread(messageServer);
        thread.start();
//        thread.interrupt();
    }
}
/**
 * 消息生产者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:31
 * @since 1.0.0
 */
public class MessageServer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            if (i % 5 == 0) {
                if (Thread.interrupted()) {
                    for (int z = 5; z > 0; z--) {
                        System.out.println(String.format("倒计时:%s", z));
                    }
                }
            }
            System.out.println(String.format("i:%s", i));
        }
    }
}
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
i:10
i:11
i:12
i:13
i:14
i:15
i:16
i:17
i:18
i:19
i:20

isInterrupted()

/**
 * 消息消费者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:41
 * @since 1.0.0
 */
public class MessageClient {
    public static void main(String[] args) throws InterruptedException {
        MessageServer messageServer = new MessageServer();
        Thread thread = new Thread(messageServer);
        thread.start();
//        thread.interrupt();
    }
}
/**
 * 消息生产者
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-13 16:31
 * @since 1.0.0
 */
public class MessageServer implements Runnable {

    @Override
    public void run() {
        for (int i = 1; i <= 20; i++) {
            if (i % 5 == 0) {
                if (Thread.currentThread().isInterrupted()) {
                    for (int z = 5; z > 0; z--) {
                        System.out.println(String.format("倒计时:%s", z));
                    }
                }
            }
            System.out.println(String.format("i:%s", i));
        }
    }
}
i:1
i:2
i:3
i:4
i:5
i:6
i:7
i:8
i:9
i:10
i:11
i:12
i:13
i:14
i:15
i:16
i:17
i:18
i:19
i:20

我们发现虽然我们服务端的代码逻辑都是一样的,但我们调用interrupted()和isInterrupted()方法时输出信息有很大的不同的。这是什么原因呢。别着急我们先分析一下interrupted()的执行过程。按照我们代码里写的需求。我们指定循环执行20次并添加了一个IF条件

if (i % 5 == 0)

我们知道正常情况下这个IF语句的代码会执行4次,但我们从输出结果上看,它只执行了1次。为什么呢。因为我们还有一个IF判断。

if (Thread.interrupted())

我们分析后知道一定是这个条件发生了变化才导致了这样的效果。也就是说一定是它执行完后,变成了false才会出现这样的效果。那为什么会这样呢。这是因为我们知道当我们调用interrupt()方法时是设置当前线程的中断状态,并没有中断该线程。interrupted()方法也确实能检测到线程是否中断,因为IF语句执行了,但它还有一个逻辑处理就是会清除当前线程的中断状态。也就是说它会把当前线程回滚到没有被中断的状态,而isInterrupted()方法就不会清除中断状态它只是会检查当然前线程是否被中断,它并不会更改线程的中断状态。这也就是为什么调用这两个方法所产生不同输出的根本原因。为了验证我们刚刚所说的,我们看一下JDK里的源码。

public static boolean interrupted() {
    return currentThread().isInterrupted(true);
}
public boolean isInterrupted() {
    return isInterrupted(false);
}
/**
 * Tests if some Thread has been interrupted.  The interrupted state
 * is reset or not based on the value of ClearInterrupted that is
 * passed.
 */
private native boolean isInterrupted(boolean ClearInterrupted);

我们通过源码得知,原来interrupted()方法底层是调用isInterrupted()方法的,唯一的不同就是它们传递的参数是不同的interrupted()方法传递参数为true。isInterrupted()方法传递的参数为false。并且这两个方法都调用了另一个方法也就是isInterrupted()方法因为这个是用native修饰的也就是说这个方法是本地方法,所以我们看不到源码。但我们可以在方法注释上来获取这个方法的说明。翻译过来的意思就是测试一个线程是否已中断,中断的状态是或者不是是根据ClearInterrupted值恢复的。虽然并没有说明true是恢复还是false是恢复,但通过我们的测试,我们知道当这个值为true是会恢复这个线程的状态的。当然这里面也有一个前提就是我们要先执行interrupt()方法,否则interrupted()和isInterrupted()方法返回的都是false。就想我们最后测试结果显示的那样。这也就是interrupt()、interrupted()、isInterrupted()它们3个方法的主要区别。

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧