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
实现。我认为可以为番石榴添加这种功能,因为这似乎是一种常见的需求。非常好,这应该是公认的解决方案,比使用有毒的轮询要干净得多!