5

我知道,如果您想线程化,您可以在 java 中扩展线程或实现 runnable 到多线程。但是为什么一定要实现一个接口让java去线程呢?使 java 线程工作的可运行接口的重要性是什么?Java的接口是从什么东西扩展而来的吗?

4

5 回答 5

11

接口的唯一特别之处Runnable在于它Thread接受了它的构造函数。这只是一个普通的旧界面。

与大多数接口一样,关键是您正在按照合同进行编程:您同意将要运行的代码放入Runnable#run()实现中,并Thread同意在另一个线程中运行该代码(当您创建并启动Thread它时) .

Thread实际上是“执行”多线程(因为它与本机系统交互)。的实现Runnable就是您放置要告诉 aThread运行的代码的位置。

实际上,您可以实现 aRunnable并运行它,而无需让它在单独的线程中运行:

Runnable someCode = new Runnable() {
    public void run() {
       System.out.println("I'm a runnable");
    }
};
someCode.run();

所以Runnable它本身和多线程没有任何关系,它只是一个标准的接口,在将一段代码封装在一个对象中时进行扩展。

于 2012-10-19T01:15:06.400 回答
2

Runnable在功能方面,实现接口和扩展Thread类没有区别。但是在某些情况下,Runnable可能会首选实现接口。想想你的类必须从其他类继承并且它应该显示线程功能的情况。由于您的类不能从多个类继承(Java 不支持它),因此您的类可以Runnable在这种情况下实现接口。

于 2012-10-19T01:14:55.073 回答
2

但是为什么一定要实现一个接口让java去线程呢?

您不需要,正如您之前所说,您可以扩展 Thread 对象并实现公共 void run 方法。如果您想要一种更有条理和更灵活(是的,灵活)的方法,您肯定希望使用 Runnable,原因很明显:代码可重用性。

当我说有组织的时候,我想说的是很容易维护一个

Runnable doSomething = new Runnable()
{
    @Override
    public void run()
    {
        goAndDoSomethingReallyHeavyWork();
    }
};

然后为另一个线程重用相同的可运行对象,或者在另一个时刻重用同一个线程(是的,您实际上可以重用一个线程),而不是将 2 个或更多线程扩展为您将使用一次的对象。

使 java 线程工作的可运行接口的重要性是什么?

重要的是 Thread 对象将“知道”您的 Runnable 有一个方法 run 并在必要时执行它(因此停止、暂停和其他 Thread 操作)。

Java的接口是从什么东西扩展而来的吗?

这个问题值得我 +1 给你。我真的很想知道,但它似乎是语言的一个特性,而不是像扩展 Object 超类的所有其他对象一样本身的产物。

我希望它有所帮助。干杯

于 2012-10-19T01:31:46.987 回答
1

但是为什么一定要实现一个接口让java去线程呢?

当您创建一个线程扩展类 Thread 时,您不能再扩展任何其他类(多重继承)。另一方面,如果您使用 Runnable,则可以在需要时获得扩展任何类的继承优势。

除了上述之外,您还可以获得内存和性能级别的好处。

于 2020-12-12T07:51:03.347 回答
0

ExecutorService.submit​( Runnable task )

你说:

延长线

我们不再需要直接寻址Thread类来并发运行代码。Java 5引入了 Executors 框架。请参阅Oracle 的教程

执行器服务管理在一个或多个后台线程上运行您的任务。您可以从通过Executors类实例化的多种执行器服务中进行选择。

对于偶尔的一些短期任务,请使用由缓存线程池支持的执行器服务。

ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit( yourRunnableObjectGoesHere ) ;

an 的工作ExecutorService是在一个名为runor的方法中执行代码call

正如其他正确答案所解释的那样,Runnable接口的目的是它代表一个合同。当您的代码声称要实现该Runnable接口时,您承诺您的代码有一个名为 exact 的方法run

Java 编译器注意到这个承诺并检查合同是否已履行。如果您传递的对象未能 (a) 声明它实现Runnable并且(b) 携带一个run不带参数且不返回值的方法,那么编译器会将这种情况标记为错误。

因此,执行器服务要求您将任务作为实现Runnable(或Callable)接口的类的对象提交,以保证当任务到达以在后台线程上执行时,该任务具有精确命名run(或callfor Callable)的方法。

示例代码

这是一些示例代码。请注意执行器服务如何不关心您传递给其submit方法的对象类型。你可以传递一个类的对象Dog, SalesReport, 或者Payroll— 没关系。执行器服务所关心的是传递给的对象submit有一个名为run.

package work.basil.example;

import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo
{
    public static void main ( String[] args )
    {
        Demo app = new Demo();
        app.demo();
    }

    private void demo ( )
    {
        Runnable task = new Runnable()
        {
            @Override
            public void run ( )
            {
                System.out.println( "Doing this work on a background thread. " + Instant.now() );
            }
        };

        ExecutorService executorService = null;
        try
        {
            executorService = Executors.newCachedThreadPool();
            executorService.submit( task );
            executorService.submit( task );
            executorService.submit( task );

            // Wait a moment for the background threads to do their work.
            try
            {
                Thread.sleep( Duration.ofSeconds( 2 ).toMillis() );
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }
        }
        finally
        {
            if ( Objects.nonNull( executorService ) ) { executorService.shutdown(); }
            System.out.println( "Ending the main thread. " + Instant.now() );
        }
    }
}

运行时:

Doing this work on a background thread. 2020-12-20T07:16:26.119414Z
Doing this work on a background thread. 2020-12-20T07:16:26.119176Z
Doing this work on a background thread. 2020-12-20T07:16:26.119255Z
Ending the main thread. 2020-12-20T07:16:28.124384Z

Lambda 语法

Runnable如果您对现代 Java 中的 lambda 语法感到满意,我们可以将定义您的实现的代码缩短为一行。效果相同,只是语法不同。

package work.basil.example;

import java.time.Duration;
import java.time.Instant;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Demo
{
    public static void main ( String[] args )
    {
        Demo app = new Demo();
        app.demo();
    }

    private void demo ( )
    {
        Runnable task = ( ) -> System.out.println( "Doing this work on a background thread. " + Instant.now() );

        ExecutorService executorService = null;
        try
        {
            executorService = Executors.newCachedThreadPool();
            executorService.submit( task );
            executorService.submit( task );
            executorService.submit( task );

            // Wait a moment for the background threads to do their work.
            try
            {
                Thread.sleep( Duration.ofSeconds( 2 ).toMillis() );
            }
            catch ( InterruptedException e )
            {
                e.printStackTrace();
            }
        }
        finally
        {
            if ( Objects.nonNull( executorService ) ) { executorService.shutdown(); }
            System.out.println( "Ending the main thread. " + Instant.now() );
        }
    }
}

遗产

您问:

Java的接口是从什么东西扩展而来的吗?

Java 中的所有类都扩展了Object该类或从Object.

Java 中的接口不扩展自任何类。请记住,接口只是一个契约,是某个类可能选择做出的关于具有特定名称的方法的承诺,这些方法接受某些类型的参数并返回某种类型的值。

Java 中的接口可以扩展一个或多个其他接口。这样做只是为声称实现该接口的类所做出的承诺添加了更多方法。请注意,Runnable它由其他两个接口扩展:RunnableFutureRunnableScheduledFuture.

于 2020-12-20T07:09:44.750 回答