简体   繁体   English

new Thread(Runnable object).start() 与 new Thread(Runnable ref. {run()});.start() 之间的区别

[英]DIfference between new Thread(Runnable object).start() vs. new Thread(Runnable ref. {run()});.start()

I am a newie in multithreading.我是多线程的新手。 I have following codes for two java program我有两个 java 程序的以下代码

public class Test implements Runnable {
    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("i am Thread-" +  Thread.currentThread().getName());
}
    }
    public static void main(String[] args) {
        Test t = new Test();
        new Thread(t).start();
       System.out.println("i am Thread-" +  Thread.currentThread().getName());
}}
---------------------------------------------
public class Test1 {
    public static void main(String[] args) {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.println("i am Thread-"+ Thread.currentThread().getName());
                }}});
        t1.start();
        System.out.println("i am Thread-"+ Thread.currentThread().getName());

        }}
--------------------------------------------

As both gives the same output.因为两者都给出了相同的 output。 Could someone please explain what is the actual difference between thsese two approaches.有人可以解释一下这两种方法之间的实际区别是什么。 Thankyou.谢谢你。

Named class, anonymous class, and lambda syntax命名为 class、匿名 class 和 lambda 语法

  • The first is an explicitly-named class.第一个是明确命名的 class。
  • The second is an anonymous class .第二个是匿名 class

No practical difference in your example code.您的示例代码没有实际区别。 Use whichever approach meets your needs and taste.使用满足您的需求和口味的任何方法。 Generally, if the class will be reused in various places, then using a named class makes sense.一般来说,如果 class 将在各个地方重复使用,那么使用命名 class 是有意义的。 If the class is brief and used in just one place, then the anonymous class approach may be better.如果 class 很简短并且只在一个地方使用,那么匿名 class 方法可能会更好。

As commented by Andreas , one big advantage of the anonymous class is that it can access any effectively final variables contained in its outer nesting method.正如Andreas 所评论的,匿名 class 的一大优势是它可以访问其外部嵌套方法中包含的任何有效的最终变量。 This can simplify your code by eliminating the chore of communicating values back and forth.这可以通过消除来回传达值的繁琐来简化您的代码。 But beware: In your case of doing concurrent work you would need to protect any such variables against non-thread-safe access.但请注意:在您进行并发工作的情况下,您需要保护任何此类变量免受非线程安全访问。

A third approach is using lambda syntax.第三种方法是使用lambda语法。

Runnable task = 
    () -> {   
         for ( int i = 1 ; i <= 5 ; i++ ) {
             System.out.println( "Thread ID: " + Thread.currentThread().getId() + " running at " + Instant.now() );
         }
    }
;

Executors framework执行者框架

By the way, in modern Java we generally have no need to directly address the Thread class.顺便说一句,在现代 Java 中,我们一般不需要直接寻址Thread class。 Instead, we use the Executors framework.相反,我们使用Executors框架。

Below is an example using anonymous class.下面是一个使用匿名 class 的示例。

Tip: Threads do not always have a name, so using their ID is more reliable.提示:线程并不总是有名称,因此使用它们的 ID 更可靠。

ExecutorService es = Executors.newCachedThreadPool() ;

Runnable task = 
    new Runnable() {  // Anonymous class.
         @Override
         public void run() {
            for ( int i = 1 ; i <= 5 ; i++ ) {
                System.out.println( "Thread ID: " + Thread.currentThread().getId() + " running at " + Instant.now() );
             }
         }
    }
;

es.submit( task ) ;
es.submit( task ) ; 
es.submit( task ) ;

es.shutdown() ;
es.awaitTermination( 1 , TimeUnit.MINUTES ) ; 

Same thing, but using the more compact lambda syntax.同样的事情,但使用更紧凑的 lambda 语法。

ExecutorService es = Executors.newCachedThreadPool() ;

Runnable task = 
    () -> {   // Lambda syntax.
         for ( int i = 1 ; i <= 5 ; i++ ) {
             System.out.println( "Thread ID: " + Thread.currentThread().getId() + " running at " + Instant.now() );
         }
    }
;

es.submit( task ) ;
es.submit( task ) ; 
es.submit( task ) ;

es.shutdown() ;
es.awaitTermination( 1 , TimeUnit.MINUTES ) ; 

Full example code完整的示例代码

For a fully-functioning example, add:对于功能齐全的示例,请添加:

  • Random amount of sleep for realism.现实主义的随机睡眠量。
  • Needed exception-handling.需要异常处理。
  • Test for exceeding our time-out when waiting for submitted tasks to finish.在等待提交的任务完成时测试是否超过了我们的超时时间。
package work.basil.demo.concurrent;

import java.time.*;
import java.util.concurrent.*;

public class App
{
    public static void main ( final String[] args )
    {
        final ExecutorService es = Executors.newCachedThreadPool();

        final Runnable task =
                ( ) -> {   // Lambda syntax.
                    for ( int i = 1 ; i <= 5 ; i++ )
                    {
                        try { Thread.sleep( ThreadLocalRandom.current().nextInt( 10 , 200 ) ); } catch ( final InterruptedException e ) { e.printStackTrace(); }
                        System.out.println( "Thread ID: " + Thread.currentThread().getId() + " running nth time: " + i + " at " + Instant.now() );
                    }
                };

        es.submit( task );
        es.submit( task );
        es.submit( task );

        es.shutdown();
        try
        {
            if ( ! es.awaitTermination( 1 , TimeUnit.MINUTES ) )
            {
                System.out.println( "WARN - Executor service time-out expired. Message # 0c75c656-f6bb-4454-9cdd-360caedc555d" );
            }
        }
        catch ( final InterruptedException e )
        {
            e.printStackTrace();
        }
    }
}

When run.跑的时候。

Thread ID: 14 running nth time: 1 at 2021-04-24T06:41:31.758156Z
Thread ID: 16 running nth time: 1 at 2021-04-24T06:41:31.903004Z
Thread ID: 16 running nth time: 2 at 2021-04-24T06:41:31.916130Z
Thread ID: 14 running nth time: 2 at 2021-04-24T06:41:31.916130Z
Thread ID: 15 running nth time: 1 at 2021-04-24T06:41:31.937443Z
Thread ID: 14 running nth time: 3 at 2021-04-24T06:41:31.949898Z
Thread ID: 15 running nth time: 2 at 2021-04-24T06:41:31.957326Z
Thread ID: 15 running nth time: 3 at 2021-04-24T06:41:31.975608Z
Thread ID: 16 running nth time: 3 at 2021-04-24T06:41:32.016034Z
Thread ID: 16 running nth time: 4 at 2021-04-24T06:41:32.085384Z
Thread ID: 16 running nth time: 5 at 2021-04-24T06:41:32.123679Z
Thread ID: 15 running nth time: 4 at 2021-04-24T06:41:32.134960Z
Thread ID: 14 running nth time: 4 at 2021-04-24T06:41:32.143010Z
Thread ID: 15 running nth time: 5 at 2021-04-24T06:41:32.283166Z
Thread ID: 14 running nth time: 5 at 2021-04-24T06:41:32.325071Z

You have already noted that both programs produce the same output and have asked for the differences in those two approaches, and here is what I see the distinction between the two.您已经注意到这两个程序产生相同的 output 并要求这两种方法的差异,这就是我看到的两者之间的区别。

1. Open to extension via top-level class 1.通过顶层class对扩展开放

By implementing Runnable interface in a top-level class, you are allowing the code to be extended or reused by other classes, whereas anonymous class approach does not let you extend outside the class.通过在顶级 class 中实现Runnable接口,您允许其他类扩展或重用代码,而匿名 class 方法不允许您在 class 之外扩展。 One may ask, "why would anyone try to reuse run() method from a parent class?", and that's a fair question but there may be other reasons to extend such class.有人可能会问,“为什么有人会尝试重用父 class 的run()方法?”,这是一个公平的问题,但可能还有其他原因来扩展此类 class。

2. Access to surrounding context via anonymous class 2. 通过匿名 class 访问周围环境

In contract, anonymous class approach lets you access final and effective final variables as well as methods, as the case may be, of the surrounding context.在合同中,匿名 class 方法允许您访问最终和有效的最终变量以及周围上下文的方法(视情况而定)。 There is no such equivalent surrounding context for a top-level class and only way to pass more information would be say, via constructor or other init mechanism before starting the Thread .顶级 class 没有这样的等效环境上下文,并且传递更多信息的唯一方法是在启动Thread之前通过构造函数或其他初始化机制。

3. Option of using Lambda expression 3. 使用 Lambda 表达式的选项

Finally, there is the option of converting an anonymous class into a lambda expression and make code more succinct and therefore more readable.最后,可以选择将匿名 class 转换为 lambda 表达式,使代码更简洁,因此更具可读性。 I'm not saying that top-level classes aren't readable but given the choice between an inline & short Lambda expression and having to navigate to another class, I'd prefer the former.我并不是说顶级类不可读,但考虑到在内联和短 Lambda 表达式之间进行选择,并且必须导航到另一个 class,我更喜欢前者。

To summarise: top-level class approach lets the code to be extended, whereas the anonymous class (or lambda) approach lets the code access the surrounding context concisely.总而言之:顶级 class 方法允许扩展代码,而匿名 class(或 lambda)方法允许代码简洁地访问周围的上下文。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM