【问题标题】:Multithreading callback methods多线程回调方法
【发布时间】:2016-01-09 13:22:16
【问题描述】:

我的应用程序中有一个Service,它允许客户端注册以接收来自服务的回调。我试图实现它,以便在调用客户端回调实现时,它们可以异步运行,也可以在服务线程上按顺序运行。每个回调的具体行为取决于用于注册客户端以进行回调的方法。客户端可以注册registerClientForCallbacks让回调发生在主线程上,也可以注册registerClientForAsyncCallbacks让回调发生在新线程上。

我遇到的问题是,当我尝试在新线程上调用回调时,线程阻塞 thread.run() 直到可运行完成,有效地消除了我对多线程的尝试。我已经在下面发布了我的服务的代码(使用 Javadoc,因为我知道它很长)。有人可以帮我理解为什么 callAllRegisteredClients 中的线程没有同时运行吗?

public class ExampleService extends Service {
    /**
     * A record of the clients which have registered to receive callbacks from this service
     * asynchronously.
     */
    private Set<ClientCallbacks> registeredClientsAsync;

    /**
     * A record of the clients which have registered to receive callbacks from this service on the
     * service's main thread.
     */
    private Set<ClientCallbacks> registeredClientsMainThread;

    @Override
    public void onCreate() {
        super.onCreate();
        registeredClientsAsync = new HashSet<ClientCallbacks>();
        registeredClientsMainThread = new HashSet<ClientCallbacks>();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new LocalBinder();
    }

    /**
     * A binder with the singular purpose of returning a reference to the service.
     */
    public class LocalBinder extends Binder {
        public ExampleService getService() {
            return ExampleService.this;
        }
    }

    /**
     * Register this client to receive callback events from this service. Callback methods will
     * execute sequentially on the service's main thread. Consider using {@link
     * #registerClientForAsyncCallbacks(ClientCallbacks) registerClientForAsyncCallbacks} for
     * asynchronous callbacks.
     *
     * @param client the client to register, not null
     * @return true if the client is unregistered or has been
     * registered to receive callbacks asynchronously using {@link
     * #registerClientForAsyncCallbacks(ClientCallbacks) registerClientForAsyncCallbacks}, false
     * otherwise
     */
    public boolean registerClientForCallbacks(@NonNull ClientCallbacks client) {
        if (client == null) {
            throw new IllegalArgumentException("client cannot be null");
        }

        // Attempt to remove from async callbacks set (may do nothing)
        registeredClientsAsync.remove(client);

        return registeredClientsMainThread.add(client);
    }

    /**
     * Register this client to receive callback events from this service. Callback methods will be
     * executed asynchronously on separate threads.
     *
     * @param client the client to register, not null
     * @return true if the client is unregistered or has been
     * registered to receive callbacks in the service's main thread using {@link
     * #registerClientForCallbacks(ClientCallbacks) registerClientForCallbacks}, false
     * otherwise
     */
    public boolean registerClientForAsyncCallbacks(@NonNull ClientCallbacks client) {
        if (client == null) {
            throw new IllegalArgumentException("client cannot be null");
        }

        // Attempt to remove from async callbacks set (may do nothing)
        registeredClientsMainThread.remove(client);

        return registeredClientsAsync.add(client);
    }

    /**
     * Calls the {@link #ClientCallbacks ClientCallbacks} callback methods in all registered
     * clients. Clients registered for asynchronous callbacks will execute immediately, and
     * clients registered for sequential callbacks will be called in turn. Note that if the
     * callback methods block, then the service's main thread will block.
     */
    private void callAllRegisteredClients() {
        // First start asynchronous callbacks
        for (ClientCallbacks client : registeredClientsAsync) {
            Thread t = new Thread(new CallbackRunnable(client), client.toString());
            t.run();
        }

        // Finally start sequential callbacks
        for (ClientCallbacks client : registeredClientsMainThread) {
            client.onServiceEvent(this);
        }
    }

    /**
     * Interface allows callback events to be delivered to registered server clients.
     */
    public interface ClientCallbacks {
        public void onServiceEvent(Service service);
    }

    /**
     * A utility class which allows client callback methods to be executed asynchronously.
     */
    private class CallbackRunnable implements Runnable {
        /**
         * The client to receive the callbacks.
         */
        private final ClientCallbacks client;

        /**
         * Creates a new CallbackRunnable.
         * @param client the client to receive the callback methods, not null
         */
        private CallbackRunnable(@NonNull ClientCallbacks client) {
            if (client == null) {
                throw new IllegalArgumentException("client cannot be null");
            }

            this.client = client;
        }

        @Override
        public void run() {
            android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
            client.onServiceEvent(ExampleService.this);
        }
    }

    /*
     * Testing
     * TODO remove
     */
    public void activateCallbacks() {
        callAllRegisteredClients();
    }
}

【问题讨论】:

  • 你为什么在线程上调用run()而不是start()?

标签: java android multithreading


【解决方案1】:

您必须使用t.start() 而不是t.run()。

t.run() 直接调用你的runnable 的run() 方法。 t.start() 启动一个新线程,然后调用run() 方法。

另外,您应该考虑使用Executor,而不是直接创建和启动线程...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 1970-01-01
    • 1970-01-01
    • 2016-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多