如何正确地停止Java中的线程?

我需要一个解决方案来正确地停止Java中的线程。

我有实现Runnable接口的IndexProcessor类:

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);

    @Override
    public void run() {
        boolean run = true;
        while (run) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                run = false;
            }
        }

    }
}

我有ServletContextListener类,它启动和停止线程:

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        thread = new Thread(new IndexProcessor());
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            thread.interrupt();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}

但是当我关闭tomcat时,我在我的IndexProcessor类中遇到异常:

2012-06-09 17:04:50,671 [Thread-3] ERROR  IndexProcessor Exception
java.lang.InterruptedException: sleep interrupted
    at java.lang.Thread.sleep(Native Method)
    at lt.ccl.searchengine.processor.IndexProcessor.run(IndexProcessor.java:22)
    at java.lang.Thread.run(Unknown Source)

我正在使用JDK 1.6。 所以问题是:

我怎样才能阻止线程并且不抛出任何异常?

PS我不想使用.stop(); 方法,因为它已被弃用。


IndexProcessor类中,您需要设置一个标志来通知线程它将需要终止,类似于您在类范围中使用的变量run

当你想停止线程时,你设置这个标志并在线程上调用join()并等待它完成。

通过使用volatile变量或者使用与被用作标志的变量同步的getter和setter方法,确保该标志是线程安全的。

public class IndexProcessor implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexProcessor.class);
    private volatile boolean running = true;

    public void terminate() {
        running = false;
    }

    @Override
    public void run() {
        while (running) {
            try {
                LOGGER.debug("Sleeping...");
                Thread.sleep((long) 15000);

                LOGGER.debug("Processing");
            } catch (InterruptedException e) {
                LOGGER.error("Exception", e);
                running = false;
            }
        }

    }
}

然后在SearchEngineContextListener

public class SearchEngineContextListener implements ServletContextListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SearchEngineContextListener.class);

    private Thread thread = null;
    private IndexProcessor runnable = null;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        runnable = new IndexProcessor();
        thread = new Thread(runnable);
        LOGGER.debug("Starting thread: " + thread);
        thread.start();
        LOGGER.debug("Background process successfully started.");
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        LOGGER.debug("Stopping thread: " + thread);
        if (thread != null) {
            runnable.terminate();
            thread.join();
            LOGGER.debug("Thread successfully stopped.");
        }
    }
}

使用Thread.interrupt()是完全可以接受的方式。 事实上,如上所述,这可能是最好的一面旗帜。 原因是,如果你处于一个可中断的阻塞呼叫(如Thread.sleep或使用java.nio频道操作),你实际上可以立即跳出这些呼叫。

如果您使用标志,则必须等待阻止操作完成,然后才能检查标志。 在某些情况下,您必须执行此操作,例如使用不可中断的标准InputStream / OutputStream

在这种情况下,当线程中断时,它不会中断IO,但是,您可以在代码中轻松地执行此操作(并且您应该在可以安全停止和清理的关键点执行此操作)

if (Thread.currentThread().isInterrupted()) {
  // cleanup and stop execution
  // for example a break in a loop
}

就像我说的, Thread.interrupt()的主要优点是你可以立即摆脱可中断的调用,这是你不能用标志方法做的。


简单的答案:您可以通过以下两种常用方式之一停止INTERNALLY线程:

  • run方法返回一个返回子例程。
  • 运行方法结束,并隐式返回。
  • 你也可以停止EXTERNALLY线程:

  • 调用system.exit (这会杀死整个进程)
  • 调用线程对象的interrupt()方法*
  • 看看线程是否有一个实现的方法,听起来像它会工作(如kill()stop()
  • *:期望的是,这应该阻止一个线程。 但是,线程在发生这种情况时的实际作用完全取决于开发人员在创建线程实现时编写的内容。

    您在运行方法实现中看到的常见模式是while(boolean){} ,其中布尔值通常是名为isRunning东西,它是其线程类的成员变量,它是易失性的,并且通常可由其他线程通过setter方法sorts,例如kill() { isRunnable=false; } kill() { isRunnable=false; } 。 这些子程序很好,因为它们允许线程在终止之前释放它保存的任何资源。

    链接地址: http://www.djcxy.com/p/92117.html

    上一篇: How to properly stop the Thread in Java?

    下一篇: How is default new thread name given in java?