【问题标题】:new Runnable() but no new thread?new Runnable() 但没有新线程?
【发布时间】:2012-02-20 05:39:22
【问题描述】:

我正在尝试理解代码 here ,特别是匿名类

private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
   final long start = mStartTime;
   long millis = SystemClock.uptimeMillis() - start;
   int seconds = (int) (millis / 1000);
   int minutes = seconds / 60;
   seconds     = seconds % 60;

   if (seconds < 10) {
       mTimeLabel.setText("" + minutes + ":0" + seconds);
   } else {
       mTimeLabel.setText("" + minutes + ":" + seconds);            
   }

   mHandler.postAtTime(this,
           start + (((minutes * 60) + seconds + 1) * 1000));
   }
};

文章说

处理程序将更新代码作为主线程的一部分运行,避免了第二个线程的开销..

不应该创建一个新的 Runnable 类来创建一个新的第二个线程吗?除了能够将 Runnable 类传递给 postAtTime 之外,这里 Runnable 类的目的是什么?

谢谢

【问题讨论】:

标签: java android multithreading runnable


【解决方案1】:

Runnable 通常用于提供线程应该运行的代码,但Runnable 本身与线程无关。它只是一个带有run() 方法的对象。

在 Android 中,Handler 类可用于要求框架稍后在相同线程上运行一些代码,而不是在不同线程上运行。 Runnable 用于提供稍后应该运行的代码。

【讨论】:

  • “Runnable 本身与线程无关”这在概念上是错误的!请阅读文档。 Runnable 接口应该由其实例打算由线程执行的任何类实现。传递 Runnable 时也会令人困惑,但事情发生在同一个线程中。请阅读“最小意外原则”。
  • @glaz666,Runnable 文档讨论了线程,因为它们是Runnable常见的用法,但该接口适用于任何类型的回调。我认为 Android HandlerRunnable 的使用是完全合理的——这比定义一个与 Runnable 相同但名称不同的新的 Android 特定接口要好。
  • 一个没有“extends Thread”也没有“implements Runnable”的“new Runnable()”示例:docs.oracle.com/javase/tutorial/uiswing/examples/start/…
  • @glaz666,我从不喜欢 Runnable 的 javadoc 中的措辞(您之前引用的),显然 Java 人员同意它太狭窄了。请注意他们如何改进 Callable 的 javadoc 中的相同措辞:“Callable 接口类似于 Runnable,因为两者都是为实例可能由另一个线程执行的类而设计的。”
【解决方案2】:

如果你想创建一个新的Thread...你可以这样做...

Thread t = new Thread(new Runnable() { public void run() { 
  // your code goes here... 
}});

【讨论】:

  • 不是 OP 要求的。
【解决方案3】:

Runnable 接口是实现多线程的另一种方式,而不是扩展 Thread 类,因为 Java 只允许扩展一个类。

但是,您可以使用 new Thread(Runnable runnable) 构造函数,如下所示:

private Thread thread = new Thread(new Runnable() {
public void run() {
   final long start = mStartTime;
   long millis = SystemClock.uptimeMillis() - start;
   int seconds = (int) (millis / 1000);
   int minutes = seconds / 60;
   seconds     = seconds % 60;

   if (seconds < 10) {
       mTimeLabel.setText("" + minutes + ":0" + seconds);
   } else {
       mTimeLabel.setText("" + minutes + ":" + seconds);            
   }

   mHandler.postAtTime(this,
           start + (((minutes * 60) + seconds + 1) * 1000));
   }
});

thread.start();

【讨论】:

  • 所以这个例子是否创建一个新线程,因为你使用了线程但没有调用 start()..
  • @shishirgarg:这个例子创建了一个新的 Thread 对象。要执行它,只需像这样调用start() 方法:thread.start()。这应该在内部调用run() 方法(注意,你永远不应该自己调用run() 方法)这会启动线程。
【解决方案4】:

你可以像这样创建一个线程:

 Thread thread = new Thread(new Runnable() {
                    public void run() {

                       }
                    });
                thread.start();

另外,您可以使用 Runnable、Asyntask、Timer、TimerTaks 和 AlarmManager 来执行线程。

【讨论】:

  • 你可以重写 Thread 的 run() 方法。创建 Runnable 有什么好处?
【解决方案5】:

Runnable 只是一个接口,它提供了方法run。 线程是实现,使用 Runnable 调用方法 run()。

【讨论】:

    【解决方案6】:

    不应该创建一个新的 Runnable 类来创建一个新的第二个线程吗?

    没有。新的Runnable 不会创建第二个Thread

    除了能够将 Runnable 类传递给 postAtTime 之外,这里 Runnable 类的目的是什么?

    Runnable 发布到 Handler。该任务在与Handler关联的线程中运行。

    如果 Handler 与 UI Thread 关联,Runnable 在 UI Thread 中运行。

    如果Handler 与其他HandlerThread 关联,则Runnable 在HandlerThread 中运行


    要将 Handler 显式关联到您的 MainThread(UI 线程),请编写以下代码。

    Handler  mHandler = new Handler(Looper.getMainLooper();
    

    如果你写如下,它使用HandlerThread Looper。

    HandlerThread handlerThread = new HandlerThread("HandlerThread");
    handlerThread.start();
    Handler requestHandler = new Handler(handlerThread.getLooper());
    

    【讨论】:

      【解决方案7】:

      最好和最简单的方法就是传递参数并创建实例并调用 线程方法

      调用线程使用创建线程对象并发送带参数或不带参数的可运行类对象和线程对象的启动方法。

      在我的情况下,我正在发送参数,我将在运行方法中使用。

      new Thread(new FCMThreadController("2", null, "3", "1")).start();

      新线程(new FCMThreadController()).start();

      public class FCMThreadController implements Runnable {
      private String type;
      private List<UserDeviceModel> devices;
      private String message;
      private String id;
      
      
          public FCMThreadController(String type, List<UserDeviceModel> devices, String message, String id) {
      
              this.type = type;
              this.devices = devices;
              this.message = message;
              this.id = id;
          }
      
      
      
          public FCMThreadController( ) {
      
          }
      
          @Override
          public void run() {
              // TODO Auto-generated method stub
      
          }
      
      
      
      }
      

      【讨论】:

        【解决方案8】:

        线程类似于某个分支。多分支意味着至少有两个分支。如果分支减少,则最小值保持为 1。这个虽然像是去掉了分支,但一般我们不认为它是分支。

        类似地,当至少有两个线程时,我们称之为多线程程序。如果减少线程,则最小值保持为 1。 Hello 程序是一个单线程程序,但没有人需要知道多线程来编写或运行它。

        简单来说,当一个程序没有线程时,这意味着该程序不是一个多线程程序,更确切地说它是一个单线程程序,你可以把你的代码作为如果它是多线程的。

        下面给出了一个无用的代码,但足以消除您对Runnable 的一些困惑。它将打印“Hello World”。

        class NamedRunnable implements Runnable {
        
            public void run() { // The run method prints a message to standard output.
                System.out.println("Hello World");
            }
        
            public static void main(String[]arg){ 
                NamedRunnable namedRunnable = new NamedRunnable( );
                namedRunnable.run();
            } 
        }
        

        【讨论】:

          猜你喜欢
          • 2018-03-02
          • 2019-06-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-10-27
          • 1970-01-01
          • 2015-09-20
          相关资源
          最近更新 更多