当前位置: 首页 > 面试题库 >

等待线程资源消耗

锺离刚洁
2023-03-14
问题内容

我的问题:

当线程处于TIMED_WAIT状态(非休眠)>
99.9%的时间时,JVM中的大量线程是否会消耗大量资源(内存,CPU)吗?当线程正在等待时,如果根本需要维护它们,需要花费多少CPU开销?

答案是否也适用于与非JVM相关的环境(例如linux内核)?

内容:

我的程序收到大量占用空间的程序包。它在不同的程序包中存储相似属性的计数。在收到包裹后的给定时间(可能是数小时或数天)之后,该特定包裹将过期,并且该包裹所贡献的任何计数都应减少。

目前,我通过将所有软件包存储在内存或磁盘中来实现这些功能。每隔5分钟,我会从存储中删除过期的软件包,并浏览其余的软件包以计算属性。此方法占用大量内存,并且时间复杂度较差(O(n)对于时间和内存,其中n是未过期的软件包数)。这使得程序的可伸缩性很差。

解决此问题的另一种方法是,每当一个软件包通过时增加属性计数,并Timer()在该软件包到期后启动一个减少属性计数的线程。这样就无需存储所有笨重的程序包,并将时间复杂度降低到O(1)。但是,这又带来了另一个问题,因为我的程序将开始具有O(n)多个线程,这可能会降低性能。由于大多数线程在其生命周期的绝大部分时间内都处于TIMED_WAIT状态(Java会Timer()调用该Object.wait(long)方法),它是否仍会以很大的方式影响CPU?


问题答案:

首先,Java(或.NET)线程!=内核/ OS线程。

Java
线程是一个高级包装程序,它抽象了系统线程的某些功能。这些类型的线程也称为托管线程。在内核级别,线程只有两种状态,运行和不运行。内核会跟踪一些管理信息(堆栈,指令指针,线程ID等),但是在内核级别,并没有处于某种TIMED_WAITING状态(等于该WaitSleepJoin状态的.NET
)的线程。。这些“状态”仅存在于那种上下文中(这是C ++
std::thread没有state成员的部分原因)。

话虽如此,当托管线程被阻塞时,它是以两种方式来完成的(取决于在托管级别上被请求阻塞的方式);我在OpenJDK中为线程代码看到的实现利用信号量来处理托管等待(这是我在具有某种“托管”线程类的其他C
++框架以及.NET Core中所看到的库),并将互斥锁用于其他类型的等待/锁定。

由于大多数实现都将使用某种锁定机制(例如信号量或互斥量),因此内核通常会执行相同的操作(至少在涉及您问题的地方);也就是说,内核会将线程从“运行”队列中移出,并将其放入“等待”队列中(上下文切换)。深入了解线程调度,特别是内核如何处理线程的执行,不在本问答的范围之内,尤其是因为您的问题是关于Java的,而Java可以在多种不同类型的OS上运行(每种操作系统都可以处理)完全不同的线程)。

更直接地回答您的问题:

当线程的TIMED_WAIT状态(不休眠)> 99.9%的时间时,JVM中的大量线程是否会消耗大量资源(内存,CPU)吗?

为此,有两点需要注意:创建的线程消耗JVM的内存(堆栈,ID,垃圾收集器等),内核消耗内核内存以在内核级别管理线程。除非您特别声明,否则消耗的内存不会更改。因此,如果线程正在睡眠或正在运行,则内存是相同的。

CPU将根据线程活动和请求的线程数进行更改(请记住,线程也消耗内核资源,因此必须在内核级别进行管理,因此必须处理的线程越多,内核就越多必须花费时间来管理它们)。

请记住,调度和运行线程的内核时间非常少(这是设计的重点),但是如果您打算运行 很多
线程,这仍然是要考虑的问题;此外,如果您知道应用程序将在只有几个核心的CPU(或集群)上运行,则可用的核心越少,内核必须进行上下文切换的次数就越多,这通常会增加时间。

当线程正在等待时,如果根本需要维护它们,需要花费多少CPU开销?

没有。参见上文,但是用于管理线程的CPU开销不会根据线程上下文而改变。可能会使用额外的CPU进行上下文切换,并且可以肯定的是,活动时线程本身会使用额外的CPU,但是
维持 等待线程与正在运行的线程相比,CPU没有额外的“成本” 。

答案是否也适用于与非JVM相关的环境(例如linux内核)?

是的,没有。如前所述,托管上下文通常适用于大多数此类环境(例如Java,.NET,PHP,Lua等),但是这些上下文可能会有所不同,并且线程习惯用法和一般功能取决于所使用的内核。因此,尽管一个特定的内核可能每个进程可以处理1000个以上的线程,但是某些内核可能有严格的限制,而其他内核则可能存在其他问题,每个进程的线程数更高;您必须参考OS
/ CPU规格,以查看可能存在的限制。

由于大多数线程将处于TIMED_WAIT状态(Java的Timer()调用Object.wait(long)方法)在其生命周期的绝大部分时间内,它是否仍然以很大的方式影响CPU?

否(阻塞线程的一部分),但要考虑的问题:如果(边缘情况)所有(或>
50%)这些线程需要在同一时间运行?如果您只有几个线程来管理您的软件包,那可能不是问题,而是说您有500多个。同时唤醒所有250个线程将导致大量CPU争用。

由于您尚未发布任何代码,因此很难针对您的情况提出具体建议,但是您倾向于将属性结构存储为类,并将该类保留在可以在Timer(或单独的线程)以查看当前时间是否与包的过期时间匹配,则将运行“过期”代码。这将线程数减少到1,并将访问时间减少到O(1);
但同样,如果没有代码,则该建议可能不适用于您的情况。

希望能有所帮助。



 类似资料:
  • 我用绝地武士连接redis服务器。Redis ip值在一个单独的文件中配置,我试图在初始化期间加载该文件 我从redis获取多个密钥的方法如下 当我在属性文件中给出了不正确的ip值时,访问它的请求线程等待了很长一段时间。我的请求不应该因为池中资源不可用而停止。 在这里,我附加了停顿线程的线程转储(即;处于等待状态的线程) 我怎样才能做到这一点?非常感谢您的帮助。提前感谢:-)

  • 问题内容: 我正在为我的ubuntu服务器(针对我的多客户端匿名聊天程序)实现一种简单的线程池机制,并且需要使我的工作线程进入睡眠状态,直到需要执行一项工作(以函数指针和参数的形式) 。 我当前的系统即将关闭。我(工人线程正在)问经理是否有工作可用,以及是否有5毫秒没有睡眠。如果存在,请将作业添加到工作队列中并运行该函数。糟糕的循环浪费。 什么我 喜欢 做的是做一个简单的事件性的系统。我正在考虑有

  • 问题内容: 我有以下情况: 为了运行算法,我必须运行多个线程,并且每个线程都会在死之前设置一个实例变量x。问题是这些线程不会立即返回: 我应该使用等待通知吗?还是我应该嵌入一个while循环并检查是否终止? 感谢大家! 问题答案: 创建一些共享存储来保存每个线程的值,或者如果足够的话,只存储总和。使用a 等待线程终止。每个线程完成后都会调用,您的方法将使用该方法来等待它们。 编辑: 这是我建议的方

  • 嗨,我正在做一个项目,我已经达到了我非常困的部分。我试图寻找方法来学习如何在繁忙的等待中编写 while 循环,但我没有找到任何东西,我的代码只是作为无限循环运行。有人可以帮助我解释一个繁忙的等待循环应该如何工作,并帮助我打破这个无限循环吗? 该项目希望做到以下几点:早上,学生醒来后(这需要一段随机的时间),他会去洗手间为新的上学日做准备。如果浴室已经客满,学生需要Rest一下(使用yield()

  • 我有一个生产者-消费者模式的多线程任务。可能有许多生产者和一个消费者。我使用ArrayBlockingQueue作为共享资源。 Producer类中的run()方法: Consumer类中的run()方法: main()方法: 现在,当队列为空时,我有消费者结束条件。但是可能会有一段时间队列变成空的,但是一些生产者线程仍然在工作。所以我只需要在完成所有生产者线程之后才完成消费者线程(但它们的数量事

  • 问题内容: 我有一个用ngResource定义的工厂: 我正在对该工厂定义的查询方法进行多次调用。这些调用可以异步发生,但是我需要等待两个调用完成才能继续: 有没有办法用ngResource定义的AngularJS工厂做到这一点,类似于jQuery的$ .when()。then()功能?我不想将jQuery添加到当前项目中。 问题答案: 您将要使用promise和$ q.all()。 基本上,您可