创建和使用匿名 Runnable 类的最佳方式

Posted

技术标签:

【中文标题】创建和使用匿名 Runnable 类的最佳方式【英文标题】:Best way of creating and using an anonymous Runnable class 【发布时间】:2012-09-28 02:24:18 【问题描述】:

我想为Runnable 使用匿名类。有两种方法,但我不知道他们是否做同样的事情:

方法一:直接使用Runnable,然后调用run()

new Runnable() 
    @Override
    public void run() 
    
.run();

方法二:创建匿名Runnable并粘贴到Thread,使用start()方法代替run()

new Thread(new Runnable() 
    @Override
    public void run() 
    
).start();

我认为方法二显然是正确的。但是,我不知道它是否与方法一做同样的事情。我们可以直接在Runnable 上调用run() 方法吗?

【问题讨论】:

【参考方案1】:

不,您通常不会直接在 Runnable 上调用 run(),因为这样您不会获得后台线程。如果您不想要并且需要后台线程,则可以直接调用run(),否则如果您想创建后台线程并从其中运行 Runnable,则必须创建一个新线程,然后传入 Runnable进入其构造函数,并调用start()

此外,还有其他方法可以完成此任务,包括使用 Executors 和 ExecutorServices,您应该研究一下它的用途,因为它们比使用简单的 Thread 对象提供更多的灵活性和功能。

您还想看看Future 接口和FutureTasks 类的使用,它们与Runnables 类似,只是它们允许您在完成时返回结果。如果您使用过 SwingWorker,那么您已经在不知不觉中使用了 Future 接口。

【讨论】:

【参考方案2】:

正如其他人所提到的,使用 Thread 类是正确的方法。但是,您还应该考虑使用 Javas Executors 框架来处理正在运行的线程。

Executors.newSingleThreadExecutor().execute(new Runnable() 
    @Override 
    public void run() 
        // code in here
    
);

当然,直接使用 Thread 就可以了。但通常建议(或首选)使用该框架。让 Java 为您处理细节。

【讨论】:

在这种情况下,有没有办法可以将参数传递给 run() 方法? @kenshinji 不,没有,您必须在实现 Runnable 的类的构造函数中传递这些参数。【参考方案3】:

Runnable 接口必须在Thread 内执行。如果您想找到另一种内联包装的方法,即Thread 中的一段代码,请尝试:

Thread t = new Thread()

     public void run()
     
        // put whatever code you want to run inside the thread here.
     
;

t.start();

【讨论】:

【参考方案4】:

我想在这个讨论中添加一些东西(你已经得到了很好的答案)。 如果您的 Runnable 对象是无状态的,为了减少内存分配(这需要时间 + 消耗一些内存 - 考虑一个应用程序大量使用线程的情况) - 请考虑使用一个静态字段来保存可运行对象。

private static Runnable runnable = new Runnable()  //Once again - do this only if this is a statelss object!
   public void run() 
   
 

//Use the runnable somewhere in the code

【讨论】:

【参考方案5】:

在方法一中,它就像一个方法一样作为 Runnable 接口实现和调用它,但不会创建后台线程。 事实上,当我们调用 start 方法时,它会导致相应的线程开始执行,Java 虚拟机在内部调用该线程的 run 方法。所以要启动一个线程,我们需要使用接口 Runnable referencence 调用 start 方法。 在方法一中,即使我们不能调用带有 Runnable 接口引用的 start 方法,因为 Runnable 接口不支持 start() 方法。因此必须创建 Thread 类的对象来启动线程执行。

【讨论】:

【参考方案6】:

永远记住,Runnable 只是您想要或能够在线程中运行的代码。一种匿名定义 Runnable 代码的方法是:

  Runnable codeToRunOnThread=new Runnable() 
      @Override
      public void run() 
      //code to run in a thread you want
      
  ;

然后你可以创建一个线程并将你创建的 Runnable 传递给这个新线程

  Thread myThread=new Thread(codeToRunOnThread);
  myThread.start();

调用 Thread 类的 start() 方法后,run() 方法内部的代码在新创建的线程上运行。

您还可以查看创建 Runnable 对象的不同方式 here

【讨论】:

【参考方案7】:

这可以通过 lambda 表达式来完成:

Runnable myRunnable = () -> 
    //code you want to execute
;

【讨论】:

不错。从 Java 8 及更高版本开始支持此功能。【参考方案8】:

第一种方法是错误的:它没有创建新线程,所以没用。

这就像将代码放在可运行文件之外。

请注意,有两种方法可以在匿名类 as described in Thread's javadoc 中定义的代码上启动新线程,但您的 方法 1 不在其中,您的方法 2 是您通常应该首选的方法。

【讨论】:

【参考方案9】:

正如@Hovercraft 所述,如果您直接调用Runnable.run() 方法,则根本不会创建Thread。就像调用任何其他方法一样(System.out.println(...),...)。

当您将Runnable 对象传递给Thread 构造函数时,会将Thread 中的target 字段设置为您的对象:

this.target = target;

然后,当您在Thread 上调用start() 时,这会分叉新线程并调用Thread.run() 方法。 Thread.run()依次调用目标的run()方法:

public void run() 
    if (target != null) 
        target.run();
    

因此,将Runnable 传递给Thread,然后调用start() 是在后台单独线程中运行Runnable 的方法。

【讨论】:

【参考方案10】:

你的方法1通常不能做任何有用的工作。使用此方法,如果您想获得简单 HelloWorld.java 程序的输出,即“Hello World”,它将类似于以下无用代码,但它会打印“Hello World”。所以你应该使用你的第二种方法。无用代码:

class MyRunnable implements Runnable 

    public void run()  
    System.out.println("Hello World");
    

    public static void main(String[]arg) 
    MyRunnable myRunnable = new NamedRunnable( );
    namedRunnable.run();
     

【讨论】:

【参考方案11】:

这是一个简单的代码示例,说明如何正确创建匿名 Runnable 类并处理内存泄漏(android 示例):

public class MainActivity extends Activity
@Override
protected void onCreate(Bundle savedInstanceState) 

            MyRunnable myRunnable = new MyRunnable(this);
            myHandler.postDelayed(myRunnable, TimeUnits);


// Must be declared as a static class    
private static class MyRunnable implements Runnable 
        WeakReference<MainActivity> mActivity;
        // Creating weakreference
        MyRunnable(MainActivity activity) 
            mActivity = new WeakReference<>(activity);
        

        @Override
        public void run() 
            MainActivity activity = mActivity.get();
            // Checking reference exist or not
            if (activity != null) 
                    //Do necessary tasks
                
            
        
    


【讨论】:

以上是关于创建和使用匿名 Runnable 类的最佳方式的主要内容,如果未能解决你的问题,请参考以下文章

初识多线程

初识多线程

Java 创建线程

JAVA的Thread类的构造方法

Java中接口式的匿名内部类的构造方法

多线程知识