我知道,如果您想线程化,您可以在 java 中扩展线程或实现 runnable 到多线程。但是为什么一定要实现一个接口让java去线程呢?使 java 线程工作的可运行接口的重要性是什么?Java的接口是从什么东西扩展而来的吗?
5 回答
接口的唯一特别之处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
它本身和多线程没有任何关系,它只是一个标准的接口,在将一段代码封装在一个对象中时进行扩展。
Runnable
在功能方面,实现接口和扩展Thread
类没有区别。但是在某些情况下,Runnable
可能会首选实现接口。想想你的类必须从其他类继承并且它应该显示线程功能的情况。由于您的类不能从多个类继承(Java 不支持它),因此您的类可以Runnable
在这种情况下实现接口。
但是为什么一定要实现一个接口让java去线程呢?
您不需要,正如您之前所说,您可以扩展 Thread 对象并实现公共 void run 方法。如果您想要一种更有条理和更灵活(是的,灵活)的方法,您肯定希望使用 Runnable,原因很明显:代码可重用性。
当我说有组织的时候,我想说的是很容易维护一个
Runnable doSomething = new Runnable()
{
@Override
public void run()
{
goAndDoSomethingReallyHeavyWork();
}
};
然后为另一个线程重用相同的可运行对象,或者在另一个时刻重用同一个线程(是的,您实际上可以重用一个线程),而不是将 2 个或更多线程扩展为您将使用一次的对象。
使 java 线程工作的可运行接口的重要性是什么?
重要的是 Thread 对象将“知道”您的 Runnable 有一个方法 run 并在必要时执行它(因此停止、暂停和其他 Thread 操作)。
Java的接口是从什么东西扩展而来的吗?
这个问题值得我 +1 给你。我真的很想知道,但它似乎是语言的一个特性,而不是像扩展 Object 超类的所有其他对象一样本身的产物。
我希望它有所帮助。干杯
但是为什么一定要实现一个接口让java去线程呢?
当您创建一个线程扩展类 Thread 时,您不能再扩展任何其他类(多重继承)。另一方面,如果您使用 Runnable,则可以在需要时获得扩展任何类的继承优势。
除了上述之外,您还可以获得内存和性能级别的好处。
ExecutorService.submit( Runnable task )
你说:
延长线
我们不再需要直接寻址Thread
类来并发运行代码。Java 5引入了 Executors 框架。请参阅Oracle 的教程。
执行器服务管理在一个或多个后台线程上运行您的任务。您可以从通过Executors
类实例化的多种执行器服务中进行选择。
对于偶尔的一些短期任务,请使用由缓存线程池支持的执行器服务。
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.submit( yourRunnableObjectGoesHere ) ;
an 的工作ExecutorService
是在一个名为run
or的方法中执行代码call
。
正如其他正确答案所解释的那样,Runnable
接口的目的是它代表一个合同。当您的代码声称要实现该Runnable
接口时,您承诺您的代码有一个名为 exact 的方法run
。
Java 编译器注意到这个承诺并检查合同是否已履行。如果您传递的对象未能 (a) 声明它实现Runnable
,并且(b) 携带一个run
不带参数且不返回值的方法,那么编译器会将这种情况标记为错误。
因此,执行器服务要求您将任务作为实现Runnable
(或Callable
)接口的类的对象提交,以保证当任务到达以在后台线程上执行时,该任务具有精确命名run
(或call
for 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
它由其他两个接口扩展:RunnableFuture
和RunnableScheduledFuture
.