android - Android 中 SingleThreadExecutor 和 Handler 的区别(举例)

标签 android multithreading executorservice

我正在研究一本教科书示例,介绍如何使用 Android 中的 Room 将数据写入 SQlite 数据库。显然,我们无法从主线程将数据写入数据库,但为此我们需要一个后台线程。在我的书中,我们所做的是,我们创建一个额外的类 AppExecutors ,其中包含以下内容:

public class AppExecutors {
    private final Executor _diskIO;
    private final Executor _networkIO;
    private final Executor _mainThread;

    private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
        _diskIO = diskIO;
        _networkIO = networkIO;
        _mainThread = mainThread;
    }

    public AppExecutors() {
        this(Executors.newSingleThreadExecutor(),
                Executors.newFixedThreadPool(3),
                new MainThreadExecutor());
    }

    public Executor diskIO() {
        return _diskIO;
    }


public Executor networkIO() {
        return _networkIO;
    }

    public Executor mainThread() {
        return _mainThread;
    }

    private static class MainThreadExecutor implements Executor {
        private Handler mainThreadHandler = new Handler(Looper.getMainLooper());

        @Override
        public void execute(Runnable command) {
            mainThreadHandler.post(command);
        }
    }
}

然后,在 MainActivity 中(也包含 UI,即按钮,单击时会触发操作),我们调用

getApp().getExecutors().diskIO().execute(() -> {
    ...
}

其中 getApp().getExecutors() 返回 AppExecutors 的新实例。

这是我的问题:

我确实明白 getApp().getExecutors().mainThread().execute(() -> {...} 传递了一个新的 Runnable 并将此 Runnable 赋予了消息队列主线程的循环。循环器将每个线程从消息队列中取出并执行它。

但是,getApp().getExecutors().diskIO().execute(() -> {...} 的情况有所不同。 传递给它的 Runnable 显然是在后台线程中执行的。 Executors.newSingleThreadExecutor() 似乎正在打开一个新线程。但没有与该线程关联的处理程序或消息队列。所以我就想,这个线程执行完之后不是会被关闭吗?一旦线程关闭,我们就无法再次打开同一个线程。这让我有点困惑,线程不应该保持打开状态吗? 我现在已经阅读了 ExecutorService ,显然这个服务只是让线程保持打开状态。但话又说回来,这不是 messageque 和 handler 正在做的事情吗?那么这有什么不同呢?

最佳答案

我认为this answer将部分回答你的问题。另外对于你的问题:

So, I was wondering, won't this thread be closed after execution? Once the thread is closed, we cannot open the same thread again. And that's a bit confusing for me, shouldn't the thread stay open?

不,不会。该执行器服务的线程将处于空闲或阻塞状态,直到您将新的可运行对象放入队列,因为它使用了 BlockingQueue。如果队列为空,该线程将被阻塞;如果 Runnale 对象到达其队列,该线程将被激活。正如您所看到的,ExecutorService 没有 Looper。仅当您调用 ExecutorService 的 shutdown() 或 shutdownNow() 方法时,它才会被销毁。

But then again, isn't this the same thing that the messageque and the handler are doing? So how is this different?

相比之下,Handler 需要绑定(bind)到 Looper 才能发送消息和发布 Runnables,Looper 存在于 HandlerThread 中。一个HandlerThread对应一个单线程执行器服务,其Handler对应一个Executor。在 AppExecutors 类中,Handler 与主线程的 Looper 绑定(bind),因为 UI 对象无法从创建它的主线程以外的线程中触及。

让我们看看示例 Java 代码中的差异。 使用 ExecutorService 的后台线程示例。

/*
To create a background thread making use of the Java concurrent API first we
need to create an ExecutorService or only Executor if you don't want to manage
the service. But generally it must be shutdown when we are done with it.
That's why we need a reference to the ExecutorService in orderto shutdown it.
*/
ExecutorService executorService = Executors.newSingleThreadExecutor();
Executor executor = executorService;

// To send a command:
executor.execute(someRunnable);
// As you can see an executor has only the execute method.

// After we are done with executor service we must shutdown it.
executorService.shutdown();
// or
executorService.shutdownNow();
// This returns a list of runnables that were in the queue.

使用 HandlerThread 的后台线程示例:

/*
To create a background thread which has a message queue we have to make
use of the Android's HandlerThread and Handler API. A HandlerThread object
manages a Looper and a Thread in it while A Handler object is used to send
commands or messages to a living HandlerThread object.
*/
// A HandlerThread can also be instantiated with a name and a priority.
HandlerThread handlerThread = new HandlerThread();
handlerThread.start(); // Must call start in contras to an ExecutorService

// Tie this handler to the handlerThread's Looper so that we can send
// commands or messages to its queue.
Handler handler = new Handler(handlerThread.getLooper());

// To send a command
handler.post(someRunnable); // or
handler.postDelayed(someRunnable, delayInMillis); // or
handler.postAtFrontOfQueue(someRunnable); // or
handler.postAtTime(someRunnable, upTimeInMillis);

Handler API 只是 Android 特定的 API,并且有许多实用程序来发送和处理 Message 对象和 Runnable 命令。请参阅Handler API 获取更多信息。

关于android - Android 中 SingleThreadExecutor 和 Handler 的区别(举例),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68520927/

相关文章:

android - 如何在 Android 中正确使用 React Native 中的仅限 iOS 的组件而不会出错

c++ - 使用 pThreads,是否可以编写一个函数来检测从哪个线程调用它?

java - 本地运行的 DynamoDb 的默认预配置吞吐量(读取和写入容量单位)是多少?

java - 如果您将一个可运行对象提交给具有多个线程的执行程序服务,多个线程是否会执行该可运行对象?

Java ExecutorService - 创建一个新线程但不启动它

android - 仅显示操作栏的下半部分(并且在状态栏后面)

android - 将监听器添加到可扩展列表项中的子节点

java - 我的 Android 模拟器显示模拟器错误

java - 如何使用 Hazelcast 制作多线程应用程序

c++ - 在新线程中调用 OpenCV 函数 Canny() 会导致段错误