与线程相比,进程在上下文切换方面是否有任何开销?

c6ubokkw  于 2021-06-30  发布在  Java
关注(0)|答案(2)|浏览(321)

关于我打算做什么的几句话。我需要创建一些任务执行器,它将轮询队列中的任务并只执行此任务中的代码。为此,我需要实现一些中断机制,使用户能够停止此任务。
所以我看到了两种可能的解决方案:1。启动线程池并使用 .destroy() 线程的方法(我不会使用任何共享对象)2。使用分离的进程池和 System.exit() 或者杀死要处理的信号。方案2。看起来更安全,因为我可以确保线程终止不会导致任何并发问题。但我不确定它是否会产生很大的开销。
另外我也不确定jvm,如果我使用分离的进程,每个进程都将使用分离的jvm,这会带来很多开销。不管怎样。所以我的问题是。对我来说,为工作进程选择一种没有运行时的不同语言是可能的选择,但我仍然没有足够的进程经验,也不知道开销。

0ve6wy6x

0ve6wy6x1#

使用线程的.destroy()方法启动线程池并停止它们(我不会使用任何共享对象)
你不能停止现代虚拟机上的线程,除非说线程是'在它'。破坏和朋友不真正做你想做的,这是不安全的。正确的方法是打电话 interrupt() . 如果线程想要惹恼您,并且在遇到中断调用时没有真正停止,那么它们可以。解决方案是修复代码,使它不再这样做。请注意,提升中断标志将保证停止任何正在休眠的方法,该方法被指定为引发interruptedexception(sleep、wait等),并且在大多数操作系统上,也将导致任何当前冻结的i/o调用通过引发ioexception而退出,但这不能保证。
使用分离进程池和system.exit()或kill信号进行处理。
你好贵;虚拟机不是一个轻量级的东西;它将有自己的所有类的副本(甚至像 java.lang.String 和公司)。10个虚拟机是一个延伸。而1000个线程是没有问题的。
为此,我需要实现一些中断机制,使用户能够停止此任务。
真正的问题是,这很难保证。但是如果你控制了需要中断的代码,那么通常没什么大不了的。只需使用interrupt()机制。
编辑:如果您想知道如何做中断的事情:在线程上提升中断标志只会提升标志;除非编写与之交互的代码,或者调用与之交互的方法,否则不会发生其他任何事情。
主要有3种交互作用:
所有阻塞并声明抛出interruptedex的东西都将降低标志并抛出interruptedex。如果旗子升起,你呼叫 Thread.sleep ,它将立即清除标志并抛出异常,而无需等待。因此,捕获该异常,并返回/中止/中断任务。 Thread.interrupted() 将降低标志并返回true(因此,只执行一次)。把它放到你的事件循环中。不是的 public void run() {while (true) { ... }} 或者 while (running) {} 或者别的什么,这是 while (!Thread.interrupted() 或者有可能 while (running && !Thread.interrupted9)) .
任何其他阻塞方法可以是也可以不是;java故意不指定任何一种方式,因为它依赖于操作系统和体系结构。如果他们这样做了(很多人也这样做了),他们就不能抛出interruptedex,例如。 FileInputStream.read 不适合扔。它们抛出ioexception,并显示一条消息,指示发生了中止。
确保这三条代码路径以某种方式指向一个快速结束的任务,并且您拥有您想要的:用户可中断的任务。

b91juud3

b91juud32#

执行者框架

java已经为您提供了一个具有所需特性的工具executors框架。
你说:
我需要创建一些任务执行器,它将轮询队列中的任务并只执行此任务中的代码。
这个 ExecutorService 接口就是这样做的。
从中选择满足您需要的实现 Executors 班级。例如,如果要按任务提交的顺序运行任务,请使用单线程执行器服务。如果你想要其他的行为,你可以选择其他的行为。

ExecutorService executorService = Executors.newSingleThreadExecutor() ;

你说:
启动线程池
executor服务可以由线程池支持。

ExecutorService executorService = Executors.newFixedThreadPool​( 3 ) ;  // Create a pool of exactly three threads to be used for any number of submitted tasks.

你说:
只需执行此任务中的代码
将任务定义为实现 Runnable 或者 Callable . 那意味着你们班有 run 方法,或 call 方法。

Runnable task = ( ) -> System.out.println( "Doing this work on a background thread. " + Instant.now() );

你说:
将轮询队列中的任务
提交要运行的任务。您可以提交许多任务,可以是同一类的任务,也可以是不同类的任务。executor服务维护提交任务的队列。

executorService.submit( task );

或者,您可以捕获 Future 返回的对象。

Future future = executorService.submit( task );

那个 Future 对象用于检查任务是否已完成或已取消。

if( future.isDone() ) { … }

你说:
允许用户停止此任务
如果要取消任务,请致电 Future::cancel .
通过 true 如果您想在任务已经开始执行时中断它。
通过 false 如果您只想在任务开始执行之前取消它。

future.cancel( true );

你说:
看起来更安全,因为我可以确保线程终止不会导致任何并发问题。
使用executors框架,您不会创建或终止任何线程。executor服务实现处理线程。你的代码从来没有解决 Thread 直接上课。
所以没有这种并发问题。
但是,如果跨线程共享任何资源,则可能存在其他并发问题。我强烈建议阅读brian goetz等人的java并发实践。
你说:
但我不确定它是否会产生很大的开销。
正如rzwitserloot的正确答案所解释的,您的方法肯定会产生比使用executors框架更多的开销。
仅供参考,将来projectloom将把虚拟线程(光纤)引入java平台。这通常会使后台线程速度更快,并使成千上万甚至数百万个非cpu限制的任务变得实用。早期访问java16提供了特殊的构建。

ExecutorService executorService = newVirtualThreadExecutor() ; 
executorService.submit( task ) ;

相关问题