一起使用Spring @Scheduled和@Async

时间:2013-01-31 10:05:10

标签: spring memory scheduled-tasks

这是我的用例。

旧系统更新数据库队列表QUEUE。

我想要一份预定的定期工作 - 检查队列的内容 - 如果表中有行,它会锁定行并完成一些工作 - 删除QUEUE

中的行

如果上一个作业仍在运行,那么将创建一个新线程来完成工作。我想配置最大并发线程数。

我正在使用Spring 3,我目前的解决方案是执行以下操作(使用1毫秒的fixedRate来使线程基本上连续运行)

@Scheduled(fixedRate = 1)
@Async
public void doSchedule() throws InterruptedException {
    log.debug("Start schedule");
    publishWorker.start();
    log.debug("End schedule");
}

<task:executor id="workerExecutor" pool-size="4" />

这直接创建了4个线程,并且线程正确地共享了队列中的工作负载。但是,当线程需要很长时间才能完成时,我似乎得到了内存泄漏。

java.util.concurrent.ThreadPoolExecutor @ 0xe097b8f0                              |              80 |   373,410,496 |     89.74%
|- java.util.concurrent.LinkedBlockingQueue @ 0xe097b940                          |           48 |   373,410,136 |     89.74%
|  |- java.util.concurrent.LinkedBlockingQueue$Node @ 0xe25c9d68  

所以

1:我应该一起使用@Async和@Scheduled吗?

2:如果没有,那么我怎么用春天来达到我的要求呢?

3:只有当其他线程忙时才能创建新线程?

全部谢谢!

编辑:我认为工作队伍变得无限长......现在正在使用

    <task:executor id="workerExecutor"
    pool-size="1-4"
    queue-capacity="10" rejection-policy="DISCARD" />

将报告结果

2 个答案:

答案 0 :(得分:3)

你可以尝试

  1. 运行一个延迟一秒的调度程序,它将锁定&amp;取得全部 到目前为止尚未锁定的队列记录。
  2. 对于每条记录,调用Async方法,该方法将处理该记录&amp;删除它。
  3. 执行者的拒绝政策应该是ABORT,以便调度程序可以解锁尚未给出处理的队列。这样,调度程序可以在下次运行时再次尝试处理这些队列。
  4. 当然,您必须处理调度程序锁定了一个队列的场景,但处理程序无论出于何种原因都没有完成处理。

    伪代码:

    public class QueueScheduler {
        @AutoWired
        private QueueHandler queueHandler;
    
        @Scheduled(fixedDelay = 1000)
        public void doSchedule() throws InterruptedException {
            log.debug("Start schedule");
            List<Long> queueIds = lockAndFetchAllUnlockedQueues();
            for (long id : queueIds)
                queueHandler.process(id);
            log.debug("End schedule");
        }
    }
    
    public class QueueHandler {
    
        @Async
        public void process(long queueId) {
            // process the QUEUE & delete it from DB
        }
    }
    <task:executor id="workerExecutor" pool-size="1-4" queue-capcity="10"
         rejection-policy="ABORT"/>
    

答案 1 :(得分:0)

//using a fixedRate of 1 millisecond to get the threads to run basically continuously
@Scheduled(fixedRate = 1)

使用@Scheduled时,将创建一个新线程,并在指定的fixedRate上以1毫秒调用方法doSchedule。当您运行应用程序时,您已经可以看到4个线程竞争QUEUE表并且可能已经死锁。

通过进行线程转储来调查是否存在死锁。 http://helpx.adobe.com/cq/kb/TakeThreadDump.html

@Async注释在这里没有任何用处。

更好的实现方法是通过实现runnable并将类传递给具有所需线程数的TaskExecutor来创建类作为线程。

Using Spring threading and TaskExecutor, how do I know when a thread is finished?

同时检查您的设计,它似乎没有正确处理同步。如果上一个作业正在运行并且对该行保持锁定,则您创建的下一个作业仍将看到该行,并将等待获取该特定行的锁定。