我有一个侦听外部事件的对象.收到事件后,我的对象需要执行任务(Runnable).但是,有一个限制:
一旦任务开始执行,我就不应该开始其他任务(我可以忽略它们),直到原始任务完成并且在那之后经过一定量的时间(限制).
这里建议使用信号量实现:
public class Sample {
private final Semaphore semaphore = new Semaphore(1);
private final ScheduledExecutorService executor;
public Sample(ScheduledExecutorService executor) {
this.executor = executor;
}
public void tryRun() {
if (semaphore.tryAcquire()) {
try {
executor.submit(
new Runnable() {
@Override
public void run() {
try {
doIt();
} finally {
try {
executor.schedule(
new Runnable() {
@Override
public void run() {
semaphore.release();
}
},
1,
TimeUnit.MINUTES
);
} catch (Throwable t) {
semaphore.release();
}
}
}
}
);
} catch (Throwable t) {
semaphore.release();
}
}
}
private void doIt() {
// the exact task executing logic is here
}
}
Run Code Online (Sandbox Code Playgroud)
代码对我来说似乎太冗长了.有没有更好的方法呢?
PS另一个限制是ScheduledExecutorService是我对外部执行器的唯一接口,我不能在我的对象中启动自己的线程/执行器
只需使用ThreadPoolExecutor单线程.你必须决定是否可以排队很多其他任务.如果没有,请将它自己传递给BlockingQueue容量1,我相信这最多可以让一个任务排队.我正在考虑如何将其降至零.
请注意,您需要配置TPE以通过a丢弃被拒绝的任务DiscardPolicy.
+1到@djechlin.这是正确的答案.要添加实现:
ExecutorService threadPool =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(), new ThreadPoolExecutor.DiscardPolicy());
Run Code Online (Sandbox Code Playgroud)
回到你的问题.
一旦任务开始执行,我就不应该开始其他任务(我可以忽略它们),直到原始任务完成并且在那之后经过一定量的时间(限制).
这启动1并且只有1个线程,使用同步队列,DiscardPolicy除非线程正在等待运行它,否则它将丢弃任何任务.如果单个线程正在运行,那么提交给池的任何任务都将被拒绝并发送到拒绝策略.在你的情况下,你想要丢弃它们.
如果你真的想在工作线程繁忙的情况下排队任务,那么你应该使用有界的LinkedBlockingQueue.可能使用拒绝策略在队列满时阻止调用者.
类似于以下内容:
ExecutorService threadPool =
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(10), new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// this will block the caller until the queue has space
executor.getQueue().add(r);
}
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
970 次 |
| 最近记录: |