【问题标题】:java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate invokes thread every 4-5 seconds when configured for 12 hoursjava.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate 在配置 12 小时后每 4-5 秒调用一次线程
【发布时间】:2022-02-04 12:40:05
【问题描述】:

我有一个单例类,它在创建实例时创建一个线程。仅创建此类的一个对象,并且线程计划每 12 小时运行一次并打印给定的语句。在某些情况下,在前 12 小时之后,每 4-5 秒调用一次线程。我对为什么会发生这种情况感到困惑,因为我已将调度程序配置为每 12 小时运行一次,而不是每 4-5 秒运行一次。是否有我遗漏的配置或调度程序配置错误?

单例类,

import java.time.Instant;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class ThreadSchedulerTest {
private static final ThreadSchedulerTest test = new ThreadSchedulerTest();
private ThreadSchedulerTest (){createThread();}

private void createThread() {

        Runnable renewer = () -> {
            System.out.println("Running ok , time is : "+ Instant.now());
        };
        Executors.newSingleThreadScheduledExecutor(new 
 ThreadSchedulerThreadFactory("thread1")).scheduleAtFixedRate(
                renewer, 0, 12, TimeUnit.HOURS);

}
static class ThreadSchedulerThreadFactory implements ThreadFactory {
    private final String name;

    public ThreadSchedulerThreadFactory(final String name) {
        this.name = name;
    }

    @Override
    public Thread newThread(Runnable r) {
        Thread thread = new Thread(r, name);
        thread.setDaemon(true);
        return thread;
    }
}
}

有人可以帮忙澄清这个问题吗?

【问题讨论】:

    标签: java multithreading


    【解决方案1】:

    如果将 TimeUnit 更改为 SECONDS 并制作实例的 Runnable 打印哈希码,您会发现更容易测试:

    Runnable renewer = () -> {
        System.out.println("Running ok instance="+ThreadSchedulerTest.this.hashCode()+", time is : "+ Instant.now());
    };
    

    您每 4-5 秒重复一次的问题可能是您创建了两个 ThreadSchedulerTest 实例。上述消息修复将确认。

    您提供的代码将不会运行,因为您对构造函数和成员变量进行了递归定义。因此ThreadSchedulerTest 的每个实例都会执行第二个构造函数ThreadSchedulerTest test = new ThreadSchedulerTest(); - 然后实例化一个新成员test

    new ThreadSchedulerTest()
    |  Exception java.lang.StackOverflowError
    |        at ThreadSchedulerTest.<init> (#5:2)
    

    你可以修复我的这个声明 - test 是静态的,构造函数是私有的,所以只构造了一个实例:

    public class ThreadSchedulerTest {
       static final ThreadSchedulerTest test = new ThreadSchedulerTest();
       private ThreadSchedulerTest () {
            createThread(); 
       }
       ...
    

    【讨论】:

    • 嗨,谢谢你的回答。似乎我在编辑问题时错过了一些关键字。我确实有一个私有构造函数,并且测试对象也是静态和最终的。问题仍然存在。就像我在问题中提到的那样,这只出现了几次,而在其他时候它运行得很好。我无法找到调度程序在什么确切情况下开始频繁调度而不是在给定时间段。
    • 如果自包含程序也添加main。如果没有,并且您正在使用应用服务器或 Web 容器,请在部署之间重新启动它,因为您会看到该类的新旧实例正在运行。
    • 我几乎每周都会重新启动应用程序,在部署期间,有时会出现此问题,有时不会出现。关于如何确定我有该类的旧实例正在运行的任何想法?我也尝试过记录线程 ID,它与经常执行的线程相同。
    • 您已经证明有 2 个实例正在运行。如果您在应用服务器或 Web 容器中使用热部署,则需要使用容器服务提供的任何机制(例如 Servlet 容器的 ServletContentListener)来处理与先前部署相关的执行程序服务的正常关闭/清理。
    猜你喜欢
    • 2019-02-26
    • 2019-04-21
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-05
    • 2020-01-08
    • 2023-03-29
    相关资源
    最近更新 更多