对ExecutorServices来说,一个实现Runnable的类被认为是一个 "可运行的任务"?

问题描述 投票:0回答:1

我试图用Executors代替同步方法来为我管理线程。但是 submit 方法取一个 Runnable task 而非真正 Runnable target这就是我想要的,因为我启动了一个单线程,目标类将被实例化并运行,就像这样。

        thread = new Thread(this, "thread-process");
        thread.start();

我试着用执行器做一些类似的事情

        this.exec = Executors.newSingleThreadExecutor();
        this.exec.submit(this);

据我所知,线程似乎启动和运行得很好 但我不确定这些是否是等价的?我在使用可运行的目标线程时,应该这样处理吗?Executors?

java multithreading executorservice
1个回答
2
投票

tl;dr

  • 是的,这两种方法达到的目的是一样的:一些代码在后台线程上执行。
  • 使用第二种方法(执行人 框架)而不是明确的 Thread 的实例化。
  • 不要纠结于持有对你的 Runnable 对象。

详情

是的,给定一个 Runnable 的对象 run 方法),比如这样。

public class ReportRunnable implements Runnable {

    public void run() {
        System.out.println( "Reporting at " + Instant.now() );  // Passing: ( Runnable target , String name ).
    }

}

...然后这样做

Runnable runnable = new ReportRunnable() ;
thread = new Thread( runnable , "thread-process" );
thread.start();

...实际上和这样做是一样的。

ExecutorService executorService = Executors.newSingleThreadExecutor() ;
… // You should be keeping a reference to the executor service, so that you can later shut it down gracefully.
Runnable runnable = new ReportRunnable() ;
executorService.submit( runnable ) ;

在这两种情况下,你会立即启动一些正在后台线程上执行的工作。所以在这个意义上,它们的效果是一样的。但也有重要的区别。

要明白 执行人 框架(见 甲骨文教程)的发明是为了在大多数情况下减轻大多数程序员必须掌握管理线程的精细技巧。所以,很少有必要在实例化的过程中使用 Thread 自己了。尽可能的使用执行器框架。

有一点不同的是,执行者服务的 submit 方法返回一个 Future 对象。在上面的代码中,我们忽略了这个返回的对象。但你可能想捕获一个对该对象的引用,以便以后查询任务的进度或完成状态。

另一个不同之处是,你可能选择从单线程切换到使用线程池,由执行器服务自动管理。在某些情况下,你可能希望一组任务都共享同一个线程池。执行器服务让这一切变得非常简单。

ExecutorService executorService = Executors.newFixedThreadPool​( 3 )

;

一个最大的不同是,有各种不同的执行者服务供你利用,提供各种功能。你可以安排一个任务在经过一定时间后运行,而不是立即运行。而且你可以重复运行一个任务,比如每小时发送一封状态报告邮件。

ScheduledExecutorService ses = newSingleThreadScheduledExecutor() ;
… // You should be keeping a reference to the executor service, so that you can later shut it down gracefully.
Runnable runnable = new ReportRunnable() ;
ScheduledFuture<?> reportFuture = scheduler.scheduleAtFixedRate( runnable , 0 , 2 , TimeUnit.HOURS ) ;

然而,另一个区别是管理线程终止,下面将讨论。

变量名称无关紧要

你说的。

但提交方法需要一个Runnable任务,而不是一个真正的Runnable目标。

你似乎对变量的命名很纠结。变量命名是无关紧要的 这里。的 Thread 构造者 Javadoc 用途 target正如我在我的评论中所看到的复制粘贴在我的评论中。run 方法。然而我选择了一个名为 runnable. 你可以选择一个名字,如 exportQuarterlySalesDataRunnable, task, targetpinkElephant.

终止线程

请注意,您最终需要终止您的线程。在应用程序的运行过程中,您可能不再需要该线程或其当前执行的工作。或者您的应用程序可能正在结束其运行,在这种情况下,您必须关闭您的线程,否则在您的应用程序停止后,它们可能会继续像僵尸一样运行。

执行器服务使线程终止变得简单,通过几个 shutdown… 方法。您可以选择中断当前正在进行的工作,或者等待当前工作完成。

Lambda语法

为了完整起见,我将提到,你可以通过现代Java中添加的lambda特性使用更短的语法。


强烈建议:阅读、重读、再阅读这本超级好书。Java并发的实践 作者:Brian Goetz等人

© www.soinside.com 2019 - 2024. All rights reserved.