2012-08-15 25 views
4

我有一项服务,我希望作为Google Guava Service实施。我可以使用Guava的AbstractExecutionThreadService来处理需要中断的服务吗?

该服务基本上运行一个while (true)循环,它在到达BlockingQueue时处理事件。简化的示例代码,请访问:

https://gist.github.com/3354249

的问题是,在BlockingQueue#take()代码块,所以要停止该服务的唯一方法是中断它的线程。这可能使用番石榴的AbstractExecutionThreadService

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

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

  • 还有其他一些情况下,这是无法避免的线程中断,例如如果服务在从InputStream读取字节时被阻止。

回答

3

我不认为中断线程是一个真正的选择,如果你想使用AbstractExecutionThreadService因为有没有真正的任何方式,以调用interrupt()去的线程的引用。

如果您使用的是BlockingQueue,您必须在while循环内轮询,以检查服务是否仍在运行,或者您可以使用sentinel值来警示worker方法需要停止。

例子:

投票:

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()方法中打断它。

+0

感谢您的解释。我会尝试编写自己的'AbstractService'实现。我认为可以向Guava添加这种功能,因为它似乎是一种常见的需求。 – 2012-08-16 00:40:59

5

您可以覆盖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(); 
     } 
    } 
} 
+0

这是一个很好的解决方案! – 2012-12-22 03:36:25

+0

非常好,这应该是可以接受的解决方案,比使用轮询毒药更清洁! – RedShift 2017-11-22 15:11:52

相关问题