我知道在Java中,如果你想要使用多线程,可以通过扩展Thread类或实现Runnable接口来实现。但是为什么必须要实现一个接口来使Java实现线程呢?Runnable接口的重要性是什么,它是如何使Java线程工作的?Java的接口继承自哪里?
我知道在Java中,如果你想要使用多线程,可以通过扩展Thread类或实现Runnable接口来实现。但是为什么必须要实现一个接口来使Java实现线程呢?Runnable接口的重要性是什么,它是如何使Java线程工作的?Java的接口继承自哪里?
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
本身与多线程无关,它只是一个标准接口,用于将一块代码封装在对象中时扩展。
Runnable doSomething = new Runnable()
{
@Override
public void run()
{
goAndDoSomethingReallyHeavyWork();
}
};
就功能而言,实现Runnable
接口或扩展Thread
类之间没有区别。但是在某些情况下,实现Runnable
接口可能更好。想象一下这样的情况:你的类必须继承自其他类,并且还应该显示线程功能。由于你的类无法从多个类继承(Java不支持),因此在这种情况下,你的类可以实现Runnable
接口。
但是为什么在Java中必须实现一个接口来创建线程?
当你通过继承Thread类创建一个线程时,你将不能再继承其他任何类(多重继承)。 另一方面,如果你使用Runnable接口,则可以获得继承任何类的好处,如果需要的话。
除了上述好处之外,你还可以获得内存和性能方面的优势。
ExecutorService.submit( Runnable task )
您说:
扩展线程
我们不再需要直接使用 Thread
类来并发运行代码。 Java 5 引入了 Executors 框架。请参见 Oracle 的教程。
执行者服务管理在一个或多个后台线程上运行您的任务。您可以从几种类型的执行者服务中选择,这些服务是通过 Executors
类实例化的。
对于偶尔的一些短暂任务,请使用由缓存线程池支持的执行者服务。
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit( yourRunnableObjectGoesHere ) ;
ExecutorService
的作用是执行一个名为run
或call
的方法中的代码。Runnable
接口的目的是代表一个协议。当你的代码声称实现Runnable
接口时,你承诺你的代码有一个名为run
的方法。Runnable
接口且没有一个不带参数且不返回任何值的run
方法的对象,则编译器将标记该情况为错误。
因此,执行器服务要求您将任务提交为实现Runnable
(或Callable
)接口的类的对象,以确保当一个任务到达后台线程上执行时,该任务具有名为run
(或Callable
的call
)的方法。
以下是一些示例代码。请注意,执行器服务并不关心您将什么类型的对象传递给其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
如果您熟悉现代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
被两个其他接口RunnableFuture
和RunnableScheduledFuture
所继承。
theRunnable.run()
并期望它能自动启动线程:但实际上并不会。 - user166390Thread
。 - Mark Peters