美文网首页
Chapter 1.3 线程对象

Chapter 1.3 线程对象

作者: 原创迷恋者 | 来源:发表于2019-10-14 14:52 被阅读0次

中断

一个中断是指对线程的一个提醒,让它停止做当前的事,转而做一个其他的事情。由程序员决定线程如何应对一个中断,不过很多情况下,时要求线程终止。这节将会强调这个用法。

一个线程通过调用Thread对象的interrupt方法来发送中断。为了让中断机制正确工作,被中断的线程必须要支持它自己的中断。

支持中断

一个线程要如何支持自己的中断呢?这取决于它当前正在做什么。如果这个线程当前正在调用一个会抛出InterruptedException的方法,等它捕获到异常,它只是简单地从run方法中返回。举个例子,假设SleepMessages类中间的信息循环是在Runnable对象的run方法中,那么它需要这样改动,来支持中断。

for (int i = 0; i < importantInfo.length; i++) {
    // Pause for 4 seconds
    try {
        Thread.sleep(4000);
    } catch (InterruptedException e) {
        // We've been interrupted: no more messages.
        return;
    }
    // Print a message
    System.out.println(importantInfo[i]);
}

很多会抛出InterruptedException异常的方法,比如sleep,都被设计成,当收到中断时能立刻返回。

如果一个线程一直没有调用会抛出InterruptedException异常的方法该怎么办?那么它把必须每过一段时间调用一次Thread.interrupted,这个方法会在收到中断之后返回true。举例如下:

for (int i = 0; i < inputs.length; i++) {
    heavyCrunch(inputs[i]);
    if (Thread.interrupted()) {
        // We've been interrupted: no more crunching.
        return;
    }
}

在上面的简单案例中,代码只是简单地测试了中断,如果线程收到了中断,则退出。在更为复杂的应用中,可能抛出一个InterruptedException会更合理。

if (Thread.interrupted()) {
    throw new InterruptedException();
}

这使得中断处理的代码集中在一个catch子句中。

中断状态标记

中断的机制是由被称为中断状态的内部标记实现的。调用Thread.interrupt会设定这个标记。当一个线程调用Thread.interrputed静态方法时,这个标记位就被清零。非静态方法isInterrupted方法,可以被一个线程用来查询另一个线程的中断状态,不会改变中断标志位。

Joins

joins方法允许一个线程等待另一个线程完成。假设t是当前正在执行的线程,则使用t.join()方法会导致当前线程停止运行,直到t的线程结束。对join方法的重载允许程序员指定一个等待时间段。不过,就像sleep方法一样,join方法也依赖于OS的计时,所以你也不能确保join方法一定会等待你指定的时间。

和sleep方法一样,join方法应对中断的方法也是通过InterruptedException来退出。

一个线程的例子

接下来的例子会使用到本节中的所有概念。SimpleThreads类由两个线程构成。第一个线程是每个JAVA应用都有的Main线程。Main线程使用Runnable对象创建了一个新的线程,MessageLoop,然后会等待它的结束。如果MessageLoop线程花了太长时间,主线程会中断它。

MessageLoop线程打印一系列的信息。如果在打印完所有信息之前,它就被中断了,那MessageLoop会打印一条信息并退出。

public class SimpleThreads {

    // Display a message, preceded by
    // the name of the current thread
    static void threadMessage(String message) {
        String threadName =
            Thread.currentThread().getName();
        System.out.format("%s: %s%n",
                          threadName,
                          message);
    }

    private static class MessageLoop
        implements Runnable {
        public void run() {
            String importantInfo[] = {
                "Mares eat oats",
                "Does eat oats",
                "Little lambs eat ivy",
                "A kid will eat ivy too"
            };
            try {
                for (int i = 0;
                     i < importantInfo.length;
                     i++) {
                    // Pause for 4 seconds
                    Thread.sleep(4000);
                    // Print a message
                    threadMessage(importantInfo[i]);
                }
            } catch (InterruptedException e) {
                threadMessage("I wasn't done!");
            }
        }
    }

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

        // Delay, in milliseconds before
        // we interrupt MessageLoop
        // thread (default one hour).
        long patience = 1000 * 60 * 60;

        // If command line argument
        // present, gives patience
        // in seconds.
        if (args.length > 0) {
            try {
                patience = Long.parseLong(args[0]) * 1000;
            } catch (NumberFormatException e) {
                System.err.println("Argument must be an integer.");
                System.exit(1);
            }
        }

        threadMessage("Starting MessageLoop thread");
        long startTime = System.currentTimeMillis();
        Thread t = new Thread(new MessageLoop());
        t.start();

        threadMessage("Waiting for MessageLoop thread to finish");
        // loop until MessageLoop
        // thread exits
        while (t.isAlive()) {
            threadMessage("Still waiting...");
            // Wait maximum of 1 second
            // for MessageLoop thread
            // to finish.
            t.join(1000);
            if (((System.currentTimeMillis() - startTime) > patience)
                  && t.isAlive()) {
                threadMessage("Tired of waiting!");
                t.interrupt();
                // Shouldn't be long now
                // -- wait indefinitely
                t.join();
            }
        }
        threadMessage("Finally!");
    }
}

后感

  1. 上面的例子很有意思,它只是建立了一个新的线程,但是不涉及到任何线程同步的问题。我们常常因为面试题,混淆多线程和线程同步是两个概念,多线程未必需要线程同步,只有在代码会对状态发生改变的时候,我们才会考虑同步的问题。
  2. 很感谢网络和计算机,给我们这样开发分享知识的环境。

相关文章

网友评论

      本文标题:Chapter 1.3 线程对象

      本文链接:https://www.haomeiwen.com/subject/mhjrmctx.html