6

我有一项服务,我想实现为 Google Guava Service

该服务基本上运行一个while (true)循环,当事件到达BlockingQueue. 此处提供了简化的示例代码:

https://gist.github.com/3354249

问题是代码阻塞了BlockingQueue#take(),所以停止服务的唯一方法是中断它的线程。这可以使用番石榴AbstractExecutionThreadService吗?

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

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

  • 在其他情况下,无法避免线程中断,例如,如果服务在从InputStream.

4

2 回答 2

7

您可以覆盖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();
        }
    }
}
于 2012-12-21T13:15:17.860 回答
4

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

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

例子:

轮询:

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 是长期存在的并且有可能无限期阻塞,我认为使用 anAbstractExecutionThreadService是不可能的。您应该改为使用AbstractService创建并保存对其自己的执行线程的引用,以便您可以在doStop()方法中中断它。

于 2012-08-15T04:25:36.193 回答