3

我需要实现一个定期读取目录并处理在其中找到的文件的服务。我想经常阅读目录,例如每 5 秒。问题是发送文件可能需要一些时间。发送文件时将它们移走。我的想法是使用ThreadPoolTaskScheduler单个线程池并将任务安排为每 5 秒运行一次。该解决方案似乎有效,我经常阅读目录,当任务为空时,任务很快完成。当我发现一些文件时,任务需要更长的时间,但由于池只有一个线程,因此没有执行其他并发任务。

我的问题是我无法理解由于池已满而无法运行的计划任务发生了什么?他们是被取消还是刚刚入队。我担心排队太多任务并造成内存泄漏。

这是我的 spring.xml

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
     xmlns:task="http://www.springframework.org/schema/task"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/task
        http://www.springframework.org/schema/task/spring-task-3.2.xsd">
....
    <bean id="inviaFattureTask"  class="com.sirio.fatturazionepa.invio.InviaFattureTask">
        <property name="fileSystemUtils" ref="fileSystemUtils"></property>
        <property name="fattureManager" ref="fattureManager"></property>
    </bean>
    <task:scheduler id="myScheduler" pool-size="1"/>

...

</beans>

和java代码。

TaskScheduler ts = appContext.getBean(TaskScheduler.class);
        InviaFattureTask task = appContext.getBean(InviaFattureTask.class);
         ts.schedule(task, new CronTrigger("*/5 * * * * ?"));

谢谢大卫

4

3 回答 3

1

快速测试会告诉你发生了什么:
XML:

<task:scheduler id="taskScheduler" pool-size="1"/>  

和Java:

    test.schedule(new Runnable() {
        @Override
        public void run() {
            long ts = System.currentTimeMillis();
            System.out.println("Job start: " + ts);
            long counter = 0;
            while (System.currentTimeMillis() - ts < 10000) {
                counter++;
            }
            System.out.println("Job end: " + System.currentTimeMillis());
        }

    }, new CronTrigger("*/5 * * * * ?"));

输出:

工作开始:1397660360001
工作结束:1397660370001
工作开始:1397660375000
工作结束:1397660385000
工作开始:1397660390001
工作结束:1397660400001

至于解释,源代码ThreadPoolTaskSchedulerReshcedulingRunnable解释得很好:

    public ScheduledFuture schedule() {
        synchronized (this.triggerContextMonitor) {
            this.scheduledExecutionTime = this.trigger.nextExecutionTime(this.triggerContext);
            if (this.scheduledExecutionTime == null) {
                return null;
            }
            long initialDelay = this.scheduledExecutionTime.getTime() - System.currentTimeMillis();
            this.currentFuture = this.executor.schedule(this, initialDelay, TimeUnit.MILLISECONDS);
            return this;
        }
    }

    @Override
    public void run() {
        Date actualExecutionTime = new Date();
        super.run();
        Date completionTime = new Date();
        synchronized (this.triggerContextMonitor) {
            this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
        }
        if (!this.currentFuture.isCancelled()) {
            schedule();
        }
    }

IE 它安排任务,当它结束时 - 找到下一个执行触发器并安排它,然后使用简单的延迟。执行器中的线程数无关紧要,直到前一个完成后才会开始下一个执行(您可以用 2 个线程测试上述内容以确认)。

此外,既然您似乎想定期运行此任务 - 为什么不使用ScheduledTaskExecutor具有 2 种方法的具体用例呢?( scheduleWithFixedDelay(), scheduleAtFixedRate())

于 2014-04-16T15:08:24.990 回答
1

使用标签时使用的默认策略<task:scheduler />是中止新任务并抛出RejectedExecutionException.

如果您使用普通 bean 来配置,ThreadPoolTaskScheduler您可以设置更多可以影响该行为的属性,选择的 'executor' 和 'rejectedExecutionHandler` 在其中起着重要作用。

此外,您正在使用 java 来配置您的任务,您可以将其移至 xml。

<task:scheduled-tasks>
   <task:scheduled ref="inviaFattureTask" cron="*/5 * * * * ?"/>
</task:scheduled-tasks>

有关更多信息,请查看参考指南

于 2014-04-16T14:29:38.350 回答
0

最后我选择了这个配置:

<task:scheduler  id="myScheduler" pool-size="1"/>
 <task:executor  id="executor" rejection-policy="ABORT"/>
<task:scheduled-tasks scheduler="myScheduler" >
    <task:scheduled ref="inviaFattureTask" method="run"   cron="*/5 * * * * ?"/>
</task:scheduled-tasks>

语义几乎相同,但配置更明确。

我使用 cron 是因为(scheduleWithFixedDelay(), scheduleAtFixedRate()) 我不打算进行多次安装,而是希望能够以多种不同的方式自由配置触发器。

谢谢

于 2014-04-16T15:58:11.437 回答