Spring应用程序的定时器线程不断增加

Posted

技术标签:

【中文标题】Spring应用程序的定时器线程不断增加【英文标题】:Spring application's timer threads keep increasing 【发布时间】:2021-10-03 04:27:38 【问题描述】:

我有一些使用 Spring Batch 的 Java 应用程序。我有一个用作队列的表,其中包含有关客户端请求的作业的信息(当客户端请求要执行的任务时,会在此队列中添加一行)。

在我的一个课程中,会运行一个 while 循环,直到有人停用某些标志:

    protected void runJobLaunchingLoop() 
        while (!isTerminated()) 
            try 
                if (isActivated()) 
                    QueueEntryDTO queueEntry = dequeueJobEntry();
                    launchJob(queueEntry);
                
            
            catch (EmptyQueueException ignored) 
            catch (Exception exception) 
                logger.error("There was a problem while de-queuing a job ('" + exception.getMessage() + "').");
            
            finally 
                pauseProcessor();
            
        
    

pauseProcessor() 方法调用 Thread.sleep()。当我在 Docker 容器中运行这个应用程序时,看起来应用程序运行的线程数量不断增加。线程的名称为“Timer-X”,其中 X 为自动递增的某个整数。

我查看了其中一个的堆栈跟踪:

    "Timer-14" - Thread t@128
   java.lang.Thread.State: WAITING
    at java.base@11.0.6/java.lang.Object.wait(Native Method)
    - waiting on <25e60c31> (a java.util.TaskQueue)
    at java.base@11.0.6/java.lang.Object.wait(Unknown Source)
    at java.base@11.0.6/java.util.TimerThread.mainLoop(Unknown Source)
    - locked <25e60c31> (a java.util.TaskQueue)
    at java.base@11.0.6/java.util.TimerThread.run(Unknown Source)

   Locked ownable synchronizers:
    - None

知道这可能是什么原因吗?我不确定,但如果我不在容器中运行应用程序,而是从 IntelliJ 本地运行,似乎问题不会发生。我不确定,因为有时线程数开始增加需要一段时间。


编辑:一些相关代码...

protected QueueEntryDTO dequeueJobEntry() 
        Collection<QueueEntryDTO> collection = getQueueService().dequeueEntry();
        if (collection.isEmpty())
            throw new EmptyQueueException();
        return collection.iterator().next();
    

@Transactional
    public Collection<QueueEntryDTO> dequeueEntry() 
        Optional<QueueEntry> optionalEntry = this.queueEntryDAO.findTopByStatusCode(QueueStatusEnum.WAITING.getStatusCode());
        if (optionalEntry.isPresent()) 
            QueueEntry entry = (QueueEntry)optionalEntry.get();
            QueueEntry updatedEntry = this.saveEntryStatus(entry, QueueStatusEnum.PROCESSING, (String)null);
            return Collections.singleton(this.queueEntryDTOMapper.toDTO(updatedEntry));
         else 
            return new ArrayList();
        
    

private void pauseProcessor() 
        try 
            Long sleepDuration = generalProperties.getQueueProcessingSleepDuration();
            sleepDuration = Objects.requireNonNullElseGet(
                    sleepDuration,
                    () -> Double.valueOf(Math.pow(2.0, getRetries()) * 1000.0).longValue());
            Thread.sleep(sleepDuration);
            if (getRetries() < 4)
                setRetries(getRetries() + 1);
        
        catch (Exception ignored) 
            logger.warn("Failed to pause job queue processor.");
        
    

【问题讨论】:

创建定时器的代码在哪里? 我没有创建任何东西,所以我很惊讶。不知道如何正确地进行分析。 你尝试过什么调试?你在 Timer 的构造函数中下过断点吗? 没有看到这段代码是如何启动的或者调用了什么代码,这是无法回答的。 我只是在 Timer 构造函数中放置了一个断点,并看到线程是从 dequeueJobEntry() 中创建的。似乎在建立连接时会发生这种情况。这很有趣,因为在某些时候,容器中也发生了错误,其中存在连接问题、连接过多或类似问题。我会将相关代码添加到我的答案中。 【参考方案1】:

这似乎是由a bug that was resolved in a more recent version of DB2 than I was using引起的。

应用程序在使用 API 时获得大量计时器线程 timerLevelforQueryTimeout 值未在 使用 JCC 驱动程序版本 11.5 GA (JCC 4.26.14) 的应用程序或 之后。 此问题已在 11.5 M4 FP0(JCC 4.27.25) 中修复。

我在我的 POM 文件中将版本更新为较新的版本 (11.5.6),但这并没有解决问题。原来我的 K8s pod 仍在使用 11.5.0 并且 Maven 表现得很奇怪。然后我申请了this technique(在POM文件中使用dependencyManagement)并加载了较新的版本。

【讨论】:

以上是关于Spring应用程序的定时器线程不断增加的主要内容,如果未能解决你的问题,请参考以下文章

delphi 7 做多线程程序,内存不断增加,怎么解决?

Tomcat PermGen 上的 Spring MVC 空间不断增加

在 MFC 中不断增加进度条

Spring使用@Scheduled注解配置定时任务

Spring4+Springmvc+quartz实现多线程动态定时调度

以编程方式增加 Spring Boot 中的线程数