android中singlethreadexecutor和处理程序之间的区别(通过示例)

xxhby3vn  于 2021-09-13  发布在  Java
关注(0)|答案(2)|浏览(258)

我正在通过一本教科书的例子学习如何在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中,我们调用

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

哪里 getApp().getExecutors() 返回的新示例 AppExecutors .
我的问题是:
我明白 getApp().getExecutors().mainThread().execute(() -> {...} 传递一个新的runnable,并将此runnable提供给主线程的messagequeue。循环器将每个线程从消息队列中取出并执行它。
然而,情况不同 getApp().getExecutors().diskIO().execute(() -> {...} . 传递给它的runnable显然是在后台线程中执行的。 Executors.newSingleThreadExecutor() 似乎打开了一条新的思路。但没有与此线程关联的处理程序或messagequeue。所以,我想知道,这个线程在执行后不会被关闭吗?一旦线程关闭,我们就不能再次打开同一个线程。这对我来说有点困惑,线不应该保持开放吗?我现在已经阅读了Executor服务,显然这个服务只是让线程保持打开状态。但话说回来,这不是messageque和处理程序正在做的事情吗?那么这有什么不同呢?

pn9klfpd

pn9klfpd1#

下面是一个修改appexecutors类的示例。您可以看到,我们没有使用单个线程执行器,而是使用了后台处理程序线程,我们创建了一个处理程序对象,然后将其绑定到handlerthread对象。此外,对于主线程执行,我们删除了 Package 器类并创建了另一个处理程序对象,然后将其绑定到主线程的循环器。我希望你一切都清楚

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

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

    public AppExecutors() {

        HandlerThread htDiskIO = new HandlerThread(
            "com.application.htDiskIO", // Give it a name (optional)
            Process.THREAD_PRIORITY_BACKGROUND
        );

        this( new Handler(htDiskIO.getLooper()),
              Executors.newFixedThreadPool(3),
              new Handler(Looper.getMainLooper()));
    }

    public Handler diskIO() {
        return _diskIO;
    }

    public Executor networkIO() {
        return _networkIO;
    }

    public Handler mainThread() {
        return _mainThread;
    }
}

以下是新appexecutors类的一些示例用法片段:

AppExecutors executors = new AppExecutors();

// Now for diskIO operations you must call like:
executors.diskIO().post(someRunnable);
executors.diskIO().postDelayed(someRunnable, someDelay);

// The network operation is same
executors.networkIO().execute(someRunnable);

// And last but not least; main thread operations
execute.mainThread().post(someRunnable);
execute.mainThread().postDelayed(someRunnable, someDelay);

还要注意的是,handlerthread和handler api属于google的android.os包。因此,您将无法在非为android操作系统编写的应用程序中使用它们。以上就是这个例子,祝你学业成功。

r6l8ljro

r6l8ljro2#

我认为这个答案将部分回答你的问题。另外,对于您的问题:
所以,我想知道,这个线程在执行后不会被关闭吗?一旦线程关闭,我们就不能再次打开同一个线程。这对我来说有点困惑,线不应该保持开放吗?
不,不会的。该executor服务的线程将处于空闲或阻塞状态,直到您将新的runnable排队,因为它使用blockingqueue。如果队列为空,线程将被阻塞,如果runnale对象到达其队列,线程将被激活。如您所见,executorservice没有活套。只有在调用executorservice的shutdown()或shutdownnow()方法时,它才会被销毁。
但话说回来,这不是messageque和处理程序正在做的事情吗?那么这有什么不同呢?
相反,处理程序需要绑定到循环器才能发送消息和发布可运行文件,而循环器则位于handlerthread中。handlerthread对应于单线程执行器服务,其处理程序对应于执行器。在appexecutors类中,处理程序绑定到主线程的循环器,因为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,它有许多用于发送和处理消息对象和可运行命令的实用程序。有关更多信息,请参阅处理程序api。

相关问题