簡體   English   中英

EJB @Schedule 等待方法完成

[英]EJB @Schedule wait until method completed

我想編寫一個每分鍾執行一次的后台作業 (EJB 3.1)。 為此,我使用以下注釋:

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

這是工作正常。

但是,有時這項工作可能需要一分鍾以上。 在這種情況下,計時器仍會被觸發,從而導致線程問題。

如果當前執行未完成,是否有可能終止調度程序?

如果只有 1 個計時器可能同時處於活動狀態,則有幾種解決方案。

所有的第一@Timer大概應該是存在於一個@Singleton 在 Singleton 方法中,默認情況下是寫鎖定的,因此在嘗試調用計時器方法時容器將自動被鎖定,而其中仍然存在活動。

以下基本上就足夠了:

@Singleton
public class TimerBean {

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

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

atSchedule默認是寫鎖定的,並且其中只能有一個線程處於活動狀態,包括由容器發起的調用。

在被鎖定時,容器可能會重試計時器,因此為了防止這種情況發生,您可以使用讀鎖代替並委托給第二個 bean(需要第二個 bean,因為 EJB 3.1 不允許將讀鎖升級到寫鎖)。

計時器豆:

@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");
        }
    }

}

工人豆:

@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");
    }
}

這可能仍會在日志中打印一個嘈雜的異常,因此更詳細但更安靜的解決方案是使用顯式布爾值:

計時器豆:

@Singleton
public class TimerBean {

    @EJB
    private WorkerBean workerBean;

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

}

工人豆:

@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,並在那里檢查該布爾值等。

我遇到了同樣的問題,但解決的方法略有不同。

@Singleton
public class DoStuffTask {

    @Resource
    private TimerService timerSvc;

    @Timeout
    public void doStuff(Timer t) {
        try {
            doActualStuff(t);
        } catch (Exception e) {
            LOG.warn("Error running task", e);
        }
        scheduleStuff();
    }

    private void doActualStuff(Timer t) {

        LOG.info("Doing Stuff " + t.getInfo());
    }

    @PostConstruct
    public void initialise() {
        scheduleStuff();
    }

    private void scheduleStuff() {
        timerSvc.createSingleActionTimer(1000l, new TimerConfig());
    }

    public void stop() {
        for(Timer timer : timerSvc.getTimers()) {
            timer.cancel();
        }
    }

}

這通過設置要在將來執行的任務(在本例中為一秒)來實現。 在任務結束時,它會再次安排任務。

編輯:更新以將“東西”重構為另一種方法,以便我們可以防范異常,以便始終重新安排計時器

從 Java EE 7 開始,可以使用“EE-aware” ManagedScheduledExecutorService ,即在 WildFly 中:

例如,在@Singleton @Startup @LocalBean ,注入在standalone.xml配置的默認“managed-scheduled-executor-service”:

@Resource
private ManagedScheduledExecutorService scheduledExecutorService;

@PostConstruct安排一些任務以固定延遲執行,即每秒執行一次:

scheduledExecutorService.scheduleWithFixedDelay(this::someMethod, 1, 1, TimeUnit.SECONDS);

scheduleWithFixedDelay

創建並執行一個周期性動作,該動作首先在給定的初始延遲后啟用,然后在一個執行終止和下一個執行開始之間具有給定的延遲。[...]

不要在 ie @PreDestroy關閉調度程序:

Managed Scheduled Executor Service 實例由應用服務器管理,因此 Java EE 應用程序被禁止調用任何與生命周期相關的方法。

好吧,我遇到了類似的問題。 有一個作業應該每 30 分鍾運行一次,有時該作業需要 30 多分鍾才能完成,在這種情況下,另一個作業實例正在啟動,而前一個作業尚未完成。 我通過使用一個靜態布爾變量解決了這個問題,每當它開始運行時我的工作就會將它設置為 true,然后在它完成時將它設置回 false。 由於它是一個靜態變量,所有實例將始終看到相同的副本。 當您設置和取消設置靜態變量時,您甚至可以同步塊。 class myjob{ private static boolean isRunning=false;

public executeJob(){
if (isRunning)
    return;
isRunning=true;
//execute job
isRunning=false;
  }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM