【问题标题】:How do Lambba works in Java when using Thread and Runnable?使用 Thread 和 Runnable 时,Lamba 在 Java 中如何工作?
【发布时间】:2020-02-01 01:22:25
【问题描述】:

我的 IDE(IntelliJ) 建议替换此代码:

private void countIterations() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            long startTimestamp = System.currentTimeMillis();
            long endTimestamp = startTimestamp + ITERATIONS_COUNTER_DURATION_SEC * 1000;

            int iterationsCount = 0;
            while (System.currentTimeMillis() <= endTimestamp) {
                iterationsCount++;
            }

            Log.d(
                    "Exercise1",
                    "iterations in " + ITERATIONS_COUNTER_DURATION_SEC + "seconds: " + iterationsCount
            );
        }
    }).start();

}

有了这个:

private void countIterations() {
    new Thread(() -> {
        long startTimestamp = System.currentTimeMillis();
        long endTimestamp = startTimestamp + ITERATIONS_COUNTER_DURATION_SEC * 1000;

        int iterationsCount = 0;
        while (System.currentTimeMillis() <= endTimestamp) {
            iterationsCount++;
        }

        Log.d(
                "Exercise1",
                "iterations in " + ITERATIONS_COUNTER_DURATION_SEC + "seconds: " + iterationsCount
        );
    }).start();

}

我的问题是它如何知道它是 Runnable? Thread 和 Runnable 都有 run 方法。

【问题讨论】:

  • 它通过类型推断知道它。 new Thread(Runnable) 期望...嗯...Runnable,因此 lambda 必须是 Runnable 的实现。
  • 除上述之外。调用 new Thread(new Thread()) 中的任何一个或传递 new Runnable 或 lambda,都会将 Thread 构造函数解析为 (runnable),但您不能将 new Thread 作为 lambda 传递,因为它是一个类。 lambda 表达式是只传递函数式接口的简写。
  • 除了前面正确的 cmets,我还要补充一点,这称为目标类型,即根据要分配或传递 lambda 的目标来推断类型。
  • 除了 all 之前的 cmets,在现代 Java 中很少有充分的理由使用 new Thread;你应该改用Executor
  • @chrylis-onstrike- 这取决于run() 方法的作用。在这种情况下,您可能是对的,因为 run() 方法似乎只做一件事然后退出。但对于长时间运行的线程,调用适当的ThreadFactory object 可能更有意义。

标签: java lambda java-8 concurrency


【解决方案1】:

它怎么知道是Runnable?

首先,让我们确保我们知道“Runnable”是什么意思。有经验的Java程序员说不用想太深,但Runnable不是一个类。它是一个接口:它是一些实际类应该拥有的一个或多个方法的规范。当我们说“可运行”时,我们真正的意思是“implements Runnable 的某个类的实例。”

那么编译器如何知道 lambda 表达式必须创建“可运行对象”?这很容易。编译器已经看到Thread 类的声明,Thread 类声明明确表示构造函数的参数必须是 Runnable。

ThreadRunnable 都有 run() 方法。

好的。 Thread implements Runnable,但在那里使用Thread 实例没有任何意义,因为Threadrun() 方法不会执行您希望线程执行的操作。编译器必须使用run() 方法定义一个全新的类,该方法执行您放入lambda 主体的所有内容。系统中没有其他类已经完成了所有这些事情。

好的,那么为什么新类不是extends Thread? (或者,extendsimplements Runnable 的任何其他现有类?)

只是因为没有理由这样做。 Thread 构造函数并没有说它想要一个 Thread 参数。它说它需要一个Runnable 参数。它会对implements Runnable任何 类感到满意,并且除了调用它的run() 方法之外,它永远不会对对象做任何事情。

好的,但是编译器如何知道将 lambda 的主体变成名为 run() 的方法?

因为Runnable 是一个@functional 接口,它只声明了一个方法。 Runnable 对象必须有一个run() 方法,并且接口没有指定任何其他方法,所以没有其他选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-24
    • 2013-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多