【问题标题】:ExecutorService doesn't call run() in RunnableExecutorService 不在 Runnable 中调用 run()
【发布时间】:2013-04-06 11:58:22
【问题描述】:

我在 Android 的 asmack 库中遇到了一个奇怪的问题。该库使用 ExecutorService 来解析传入的数据包:

private ExecutorService listenerExecutor;

listenerExecutor = Executors.newSingleThreadExecutor(new ThreadFactory() {

        public Thread newThread(Runnable runnable) {
            Thread thread = new Thread(runnable,
                    "Smack Listener Processor (" + connection.connectionCounterValue + ")");
            thread.setDaemon(true);
            return thread;
        }
    });

(...)

listenerExecutor.submit(new ListenerNotification(packet));

(...)

/**
 * A runnable to notify all listeners of a packet.
 */
private class ListenerNotification implements Runnable {

    private Packet packet;

    public ListenerNotification(Packet packet) {
        this.packet = packet;
    }

    public void run() {
        for (ListenerWrapper listenerWrapper : connection.recvListeners.values()) {
            listenerWrapper.notifyListener(packet);
        }
    }
}

一切正常,直到调用 submit() 方法时,也调用了 ListenerNotification 的构造函数,但不再调用 ListenerNotification 中的 run() 方法。

这可能是什么原因? ExecutorService 中是否有一些机制可能导致对提交的调用被忽略?

【问题讨论】:

  • ListenerNotification.run() 是否运行一次?您是否尝试过使用默认的 ThreadFactory 而不是您自己的?
  • 是的,它会运行一段时间然后停止。这不是确定性的,也不是可重现的,这让我想知道......我没有对这个库代码进行更改 - 我只在我的两个项目中使用它。我以前使用过同一个库,我没有遇到这种性质的问题,现在它们出现了。我什至从 run() 方法中迭代的侦听器列表中删除了我自己的侦听器,因为我认为可能我正在做的任何事情都花费了太长时间,但这也没有帮助。
  • 尝试旧版本的库,看看它现在是否也发生了。也许单线程执行器处于某种“锁定”状态。这是我听说的关于 aSmack 此类行为的第一份报告。
  • 是的,线程实际上被我自己的代码阻塞了。

标签: android executorservice java.util.concurrent asmack


【解决方案1】:

不出所料,问题在我这边。

我在我的代码中实现了一个 Roster Packet 侦听器并覆盖了 processPacket 方法:

@Override
public void processPacket(Packet packet) {
    if (packet instanceof RosterPacket) {
        RosterPacket rosterPacket = (RosterPacket) packet;
        Logger.d(LOGTAG, "Initial roster packet received: " + rosterPacket.getRosterItemCount());
        mConnection.removePacketListener(this);
        fireOnInitialRosterPacketReceived(rosterPacket);
    }
}

但是,我的内部监听器调用方法引入了一个无限循环:

private void fireOnInitialRosterPacketReceived(RosterPacket rosterPacket) {
    Iterator<SessionListener> it = mSessionListeners.iterator();
    while (it.hasNext()) {
        // it.next().onInitialRosterPacketReceived(mConnection,
        // rosterPacket);
    }
}

这阻塞了执行器启动的线程,因此后续的提交调用不会再次触发该线程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-28
    相关资源
    最近更新 更多