[英]Java Threading: How does implementing runnable work for threading
我知道如果你想要线程,你可以扩展线程或在 java 中实现可运行到多线程。 但是为什么非要实现一个接口让java去线程呢? 使 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
接口和扩展Thread
类没有区别。 但是在某些情况下,可能更喜欢实现Runnable
接口。 考虑一下您的类必须从其他类继承的情况,并且它还应该显示线程功能。 由于您的类不能从多个类继承(Java 不支持),因此在这种情况下您的类可以实现Runnable
接口。
但是为什么非要实现一个接口让java去线程呢?
您不需要,正如您之前所说,您可以扩展 Thread 对象并实现 public 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 ) ;
ExecutorService
的工作是执行名为run
或call
的方法中的代码。
正如其他正确答案所解释的那样, Runnable
接口的目的是它代表一个合同。 当您的代码声称实现Runnable
接口时,您承诺您的代码有一个名为run
的方法。
Java 编译器注意到这个承诺并检查合同是否已履行。 如果您传递的对象未能同时 (a) 声明它实现Runnable
,并且(b) 携带不带参数且不返回任何值的方法run
,则编译器会将这种情况标记为错误。
因此,执行程序服务要求您将任务作为实现Runnable
(或Callable
)接口的类的对象提交,以保证当任务到达并在后台线程上执行时,该任务有一个名为run
(或call
Callable
)。
这是一些示例代码。 请注意执行程序服务如何不关心您传递给它的submit
方法的对象类型。 您可以传递类Dog
、 SalesReport
或Payroll
的对象——都没有关系。 executor 服务只关心传递给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
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.