Java线程:实现runnable如何为线程工作

时间:2012-10-19 01:13:25

标签: java multithreading

据我所知,如果你想要线程,你可以在java中扩展线程或实现runnable到multithread。但为什么你必须实现java的接口线程?什么是可运行的接口的重要性,使java线程工作? Java的界面是否扩展了什么?

5 个答案:

答案 0 :(得分:10)

Runnable接口唯一特别之处在于它是Thread在其构造函数中所采用的内容。这只是一个简单的界面。

与大多数接口一样,重点在于您正在编写合同:您同意将要运行的代码放在Runnable#run()实现中,Thread同意运行该代码在另一个线程中(当你使用它创建并启动Thread时)。

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

实际上,您可以实现Runnable并运行它,而不必在单独的线程中运行:

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

所以Runnable本身与多线程无关,它只是在对象中封装代码块时扩展的标准接口。

答案 1 :(得分:2)

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

答案 2 :(得分:1)

  

但是为什么你必须为java实现一个接口线程?

如前所述,您不能扩展Thread对象并实现public void run方法。如果你想要一个更有条理和更灵活(是的,灵活的)方法,你肯定想要使用Runnable一个明显的原因:代码可重用性。

当我说有组织的时候,我想说保持一个

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

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

  

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

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

  

Java的界面是否扩展了什么?

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

我希望它有所帮助。干杯

答案 3 :(得分:0)

但是为什么要为Java线程实现接口呢?

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

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

答案 4 :(得分:0)

ExecutorService.submit​( Runnable task )

你说:

<块引用>

扩展线程

我们不再需要直接寻址 Thread 类来并发运行代码。 Java 5 引入了 Executors 框架。见tutorial by Oracle

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

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

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

ExecutorService 的工作是在完全命名为 runcall 的方法中执行代码。

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

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

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

示例代码

这是一些示例代码。请注意执行程序服务如何不关心您传递给其 submit 方法的对象类型。您可以传递类 DogSalesReportPayroll 的对象 — 无关紧要。执行器服务只关心传递给 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 语法

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

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