zoukankan      html  css  js  c++  java
  • EJB之Timer

    EJB Timer

    • 要么: Annotation @Schedule 或者方法前声明@Timeout
    • 要么: 在部署描述中定义timeout-method
    • 如果是使用@Schedule, Timer在一个ejb中可以支持多个,如:


        @Schedule(second="*/2", minute="*",hour="*", persistent=false,info="timer1")
        public void doWork(){
            System.out.println( "Hi from the EJB timer example!" );
        }


        @Schedule(second="*/1", minute="*",hour="*", persistent=false,info="timer2")
        public void doWork2(){
            System.out.println( "Hi .... 2nd timer!" );    
        }
    以上分别启动了2个timer,一个每隔2秒执行一次,一个每隔1秒执行一次. 执行时container做了并发访问控制.也就是说callback方法一个时刻只能执行一个方法.

    • 如果是使用@Timeout, 也就是Programmatic Timers, callback方法有且只有一个.

    All timers created via one of the TimerService timer creation methods for a particular component use a single timeout callback method. --From ejb spec 3.1 chapter 18
    如前一个调用没有完成,而后面的timer过来了,在后面的timer在调用callback时会等待write lock(ejb方法默认), 如果超时就会出现如下异常, Jboss的行为, 还会retry一次,如果还是timeout,则会放弃.:

    09:20:59,045 ERROR [org.jboss.as.ejb3] (EJB default - 2) JBAS014122: Error during retrying timeout for timer: [id=c2a31520-2c55-4b01-b362-d8dfdb73a2d0 timedObjectId=jboss-ejb-timer.jboss-ejb-timer.TimeoutExample auto-timer?:false persistent?:false timerService=org.jboss.as.ejb3.timerservice.TimerServiceImpl@65886ae8 initialExpiration=Tue Mar 29 09:20:48 CST 2016 intervalDuration(in milli sec)=0 nextExpiration=null timerState=RETRY_TIMEOUT: javax.ejb.ConcurrentAccessTimeoutException: JBAS014373: EJB 3.1 PFD2 4.8.5.5.1 concurrent access timeout on org.jboss.invocation.InterceptorContext$Invocation@7c49f17f - could not obtain lock within 5000MILLISECONDS
        at org.jboss.as.ejb3.concurrency.ContainerManagedConcurrencyInterceptor.processInvocation(ContainerManagedConcurrencyInterceptor.java:100) [jboss-as-ejb3-7.3.0.Final-redhat-14.jar:7.3.0.Final-redhat-14]



    TimerService的createSingleActionTimer()和createIntervalTimer()

    • createSingleActionTimer

    只触发一次,如果触发时等不到锁,timeout, 则如上所述,再试一次,如果还不行,直接放弃。
    注意: 如是Singleton的EJB, 默认的锁是Write lock, 除非主动声明为READ lock, 如:@Lock(LockType.READ)

    • createIntervalTimer

    周期性触发,到点触发发现上一个还没搞完,则直接skip,放弃了,接着等下一个,如下code

         @Timeout
        public void scheduler(Timer timer) {
            System.out.println("EJB Timer: Info=" + timer.getInfo() + " " + Thread.currentThread().getName());

            try {
                Thread.sleep(1000*30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


        //
        @PostConstruct
        public void initialize( InvocationContext ctx ) {
            //...
            timerService.createIntervalTimer(2000, 10*1000, new TimerConfig("Single Timer #2", false));
            //....
        }

    输出的log如下:
    10:21:47,864 INFO  [stdout] (EJB default - 7) EJB Timer: Info=Single Timer #2 EJB default - 7

    10:21:57,864 WARN  [org.jboss.as.ejb3] (EJB default - 9) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:21:57 CST 2016
    10:22:07,864 WARN  [org.jboss.as.ejb3] (EJB default - 6) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:22:07 CST 2016
    10:22:17,864 WARN  [org.jboss.as.ejb3] (EJB default - 8) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:22:17 CST 2016
    10:22:27,865 INFO  [stdout] (EJB default - 3) EJB Timer: Info=Single Timer #2 EJB default - 3

    10:22:37,864 WARN  [org.jboss.as.ejb3] (EJB default - 10) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:22:37 CST 2016
    10:22:47,864 WARN  [org.jboss.as.ejb3] (EJB default - 2) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:22:47 CST 2016
    10:22:57,864 WARN  [org.jboss.as.ejb3] (EJB default - 1) JBAS014143: A previous execution of timer [jboss-ejb-timer.jboss-ejb-timer.TimeoutExample 8ba38f5a-0da7-4993-8b0b-e69854f61ee4] is still in progress, skipping this overlapping scheduled execution at: Tue Mar 29 10:22:57 CST 2016

    Jboss quickstart中有timer的例子。    


    更复杂的例子:

    如果显示指定callback方法为read lock,情况如何呢?

    1. 如果上一个callback方法没有完成,这时候下一个timer(第二次timer)触发的调用过来了.
    2. 因为是read lock, 所以顺利进入到callback方法内部, 上面说的等锁而导致的timeout retry行为就不会发生.
    3. ejb container从线程池中调度一个thread过来,执行callback,因为某种原因花了很长时间.
    4. 第三次timer触发, ejb从线程池再拿一个thread,执行callback, ...
    5. 到了第11次触发(线程池数量假设为10), 无线程可用,方法阻塞,等待(注意不会timeout,因为已经进入到callback方法体)
    6. 其他ejb如果需要从线程池中启动, 发现无资源可用,也会继续等待, 注意是等待,
    7. 如果积攒的需要启动的线程越来越多, 如果前面的callback方法突然返回,哈哈,后面的线程就会疯狂的run.
    8. .....

    所以搞timer, 最好不要将callback设置为read lock, 否则有可能thread leak, 试想你启动一个timer,每一秒钟执行一次, 执行的过程中hung住了, 而此时callback方法为read lock.

    ....

    如:

    //EJB A中

        @Timeout
        @Lock(LockType.READ)
        public void scheduler(Timer timer) {

            //Just test code, please DONT use sleep in your code!

            try {
                Thread.sleep(1000*30);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }

    //in initialize method

    for(int i = 2; i < 20; i++)
                timerService.createSingleActionTimer(1000, new TimerConfig("Single Timer #1", false) );

    //EJB B

       @Schedule(second="*/2", minute="*",hour="*", persistent=false)
        public void doWork(){
            System.out.println( "Hi from the EJB timer example!" );      //这些timer会一直积攒在那里, 因为所有的线程全部被EJB A占用,没有返回.

        }

    所以线程池里没有线程可用会死等下去, 而如果timer调用的callback方法不会死等, 有timeout. 如果是read lock就会一直耗干线程池中的线程实例.

    关于timer.cancel

    如果一个timer已经开始被执行,但还没完成,这时候调用timer.cancel()会成功,但当先已经被触发的API会继续执行完毕, 不会stop掉。

  • 相关阅读:
    城市社会经济专项规划之生态产业规划
    土地资源承载力研究
    生态功能区划方法之三:聚类分析法和生态融合法
    生态功能区划综述
    生态功能区划及生态规划的重要内容:生态环境现状评价
    生态功能区划方法之一:生态敏感性分析法
    生态环境专项规划
    城市社会经济专项规划之生态人居规划
    城市生态规划关键技术方法之五:生态支持系统瓶颈分析方法
    环境容量研究
  • 原文地址:https://www.cnblogs.com/bjfarmer/p/5332352.html
Copyright © 2011-2022 走看看