EJB @Schedule 等待方法完成 [英] EJB @Schedule wait until method completed

查看:25
本文介绍了EJB @Schedule 等待方法完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想编写一个每分钟执行一次的后台作业 (EJB 3.1).为此,我使用以下注释:

I want to write a back-ground job (EJB 3.1), which executes every minute. For this I use the following annotation:

@Schedule(minute = "*/1", hour = "*")

工作正常.

但是,有时这项工作可能需要一分钟以上的时间.在这种情况下,计时器仍会被触发,从而导致线程问题.

However, sometimes the job may take more than one minute. In this case, the timer is still fired, causing threading-issues.

是否有可能在当前执行未完成时终止调度程序?

Is it somehow possible, to terminate the scheduler if the current execution is not completed?

推荐答案

如果只能同时激活 1 个计时器,则有几种解决方案.

If only 1 timer may ever be active at the same time, there are a couple of solutions.

首先,@Timer 应该出现在 @Singleton 上.在 Singleton 方法中,默认情况下是写锁定的,因此当容器中仍有活动时尝试调用计时器方法时,容器将自动被锁定.

First of all the @Timer should probably be present on an @Singleton. In a Singleton methods are by default write-locked, so the container will automatically be locked-out when trying to invoke the timer method while there's still activity in it.

以下基本就够了:

@Singleton
public class TimerBean {

    @Schedule(second= "*/5", minute = "*", hour = "*", persistent = false)
    public void atSchedule() throws InterruptedException {

        System.out.println("Called");
        Thread.sleep(10000);
    }
}

atSchedule 默认是写锁定的,并且其中只能有一个线程处于活动状态,包括由容器发起的调用.

atSchedule is write-locked by default and there can only ever be one thread active in it, including calls initiated by the container.

在被锁定时,容器可能会重试计时器,因此为了防止这种情况,您可以使用读取锁代替并委托给第二个 bean(需要第二个 bean,因为 EJB 3.1 不允许升级读取锁定为写锁).

Upon being locked-out, the container may retry the timer though, so to prevent this you'd use a read lock instead and delegate to a second bean (the second bean is needed because EJB 3.1 does not allow upgrading a read lock to a write lock).

定时器 bean:

@Singleton
public class TimerBean {

    @EJB
    private WorkerBean workerBean;

    @Lock(READ)
    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    public void atSchedule() {

        try {
            workerBean.doTimerWork();
        } catch (Exception e) {
            System.out.println("Timer still busy");
        }
    }

}

工作bean:

@Singleton
public class WorkerBean {

    @AccessTimeout(0)
    public void doTimerWork() throws InterruptedException {
        System.out.println("Timer work started");
        Thread.sleep(12000);
        System.out.println("Timer work done");
    }
}

这可能仍会在日志中打印一个嘈杂的异常,因此更详细但更安静的解决方案是使用显式布尔值:

This will likely still print a noisy exception in the log, so a more verbose but more silently solution is to use an explicit boolean:

定时器 bean:

@Singleton
public class TimerBean {

    @EJB
    private WorkerBean workerBean;

    @Lock(READ)
    @Schedule(second = "*/5", minute = "*", hour = "*", persistent = false)
    public void atSchedule() {
        workerBean.doTimerWork();
    }

}

工作bean:

@Singleton
public class WorkerBean {

    private AtomicBoolean busy = new AtomicBoolean(false);

    @Lock(READ)
    public void doTimerWork() throws InterruptedException {

        if (!busy.compareAndSet(false, true)) {
            return;
        }

        try {
            System.out.println("Timer work started");
            Thread.sleep(12000);
            System.out.println("Timer work done");
        } finally {
            busy.set(false);
        }
    }

}

还有一些可能的变化,例如您可以将繁忙检查委托给拦截器,或者将仅包含布尔值的单例注入计时器 bean,并在那里检查该布尔值等.

There are some more variations possible, e.g. you could delegate the busy check to an interceptor, or inject a singleton that only contains the boolean into the timer bean, and check that boolean there, etc.

这篇关于EJB @Schedule 等待方法完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆