我可以将Guava的AbstractExecutionThreadService用于需要中断的服务吗?

Chr*_*s B 5 java service interrupt guava

我有一项服务,我想将其作为Google Guava实施Service.

该服务基本上运行一个while (true)循环,在事件到达时处理它们BlockingQueue.这里提供简化的示例代码:

https://gist.github.com/3354249

问题是代码阻塞BlockingQueue#take(),因此停止服务的唯一方法是中断其线程.这可能是使用番石榴的AbstractExecutionThreadService吗?

当然,在这种情况下,我可以queue.take()使用轮询循环替换queue.poll(1, TimeUnit.SECONDS),从而消除了线程中断的需要.然而:

  • 出于性能和代码可读性的原因,我想避免这样做

  • 在其他情况下,无法避免线程中断,例如,如果在从a读取字节时阻止服务InputStream.

Pet*_*aný 6

您可以覆盖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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Mik*_*eck 4

如果您想使用 an ,我认为中断线程并不是一个真正的选择AbstractExecutionThreadService,因为实际上没有任何方法可以获取对线程的引用来调用interrupt().

如果您使用的是 BlockingQueue,则必须在 while 循环内进行轮询以检查服务是否仍在运行,或者您可以使用哨兵值来提醒工作方法需要停止。

例子:

轮询:

while(isRunning()) {
    Value v = queue.poll(1, TimeUnit.SECONDS);
    // do something with v
}
Run Code Online (Sandbox Code Playgroud)

哨兵值:

while(isRunning()) {
    Value v = queue.take();
    if(v == POISON) {
        break;
    }
    // do something with v
}
Run Code Online (Sandbox Code Playgroud)

我个人会尝试轮询解决方案,看看性能如何。您可能会惊讶于这对性能的影响如此之小。

至于从 InputStream 读取,如果 InputStream 寿命很长并且有可能无限期地阻塞,我认为使用 anAbstractExecutionThreadService是不可能的。您应该使用 anAbstractService它创建并保存对其自己的执行线程的引用,以便您可以在方法中中断它doStop()