【问题标题】:Java thread start() without join() or interrupt() in servletservlet 中没有 join() 或 interrupt() 的 Java 线程 start()
【发布时间】:2009-09-01 13:32:38
【问题描述】:

我有一个 servlet 过滤器,它携带一些逻辑并在其主页处理请求之前产生输出。我有一个新的需求,需要比生成输出的那一刻晚几秒钟(延迟约 10 秒)。由于之前做出的某些糟糕的设计选择,我无法移动过滤器的位置,只是为了让输出在之后发送。

我已选择生成一个线程并在其中延迟消息的传输。我目前没有采取任何明确的步骤来停止该线程的执行。我不确定是否一切都得到了妥善清理。在此之后我应该使用 join() 或 interrupt() 或任何其他 Thread 方法来安全地清理吗?

所以在主 servlet 代码中我有这样的东西......

Thread t = new Thread(new MessageSender(message, 10000));
t.start();
//Carry on.. la la la

虽然这个类中还有其他字段,但我只是去掉了很多非必要的东西,比如建立数据库连接等,以明确这一点。

private static class MessageSender implements Runnable {
    String message;
    int delay;

    public MessageSender(String message, int delay) {
        this.message = message;
        this.delay = delay;
    }

    public void run() {
        try {
            Thread.sleep(delay);
            System.out.println(new java.util.Date() + ": hello world");                
        } catch (InterruptedException e) {
            // Do blah
        } catch (Exception e) {
            // Do blah blah
        } finally {
            // Close connections and stuff
        }
    }
}

【问题讨论】:

    标签: java multithreading servlets


    【解决方案1】:

    您的代码应该没问题,一旦完成,VM 会清理线程。

    但是,我建议不要使用这样的原始线程,而是使用java.util.concurrent.ScheduledExecutorService,使用java.util.concurrent.Executors 创建。这是一个更好的抽象,可以更好地控制您的线程分配。

    【讨论】:

      【解决方案2】:

      是的,一切都会得到妥善清理。线程在完成 run() 方法后死亡,因为您不再引用该线程对象 - 它将被正确地垃圾收集。

      只要确保“Thread t”对象不会被任何东西引用。为确保这一点,您可以使用: (新线程(...)).start();

      【讨论】:

        【解决方案3】:

        servlet 规范明确声明(“线程安全”部分)请求和响应对象不能保证是线程安全的,并且如果这些对象被移交给其他线程,那么应用程序负责确保这些对象是同步的,并且只能在 servlet 的服务方法范围内访问它们。换句话说,你必须 .join() 那些线程。

        【讨论】:

          【解决方案4】:

          我不得不自己回答同样的问题:)

          我可以承认线程在完成后确实被清理了。如果您不能完全确定生成的线程是否会死掉,您应该能够监视该进程并查看它当前正在运行的线程数。如果这个数字继续增长,那就是失控了。

          在 Unix 系统上,您可以使用 ps 命令,但我生疏了,所以我问 google 而不是阅读手册页。 谷歌上的第一个点击是This script that lists threads for each process。输出如下所示

          PID TID CLS RTPRIO  STAT    COMMAND WCHAN
          ....
          16035   16047   TS  -   S   (java)  
          16035   16050   TS  -   S   (java)  
          16035   16054   TS  -   S   (java)  
          16035   16057   TS  -   S   (java)  
          16035   16058   TS  -   S   (java)  
          16035   16059   TS  -   S   (java)  
          16035   16060   TS  -   S   (java)  
          ....
          

          我只是grep 输出我想观察的进程的进程ID (pid) 并计算行数,每行对应一个线程。像这样:

          morten@squeeze: ~$ sh /tmp/list_threads.sh | grep 16035 | wc -l
          20
          

          所以我目前正在观看的程序(PID 16035)有 20 个线程正在运行。

          这不需要知道jconsole 或对代码进行任何更改。最后一部分可能是最重要的部分,因为我还没有自己编写程序,所以现在我不必阅读和理解程序。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-14
            • 2016-10-27
            • 2018-05-08
            • 1970-01-01
            相关资源
            最近更新 更多