停止Spring计划执行,如果它在一段固定时间后挂起

时间:2016-10-07 12:51:20

标签: java spring spring-boot spring-scheduled

我已经使用Spring Framework' Scheduled来安排我的工作每隔5分钟使用cron运行一次。但是有时候我的工作无限期地等待外部资源,我不能在那里暂停。我无法使用fixedDelay作为先前的进程,有时会进入等待无限模式,我必须每隔5分钟刷新数据。

所以我在Spring框架Scheduled中寻找任何选项,以便在fixed-time成功运行之后停止该进程/线程。

我在下面的设置中找到ThreadPoolExecutor初始化keepAliveTime@Configuration@Bean(destroyMethod="shutdown") public Executor taskExecutor() { int coreThreads = 8; int maxThreads = 20; final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor( coreThreads, maxThreads, 120L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>() ); threadPoolExecutor.allowCoreThreadTimeOut(true); return threadPoolExecutor; } 我放入LogManager.LogFactory = new Log4NetFactory(configureLog4Net: true); 课程。任何人都能告诉我这项工作是否符合我的预期。

{{1}}

3 个答案:

答案 0 :(得分:8)

我不确定这会按预期工作。确实keepAlive用于IDLE线程,我不知道你的等待资源的线程是否处于IDLE状态。此外,只有当线程数大于核心时,才能真正知道它何时发生,除非你监视线程池。

  

keepAliveTime - 当线程数大于核心时,这是多余空闲线程在终止之前等待新任务的最长时间。

您可以做的是:

public class MyTask {

    private final long timeout;

    public MyTask(long timeout) {
        this.timeout = timeout;
    }

    @Scheduled(cron = "")
    public void cronTask() {
        Future<Object> result = doSomething();
        result.get(timeout, TimeUnit.MILLISECONDS);
    }

    @Async
    Future<Object> doSomething() {
        //what i should do
        //get ressources etc...
    }
}

不要忘记添加@EnableAsync

通过实施Callable,在没有@Async的情况下也可以这样做。

编辑:请记住,它会等到超时,但运行任务的线程不会被中断。发生TimeoutException时,您需要调用Future.cancel。并在任务中检查isInterrupted()以停止处理。如果你正在调用api,请确保选中了isInterrupted()。

答案 1 :(得分:7)

allowCoreThreadTimeOut timeout 设置无效,导致它只允许工作线程在一段时间后无法工作(参见javadocs)

你说你的工作无限期地等待外部资源。我确定这是因为您(或您使用的某些第三方库)使用的套接字默认超时。 还要记住jvm在socket.connect / read上阻塞时忽略了Thread.interrupt()。

因此找出你的任务中使用的女巫套接字库(以及它是如何使用的)并更改它的默认超时设置。

例如:在Spring内部广泛使用 RestTemplate (在休息客户端,春季社交,春季安全OAuth等)。并且有ClientHttpRequestFactory实现来创建RestTemplate实例。默认情况下,spring使用SimpleClientHttpRequestFactory使用JDK套接字。默认情况下,所有超时都是无限的。

因此,找出你准确冻结的位置,阅读它的文档并正确配置它。

P.S。如果您没有足够的时间并且“感到幸运”,请尝试使用设置jvm属性 sun.net.client.defaultConnectTimeout 来运行您的应用程序, sun.net.client.defaultReadTimeout 到一些合理的值(详见docs

答案 2 :(得分:2)

QBluetoothLocalDevice localDevice; QString localDeviceName; // Check if Bluetooth is available on this device if (localDevice.isValid()) { // Turn Bluetooth on localDevice.powerOn(); // Read local device name localDeviceName = localDevice.name(); // Make it visible to others localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable); // Get connected devices QList<QBluetoothAddress> remotes; remotes = localDevice.connectedDevices(); ui->textBrowser->setText(localDevice.name() + "\n" + localDevice.address().toString()); } 仅用于清除一段时间内不需要的工作线程 - 它对提交给执行程序的任务的执行时间没有任何影响。

如果花时间考虑中断,你可以启动一个新线程并加入超时,如果没有及时完成则中断它。

keepAliveTime