这是我的用例。
旧系统更新数据库队列表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" />
将报告结果
答案 0 :(得分:3)
你可以尝试
当然,您必须处理调度程序锁定了一个队列的场景,但处理程序无论出于何种原因都没有完成处理。
伪代码:
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?
同时检查您的设计,它似乎没有正确处理同步。如果上一个作业正在运行并且对该行保持锁定,则您创建的下一个作业仍将看到该行,并将等待获取该特定行的锁定。