干净地中断zeromq轮询线程

时间:2014-02-26 16:16:53

标签: java multithreading zeromq jeromq

我使用jeromq 0.3.2编写了一个用Java编写的多线程应用程序。我正在努力将它放入Tanuki服务包装器中,以便它作为Windows服务运行,而我在干净地停止线程时遇到了一些麻烦。代理的run()方法是来自Simple Piratethe guide模式的变体,如下所示:

public void run()
{
    ZContext context = new ZContext();
    Socket frontend = context.createSocket(ZMQ.ROUTER);
    Socket backend = context.createSocket(ZMQ.ROUTER);
    frontend.bind("tcp://*:5555");
    backend.bind("inproc://workers");

    while (!Thread.currentThread().isInterrupted())
    {
        ZMQ.Poller poller = new ZMQ.Poller(2);
        poller.register(frontend, ZMQ.Poller.POLLIN);
        poller.register(backend, ZMQ.Poller.POLLIN);
        poller.poll();
        if (poller.pollin(0))
        {
            processFrontend(frontend, backend, context);
        }
        if (poller.pollin(1))
        {
            processBackend(frontend, backend);
        }
    }

    // additonal code to close worker threads
}

当控制包装器想要停止应用程序时,如何干净地退出此循环?

如果当前没有连接的客户端,则在调用poller.poll()时阻止循环,因此如果包装器在线程上调用interrupt(),则忽略它。如果有客户端当前正在发送消息,则调用interrupt()会导致poller.poll()方法抛出zmq.ZError$IOException: java.nio.channels.ClosedByInterruptException

我也尝试过使用:

PollItem[] items = {
    new PollItem(frontend, Poller.POLLIN),
    new PollItem(backend, Poller.POLLIN)
};
int rc = ZMQ.poll(items, 2, -1);

if (rc == -1)
    break;

if (items[0].isReadable())
{
    processFrontend(frontend, backend, context);
}

if (items[1].isReadable())
{
    processBackend(frontend, backend);
}

但是对ZMQ.poll的调用表现出相同的行为。两种可能的替代方案是:

  • ZMQ.poll上设置超时,并在tryEx / catch中包含run()方法的内容以用于IOException。
  • 向我的Runnable添加一个方法,该方法将连接到前端并发送一条特殊消息,该消息将在processFrontend中读取并导致代码突破循环。

第一个似乎有点脏,第二个感觉有点脆弱。我还应该考虑其他方法吗?是否有一些我可以使用的轮询方法能更干净地对线程中断作出反应?

1 个答案:

答案 0 :(得分:2)

最好将循环提取到单独的线程并打开另一个inproc PULL套接字,以便循环轮询来自3个套接字的消息:frontendbackend和{{1 }}。如果主线程收到中断信号,则应该向代理循环发送control命令。

这个模式正好在我的项目中实现:https://github.com/thriftzmq/thriftzmq-java/blob/master/thriftzmq/src/main/java/org/thriftzmq/ProxyLoop.java

在主线程上,您可以添加STOP并从其中发送shutdownHook命令到循环。

STOP

P.S。使用guava-library中的原语来管理服务生命周期使生活变得更加容易。