【问题标题】:Java - Stop thread while consumer is waiting and tomcat is shutdownJava - 在消费者等待并且tomcat关闭时停止线程
【发布时间】:2015-12-09 01:12:27
【问题描述】:

我有一个 servlet,它是一个单例。

在初始化中,我创建了生产者和消费者。

consumer = new MyThread();
consumer.start();

方法运行是这样的:

@Override
public void run() {
    while (!isShutdown()) {
        if (queue.isEmpty())
            queue.wait();
        else
            ...
    }
}

然后我有销毁方法。 将shutdown设置为true,我使用.join

        consumer.setShutdown(true); 
        consumer.join();

但是 .join 方法得到了锁定.. 并且永远不会完成。 如果我将 queue.wait 更改为 Thread.sleep(),它可以工作...但我不想更改...我做错了什么?

如果我没有完成线程,我明白了: 严重:Web 应用程序 [/test] 似乎已经启动了一个名为 [Comsumer0] 的线程,但未能停止它。这很可能会造成内存泄漏。

【问题讨论】:

    标签: java multithreading tomcat thread-safety


    【解决方案1】:

    使用等待/通知方法是创建消费者-生产者模式的旧方法。

    最好使用 BlockingQueue。

    BlockingQueue.put() - 生产者,BlockingQueue.poll() - 消费者。

    BlockingQueue 在BlockingQueue.pollBlockingQueue.put 下隐藏等待方法,并且会阻塞消费者线程,直到生产者向队列添加值。

    要修复上面的例子,你应该让它等待一段有限的时间,比如queue.wait(1000),或者唤醒消费者线程显式调用queue.notify()

    【讨论】:

      【解决方案2】:

      队列很可能是空的,并且由于您已关闭,因此您永远不会向队列中发送任何内容以使其唤醒。

      通过在设置关闭标志后向队列发送虚拟消息或完全删除关闭标志并向队列发送关闭命令来解决此问题。

      另外请注意,如果您的关闭标志不是 volatile(或 AtomicBoolean),那么由于 CPU 内部的缓存,一个线程可能看不到它被另一个线程设置。

      【讨论】:

        【解决方案3】:

        这就是BlockingQueue 的用途:

            BlockingQueue queue = new ArrayBlockingQueue(5);
            // ...
            while (!isShutdown()) {
                Object poll = queue.poll(5, TimeUnit.SECONDS);
            }
        

        【讨论】:

        • 这会解决问题,但是 BlockingQueue 提供了 take() 方法具有效率优势,使用 poll() 使 OP 使用另一个实现,Ryt?
        • @Nilesh - take 将等到有东西放入队列或出现interrupt。如果队列变空并且没有其他项目被推送到它上面,则必须破坏性地中止take。使用poll 允许我们在等待时也检查其他状态。
        【解决方案4】:

        您应该按照上面的建议更改设计,或者如果您不想更改代码,请更改您的 setShutdown() 方法主体和语句以通知队列。

        public void setShutdown(boolean shutdown) {
          this.shutdown = shutdown;
          this.queue.notifyAll();
        }
        

        【讨论】:

        • 在关机过程中尝试 notifyAll 时出现以下错误:2015 年 12 月 9 日上午 10:33:10 org.apache.catalina.core.ApplicationContext 日志严重:Servlet HttpEmailArrivedNotifyPL throw unload( ) 异常 javax.servlet.ServletException: Servlet.destroy() for Servlet HttpEmailArrivedNotifyPL 抛出异常
        • 对不起,通知和等待应该被包装到同步块中。
        猜你喜欢
        • 2021-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多