Handler、Runnable 和 Threads 之间有啥区别?

Posted

技术标签:

【中文标题】Handler、Runnable 和 Threads 之间有啥区别?【英文标题】:What is the different between Handler, Runnable, and Threads?Handler、Runnable 和 Threads 之间有什么区别? 【发布时间】:2014-02-07 07:21:34 【问题描述】:

Handler、Runnable、Threads有什么区别?

当我使用 android 时,我需要在后台运行一些东西。我使用线程来运行它。通常我会写一个扩展 Thread 的类并实现 run 方法。

我还看到了一些实现 runnable 并将 runnable 传递给 Threads 的示例。

但是我仍然很困惑。谁能给我一个明确的解释?

    如果可以在 Thread 的 run 方法中编写后台代码,那么 Runnable 的意义何在? Handler在线程内部是如何使用的,为什么我们需要使用它。 Android 有另一个叫 runOnUiThread 的东西,我们如何使用它?我知道它是用来更新 UI 的。

【问题讨论】:

我对 Handler 和 UniThread 了解不多,因此评论没有回答,但通常你只会制作 Runnable 实现。如果您想更改有关执行的某些内容,通常只会扩展线程 关于 Android 的细节我不能说太多,但您可以使用 Runnable,因为它为您安排正在运行的作业提供了更多的灵活性。直接使用Thread 意味着您无法使用一种特定的策略。 如果你能给我一些例子就太好了。 【参考方案1】:

为什么使用 Runnable over Thread?

Runnable 将需要异步运行的代码与如何代码运行分开。这使您的代码保持灵活。例如,runnable 中的异步代码可以在线程池或专用线程上运行。

Thread 声明您的可运行文件可能不需要访问。获得比必要更多的状态是糟糕的设计。

线程占用大量内存。为每个小动作创建一个新线程需要处理时间来分配和释放此内存。

runOnUiThread 实际上在做什么?

Android 的 runOnUiThread 将 Runnable 排队以在 UI 线程上执行。这很重要,因为您永远不应该从多个线程更新 UI。 runOnUiThread 使用 Handler

请注意,如果 UI 线程的队列已满,或者需要执行的项目很长,那么您排队的 Runnable 可能需要一段时间才能真正运行。

什么是处理程序?

处理程序允许您发布可运行文件以在特定线程上执行。在幕后,runOnUi 线程使用 Android 的 Ui 处理程序将您的 Runnable 排队,以便您的可运行对象可以在 UI 线程上安全地执行。

【讨论】:

【参考方案2】:

1.为什么是可运行的?

Runnable 只是一个接口,你需要实例化一个线程来包含它。而线程已经包含产生线程的能力。如果扩展线程,则不能扩展其他任何东西(Java 不支持多重继承)。你可以在一个类上有多个接口,因此你可以有 Runnable。

此外,当您扩展 Thread 类时,您的每个线程都会创建唯一的对象并与之关联。当您实现 Runnable 时,它​​会将同一个对象共享给多个线程。

2。为什么要使用处理程序,它是什么?

Handler 是用 Java 编写的(内部使用一个 Thread),所以你可以用 Handler 做的所有事情,你也可以使用 Thread 来实现。

那么为什么要使用 Handler?原因如下

Handler 允许您发送和处理 Message 和 Runnable 对象 与线程的 MessageQueue 相关联。简单来说, 处理程序使您的工作变得轻松。

Android 有两个处理线程的主要规则:

不要阻塞 UI 线程

不要从 UI 线程外部访问 Android UI 工具包

要按照上述 2 条规则进行绑定,在 android 中,我们有 3 个内置方法可以处理当您的 Activity 类之一在不同线程上运行或从不同线程调用时的情况。

然后,我们可以使用以下这三种方法安排 UI 更新在 UI 线程上运行。 Activity 或 View 然后作为一个处理程序工作(更多关于下面的处理程序)并将您的可运行安排到 UI 线程:

    Activity.runOnUiThread(可运行)
      View.post(Runnable) View.postDelayed(Runnable, long) //(long = 调度时间)

3.什么是 UI 线程?

UI 线程是渲染 UI 元素(如 View 和 Activity)的主线程。 UI 线程中不应发生任何耗时的操作。应用程序默认在 UI 线程中运行。您无需执行任何特殊操作即可使用 UI 线程。

【讨论】:

【参考方案3】:

Handler、Runnable和Threads实际上是一起工作的,我认为你不应该比较它们。

处理程序

允许在两个线程之间以安全的方式发送消息,即发送线程将消息放入目的线程队列,目的队列会在适当的时间处理该消息。

可运行

这是您实现的接口,在实现中您将要执行的逻辑放在某个线程上。您实际上也可以在非线程相关的地方使用 Runnable。许多 Java api 实际上都使用 Runnable,而不仅仅是 Thread 的。您可以使用处理程序发布 Runnable,也可以将其与执行程序一起使用。 Runnables 很好,因为您可以以匿名实现的形式实现它们。

单线程

您的意思是 UI 线程?大多数用户界面在单线程中实现其工作,所有 UI 元素:窗口/小部件使用消息进行通信(就像在 Handler 中一样)。 IE。用户按下按钮,这会启动一条消息,其中包含按下按钮的信息,它被发送到 UI 线程并最终传递给您的侦听器。

在 Android 中,禁止(导致异常)从非 UI 线程修改 UI 元素,这是有道理的 - 如果您要从其他线程修改它,这可能会在 UI 线程对同一个小部件进行一些更改时发生 - 导致在未定义的行为中。

【讨论】:

我看到 Thread 类实现了 Runnable 接口。我的理解是可运行与并发无关。线程是完成这项工作的。 Runnable 只是可以放在代码上的东西,因此它可以使用线程运行。我说的对吗? 正确,但是Thread在android中是一个相当底层的概念,因为android组件(即activity)的生命周期相当复杂,你应该使用AsyncTask,Loaders,IntentService-s,...跨度> 线程也占用大量内存。它们的创建和收集成本很高。【参考方案4】:

我使用线程来运行它。通常我会写一个扩展 Thread 的类并实现 run 方法。

1.如果可以在Thread的run方法中编写后台代码,那么Runnable有什么意义?

使用 Runnable 并从 Runnable 创建线程是一般做法。

来自concurrency 上关于RunnableThread 用法的oracle 教程:

Runnable 对象,更通用,因为 Runnable 对象可以继承 Thread 以外的类。

2.Handler在线程内部是如何使用的,为什么要使用它。

这是一个需要解释的庞大话题。用官方文档网站的简单术语:

    Handler 允许您发送和处理与线程的MessageQueue 关联的MessageRunnable 对象。每个Handler 实例都与一个线程和该线程的消息队列相关联。

    当您创建一个新的Handler 时,它会绑定到创建它的线程的线程/消息队列——从那时起,它将向该消息队列传递消息和可运行文件并执行当它们从消息队列中出来时。

    Handler 有两个主要用途:(1) 安排消息和可运行对象在未来某个时间点执行; (2) 将要在与您自己的线程不同的线程上执行的操作排入队列

    当为您的应用程序创建一个进程时,它的主线程专用于运行一个消息队列,该队列负责管理***应用程序对象(活动、广播接收器等)以及它们创建的任何窗口。 您可以创建自己的线程,并通过 Handler 与主应用程序线程进行通信。 这可以通过调用与以前相同的 post 或 sendMessage 方法来完成,但是从你的新线程。然后将给定的Runnable 或 Message 安排在 Handler 的消息队列中并在适当的时候进行处理。

这张来自blog.mindorks.com Anishar Ali 文章的图片清楚地解释了概念。

3.Android还有一个叫runOnUiThread的东西,我们怎么用呢?我知道它是用来更新 UI 的。

您可以通过查看runOnUiThread 的实现来找到更多详细信息

/**
     * Runs the specified action on the UI thread. If the current thread is the UI
     * thread, then the action is executed immediately. If the current thread is
     * not the UI thread, the action is posted to the event queue of the UI thread.
     *
     * @param action the action to run on the UI thread
     */
    public final void runOnUiThread(Runnable action) 
        if (Thread.currentThread() != mUiThread) 
            mHandler.post(action);
         else 
            action.run();
        
    

Handler 用法的示例代码请参阅下面的帖子。

Android: Toast in a thread

【讨论】:

【参考方案5】:

如果可以写后台代码,那么 Runnable 有什么意义呢? Thread的run方法?

Runnable是一个用于创建新线程类的接口,类似于扩展java.lang.Thread类创建的线程类。唯一不同的是,Runnable 接口允许类扩展其他类(如果需要)以覆盖/继承某些类的功能。扩展 java.lang.Thread 类将撤销此功能。

另外,Runnable 接口代表一个可以通过普通线程或执行器或任何其他方式执行的任务。因此,将 Task 逻辑分离为 Runnable 而不是 Thread 是一个很好的设计决策。

阅读更多:http://javarevisited.blogspot.com/2012/01/difference-thread-vs-runnable-interface.html#ixzz2qgjDYJhT

【讨论】:

【参考方案6】:

Runnable 接口是 Thread 类的父类,run() 是 Runnable 接口的方法 所以通常我们应该更喜欢 Runnable 接口而不是扩展线程类,因为我们不想改变类的行为,我们也可以扩展另一个类。它也有助于实现松散耦合,并且我们有改变用户界面的好处从任何其他班级。

我们可以通过 4 种方式更改 Ui

1.使用Handler示例

public class MainActivity extends AppCompatActivity     
private Handler mainHandler=new Handler();
class ExampleRunnable implements Runnable 
        int seconds;

        public ExampleRunnable(int seconds) 
            this.seconds = seconds;
        

        @Override
        public void run() 
            for (int i = 0; i < seconds; i++) 
 mainHandler.post(new Runnable() 
                        @Override
                        public void run() 
                        button.setText("50% process completed");
                        
                    );

2.通过使用runOnUIThread(),我们必须将runOnUIThread附加到帖子中,通过示例可以很容易理解

class ExampleRunnable implements Runnable 
        int seconds;



 public ExampleRunnable(int seconds) 
        this.seconds = seconds;
    

    @Override
    public void run() runOnUIThread.post(new Runnable() 
                    @Override
                    public void run() 
                        button.setText(" Runnable");
                    
                );
            

3.通过使用我们可以通过任何视图调用的任何视图,我在这里用 switch 调用过

public class MainActivity extends AppCompatActivity 
 private Switch aSwitch;
@Override
    protected void onCreate(Bundle savedInstanceState) 
 aSwitch=findViewById(R.id.switch1);
class ExampleRunnable implements Runnable 
            int seconds;



     public ExampleRunnable(int seconds) 
            this.seconds = seconds;
        

        @Override
        public void run()  aSwitch.post(new Runnable() 
                        @Override
                        public void run() 
                            button.setText(" Runnable");
                        
                    );
                

4.通过在另一个线程中创建 Handler,我们必须定义 Looper,因为默认情况下它会将我们附加到我们的线程 Looper

Handler threadHandler=new Handler(Looper.getMainLooper());
threadHandler.post(new Runnable()

                            @Override
                            public void run() 
                                button.setText(" Runnable");
                            
                        );
                    

这是 4 种实现方式,所以我认为您现在可能会了解可运行线程和 runOnUIThread() 以及 Handler 是由其他人编写的精美。

【讨论】:

以上是关于Handler、Runnable 和 Threads 之间有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

Android 中三种启用线程的方法

Handler,MessageQueue,Runnable与Looper

ThreadHandler与HandlerThreadHandler使用

如何使用android延迟不扩展或实现Thread或Runnable

Java多线程小结

如何使用Handler