Java 我能用番石榴吗;需要中断的服务的AbstractExecutionThreadService?
我有一个服务,我想作为谷歌番石榴Java 我能用番石榴吗;需要中断的服务的AbstractExecutionThreadService?,java,service,guava,interrupt,Java,Service,Guava,Interrupt,我有一个服务,我想作为谷歌番石榴服务实现 该服务基本上运行一个while(true)循环,当事件到达阻塞队列时对其进行处理。此处提供了简化的示例代码: 问题是代码阻塞了BlockingQueue#take(),因此停止服务的唯一方法是中断其线程。使用Guava的AbstractExecutionThreadService是否可以实现这一点 当然,在本例中,我可以使用queue.poll(1,TimeUnit.SECONDS)将queue.take()替换为轮询循环,从而消除线程中断的需要。然而
服务实现
该服务基本上运行一个while(true)
循环,当事件到达阻塞队列时对其进行处理。此处提供了简化的示例代码:
问题是代码阻塞了BlockingQueue#take()
,因此停止服务的唯一方法是中断其线程。使用Guava的AbstractExecutionThreadService
是否可以实现这一点
当然,在本例中,我可以使用queue.poll(1,TimeUnit.SECONDS)
将queue.take()
替换为轮询循环,从而消除线程中断的需要。然而:
- 出于性能和代码可读性的原因,我希望避免这样做
- 还有其他无法避免线程中断的情况,例如,如果从
InputStream
读取字节时服务被阻塞
如果您想使用AbstractExecutionThreadService
,我不认为中断线程是一个真正的选项,因为实际上没有任何方法可以获取线程引用以调用中断()
如果您使用的是BlockingQueue,则必须在检查服务是否仍在运行的while循环中进行轮询,或者可以使用sentinel值来警告工作方法它需要停止
示例:
投票:
while(isRunning()) {
Value v = queue.poll(1, TimeUnit.SECONDS);
// do something with v
}
前哨值:
while(isRunning()) {
Value v = queue.take();
if(v == POISON) {
break;
}
// do something with v
}
我个人会尝试轮询解决方案,看看性能如何。您可能会惊讶于这对性能的影响如此之小
至于从InputStream读取,如果InputStream是长寿命的并且有可能无限期地阻塞,我认为使用AbstractExecutionThreadService
是不可能的。相反,您应该使用一个AbstractService
,它创建并保存对自己执行线程的引用,这样您就可以在doStop()
方法中中断它。您可以重写executor()
方法来提供自己的executor,然后将对线程的引用存储到您的字段中。然后,如果需要,您可以很容易地中断线程
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import com.google.common.util.concurrent.AbstractExecutionThreadService;
public abstract class InterruptibleExecutionThreadService extends AbstractExecutionThreadService {
private final AtomicReference<Thread> runningThread = new AtomicReference<Thread>(null);
@Override
protected Executor executor() {
return new Executor() {
@Override
public void execute(Runnable command) {
Thread thread = Executors.defaultThreadFactory().newThread(command);
runningThread.compareAndSet(null, thread);
try {
thread.setName(serviceName());
} catch (SecurityException e) {
// OK if we can't set the name in this environment.
}
thread.start();
}
};
}
protected void interruptRunningThread() {
Thread thread = runningThread.get();
if (thread != null) {
thread.interrupt();
}
}
}
import java.util.concurrent.Executor;
导入java.util.concurrent.Executors;
导入java.util.concurrent.AtomicReference;
导入com.google.common.util.concurrent.AbstractExecutionThreadService;
公共抽象类InterruptableExecutionThreadService扩展了AbstractExecutionThreadService{
private final AtomicReference runningThread=新的AtomicReference(null);
@凌驾
受保护的执行者执行者(){
返回新的执行者(){
@凌驾
public void execute(Runnable命令){
Thread Thread=Executors.defaultThreadFactory().newThread(命令);
runningThread.compareAndSet(null,线程);
试一试{
setName(serviceName());
}捕获(安全异常e){
//如果在此环境中无法设置名称,则可以。
}
thread.start();
}
};
}
受保护的void interruptRunningThread(){
Thread-Thread=runningThread.get();
if(线程!=null){
thread.interrupt();
}
}
}
谢谢您的解释。我将尝试编写自己的AbstractService
实现。我认为可以为番石榴添加这种功能,因为这似乎是一种常见的需求。非常好,这应该是公认的解决方案,比使用有毒的轮询要干净得多!