为什么线程池独立执行任务而不是同时执行?
Why does thread pool takes tasks independenty and not concurrently?
我正在努力学习有关线程池的基础知识。我了解到它在内部使用阻塞队列 'steal' 任务并将它们 运行 到池中的给定线程中。这意味着如果我有 10 个任务和 5 个线程,它可以同时 运行 只有 5 个任务,直到 1 个完全完成。
问题是:为什么不能并发呢?为什么不对这 10 项任务进行时间切片呢?
这个实现的原因是什么?
Why not concurrently? Why not just time-slice those 10 tasks?
您可以拥有一个能够执行十个并发任务的线程池。您只需要将它配置为至少有十个工作线程。 “Time-slicing”任务是 线程 所做的。线程 pools 所做的是:
- 允许您的程序控制用于执行“后台”任务的线程数,并且
- 允许您的程序 re-use 个线程,这比为每个新任务创建一个新线程,然后在任务完成时销毁线程要高效得多。
为了“time-slice 10 个任务”,这些任务需要在 运行 并发的 10 个独立线程中。
time-slicing调度算法是由操作系统实现的,不是Java。时间片适用于 Java 中的线程,因为 Java 线程是作为 本地操作系统线程实现的 :每个 Java 线程都有自己的本地线程,并且这些线程由操作系统按其认为合适的方式进行调度。
这里“线程池线程”和“原始线程”没有区别。如果你给一个线程Runnable
的实例(不管它是不是线程池的一部分)它会从头到尾运行,服从操作系统的时间片调度算法。
那么为什么不使用数千个线程,为什么还要费心使用线程池呢?事实证明,操作系统线程是一种相对昂贵且稀缺的资源,因此 Java 线程也是如此。
由于操作系统线程非常昂贵,Project Loom 正在研究将轻量级用户 space 线程添加到 Java。这个答案中的一些细节可能会改变 when/if loom 被合并到主流中 Java。
一些很好的答案,但我想我会专门回答你的问题。
I learnt that it internally uses blocking queue to 'steal' tasks and run them into given threads in pool. Meaning that if I had 10 tasks and 5 threads, it could run only 5 tasks at the same time, until 1 finishes ENTIRELY.
如果您将线程池配置为有 5 个线程 (Executors.newFixedThreadPool(5)
),那么它将启动 5 个线程来 运行 您的作业。最初 5 个作业同时分配给 5 个线程 运行(如果您的服务器有 5 个可用的 CPU)。一旦 5 个作业中的一个完成,第 6 个作业将立即在空闲线程上启动。这一直持续到所有 10 个作业都已 运行.
Question is: Why not concurrently? Why not just time-slice those 10 tasks? What is the reason of this implementation?
如果需要,您可以改用缓存线程池 (Executors.newCachedThreadPool()
),这将为您同时提交的 10 个作业中的每一个启动一个线程。这可能适用于 10 个作业,但不适用于 100,000 个作业——您不会希望启动 100,000 个线程。当我们想要 限制 并发 运行 的作业数时,我们使用固定线程池。尽管似乎 运行 同时处理 5 个作业总是 运行 比 运行 同时处理 10 个作业慢,但事实并非如此。当作业和整个作业之间的 OS 时间片 吞吐量 时,5 个线程可能比 10 个线程更快,这取决于您的硬件有多少个处理器,这是有代价的。限制并发作业的数量也不会对您的服务器造成太大压力,并且应该使您的应用程序更好地与其他 运行ning 应用程序一起工作。
在这里查看我关于缩放线程的回答:Concept behind putting wait(),notify() methods in Object class
我正在努力学习有关线程池的基础知识。我了解到它在内部使用阻塞队列 'steal' 任务并将它们 运行 到池中的给定线程中。这意味着如果我有 10 个任务和 5 个线程,它可以同时 运行 只有 5 个任务,直到 1 个完全完成。
问题是:为什么不能并发呢?为什么不对这 10 项任务进行时间切片呢? 这个实现的原因是什么?
Why not concurrently? Why not just time-slice those 10 tasks?
您可以拥有一个能够执行十个并发任务的线程池。您只需要将它配置为至少有十个工作线程。 “Time-slicing”任务是 线程 所做的。线程 pools 所做的是:
- 允许您的程序控制用于执行“后台”任务的线程数,并且
- 允许您的程序 re-use 个线程,这比为每个新任务创建一个新线程,然后在任务完成时销毁线程要高效得多。
为了“time-slice 10 个任务”,这些任务需要在 运行 并发的 10 个独立线程中。
time-slicing调度算法是由操作系统实现的,不是Java。时间片适用于 Java 中的线程,因为 Java 线程是作为 本地操作系统线程实现的 :每个 Java 线程都有自己的本地线程,并且这些线程由操作系统按其认为合适的方式进行调度。
这里“线程池线程”和“原始线程”没有区别。如果你给一个线程Runnable
的实例(不管它是不是线程池的一部分)它会从头到尾运行,服从操作系统的时间片调度算法。
那么为什么不使用数千个线程,为什么还要费心使用线程池呢?事实证明,操作系统线程是一种相对昂贵且稀缺的资源,因此 Java 线程也是如此。
由于操作系统线程非常昂贵,Project Loom 正在研究将轻量级用户 space 线程添加到 Java。这个答案中的一些细节可能会改变 when/if loom 被合并到主流中 Java。
一些很好的答案,但我想我会专门回答你的问题。
I learnt that it internally uses blocking queue to 'steal' tasks and run them into given threads in pool. Meaning that if I had 10 tasks and 5 threads, it could run only 5 tasks at the same time, until 1 finishes ENTIRELY.
如果您将线程池配置为有 5 个线程 (Executors.newFixedThreadPool(5)
),那么它将启动 5 个线程来 运行 您的作业。最初 5 个作业同时分配给 5 个线程 运行(如果您的服务器有 5 个可用的 CPU)。一旦 5 个作业中的一个完成,第 6 个作业将立即在空闲线程上启动。这一直持续到所有 10 个作业都已 运行.
Question is: Why not concurrently? Why not just time-slice those 10 tasks? What is the reason of this implementation?
如果需要,您可以改用缓存线程池 (Executors.newCachedThreadPool()
),这将为您同时提交的 10 个作业中的每一个启动一个线程。这可能适用于 10 个作业,但不适用于 100,000 个作业——您不会希望启动 100,000 个线程。当我们想要 限制 并发 运行 的作业数时,我们使用固定线程池。尽管似乎 运行 同时处理 5 个作业总是 运行 比 运行 同时处理 10 个作业慢,但事实并非如此。当作业和整个作业之间的 OS 时间片 吞吐量 时,5 个线程可能比 10 个线程更快,这取决于您的硬件有多少个处理器,这是有代价的。限制并发作业的数量也不会对您的服务器造成太大压力,并且应该使您的应用程序更好地与其他 运行ning 应用程序一起工作。
在这里查看我关于缩放线程的回答:Concept behind putting wait(),notify() methods in Object class