android - Android上的任务队列就像iOS上的GCD一样?

标签 android ios multithreading grand-central-dispatch

Android 上是否有任务队列之类的东西?我知道它可以手工编写,但有现成的库吗?

最佳答案

我不确定是否会有这个库,因为 Android 已经为您想要实现的目标提供了高级构建 block 。

处理程序

如果我对您的理解正确,您希望将任何线程的任务发布到队列中并在专用线程上一个接一个地执行。这就是Android Handler是为了。

Handler、Looper、MessageQueue的关键特性

  • 处理程序绑定(bind)到单个 Looper .
  • 每个 Looper 都有一个关联的 MessageQueue
  • Handler 使用下面的 Looper 以线程安全的方式将消息入队和出队到 LooperMessageQueue
  • 处理程序对象本质上是线程安全的,因此可以安全地传递给其他线程。
  • 您可以将多个 Handler 对象绑定(bind)到同一个 Looper。如果您想使用不同的处理程序处理不同类型的消息,这将很有用。在这种情况下,您可以保证只有一个处理程序将处理给定 Looper 的 Message/Runnable。 Looper 负责将 Message 分派(dispatch)给正确的 Handler
  • 如果您已经熟悉用于在 2 个线程之间进行通信的消息队列范例(或类似 golang 的缓冲 channel 模式),那么 Handler 只是一个高级别的让您轻松使用此模式的类。

使用 Handler 发送/接收消息,发布 Runnables 的示例

// BEGIN One-time Initialization
// Create a Handler thread
// This provides the looper for the Message Queue and
// will be processing all your messages (i.e. tasks).
handlerThread = new HandlerThread("SomeThreadName");

// Start the Handler Thread
// The thread will block (using the looper) until it
// receives a new message
handlerThread.start();

// Create a Message Handler which you can use to
// post and process messages
// The same Handler can also be used to post a Runnable which will get
// executed on handlerThread
handler = new CustomHandler(mHandlerThread.getLooper());
// END One-time Initialization

// Different ways to post a message to the Handler Thread
// These calls are thread-safe, can be called safely and
// concurrently from multiple threads without race conditions
handler.sendEmptyMessage(MESSAGE_ID_1);
handler.sendEmptyMessage(MESSAGE_ID_2);
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_3, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_4, value, obj1));
handler.sendMessage(handler.obtainMessage(MESSAGE_ID_5, value1, valu2, obj1));

// Post a runnable on the Handler Thread
// This is thread-safe as well
// In fact all methods on the Handler class are thread-safe
handler.post(new Runnable() {
    @Override
    public void run() {
        // Code to run on the Handler thread
    }
});

// A skeleton implementation for CustomHandler
// NOTE: You can use the Handler class as-is without sub-classing it, if you
// intend to post just Runnables and NOT any messages
public class CustomHandler extends Handler {
    public CustomHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message message) {
        if (message != null) {
            // Process the message
            // The result can be sent back to the caller using a callback
            // or alternatively, the caller could have passed a Handler
            // argument, which the Handler Thread can post a message to

            switch (message.what) {
                case MESSAGE_ID_1:
                    // Some logic here
                    break;
                case MESSAGE_ID_2:
                    // Some logic here
                    break;
                case MESSAGE_ID_3:
                    // Some logic here
                    break;
                case MESSAGE_ID_4:
                    // Some logic here
                    break;
                case MESSAGE_ID_5:
                    // Some logic here
                    break;
                // Add more message types here as required
            }
        }
    }
}

// After you're done processing all messages and you
// want to exit the Handler Thread
// This will ensure that the queue does not accept any
// new messages, and all enqueued messages do get processed
handlerThread.quitSafely();

与上述示例的偏差

  • 虽然我在上面的例子中使用了HandlerThread,但并不是必须使用它。您甚至可以直接使用 Looper 调用,即 Looper.prepare()Looper.loop() 在线程。
  • 正如评论中已经提到的,如果您不打算处理任何消息,则无需对股票 Handler 进行子类化。
  • 您可以通过为每个需要接收消息的线程使用 Handler 轻松地在多个线程之间进行通信。
  • Handler 中有一些方法可以安排 future 的消息传递和 Runnable 执行。

Android 框架在内部广泛使用 Handler 来管理组件生命周期事件(onPauseonResume 等)。

异步任务

AsyncTask是在不同线程上调度任务的另一种选择。 .我不会详细介绍它的实现,因为 Android 开发者文档已经详细描述了它。

我通常将 AsyncTasks 用于我知道我会长时间使用后台线程的任务(至少 >= 100 毫秒)。我能想到的属于这一类的一些例子是 Binder IPC、RPC 调用、网络调用、后台下载等。

另一方面,Handler 更适合专注于尽快处理更多消息的情况。换句话说,避免在 handleMessage() 中执行任何阻塞操作。您可以使用 Handler 轻松编写无锁代码,它为您管理入队和出队消息时的所有锁定。

事实上,AsyncTask 可以与 Handler 结合使用,方法是将工作分成一个快速部分(由 Handler 负责)和一个慢速部分(由 AsyncTask 处理)。

PS:虽然与问题无关,但如果您对消息队列范式感兴趣;看看LMAX Disruptor ,这是一个高性能的线程间消息队列库。他们的设计文档很好地解释了消息队列的哪些部分需要锁定/原子访问。

关于android - Android上的任务队列就像iOS上的GCD一样?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6623266/

相关文章:

android - 每次方向改变后都会重新创建 fragment ,无法恢复状态

android - lateinit 属性适配器尚未在 Kotlin4Android 中初始化

iOS 获得不同于编程的其他颜色

javascript - 在单页 pushState Web 应用程序中模拟画外音页面加载

multithreading - MongoDB 线程安全吗?

android - Html5 应用程序与 Android 或 iphone 应用程序速度比较

android - 是否可以使用没有阴影的 OverlayItem.setMarker()?

iOS - 滚动 Collection View 到热门问题

python - Python:同时执行多个无限循环

在本地资源上同步期间的 Java 死锁?