Java 线程池中的时间切片算法

Java 线程池中的时间切片算法,java,multithreading,threadpool,cpu-cores,Java,Multithreading,Threadpool,Cpu Cores,首先,让我们讨论原始线程。假设我有4个内核和6个线程。这4个内核将对这6个线程进行“时间切片”。给这4个核心一点时间 但假设我有固定的4个线程池,我在其中运行10个线程。我读到它会将这10个线程视为任务。这意味着它不会对10个线程进行时间切片,而是一次运行4个线程,一旦其中一个线程完成,就会需要另一个线程,以此类推 我有点困惑,为什么在第一种情况下有时间切片,而在第二种情况下没有?但从技术上讲,可能会有(假设我有4个内核和5个线程池,可以处理这10个线程),然后这5个线程将在这4个内核中进行时间

首先,让我们讨论原始线程。假设我有4个内核和6个线程。这4个内核将对这6个线程进行“时间切片”。给这4个核心一点时间

但假设我有固定的4个线程池,我在其中运行10个线程。我读到它会将这10个线程视为任务。这意味着它不会对10个线程进行时间切片,而是一次运行4个线程,一旦其中一个线程完成,就会需要另一个线程,以此类推

我有点困惑,为什么在第一种情况下有时间切片,而在第二种情况下没有?但从技术上讲,可能会有(假设我有4个内核和5个线程池,可以处理这10个线程),然后这5个线程将在这4个内核中进行时间切片。另外,在5个线程中,最多可以同时执行5个任务,直到一个线程完成,然后再执行下一个线程

我写这篇文章时深思熟虑。我说错话了吗?有人能给我一个基本的经验法则,告诉我如何在不过度思考的情况下立即理解这一点吗?我觉得我缺少了一些基础知识。

在第一种情况下(4个内核和6个线程),4个线程将同时运行。2个线程将等待。
例如,如果线程1、2、3、4正在运行,而线程5、6正在等待,则可能在一段时间后,线程1、3、5、6正在运行,线程2、4正在等待。
这就是时间切片的含义

在第二种情况下,当您有一个包含4个工作线程的线程池时,同样的情况也会发生。
假设您提交了10个任务(可运行),那么其中4个任务肯定会同时运行;6将在线程池队列中等待。
每当任务完成时,线程都会从队列中提取另一个任务。
这将持续发生,直到队列中没有剩余的任务。
请注意,即使队列中没有任务,4个工作线程仍处于活动状态,尽管处于休眠状态(操作系统将运行来自其他进程的线程)

如果所有任务都是100%CPU限制的,那么线程池设计会更好,因为如果操作系统只有4个内核,那么无论有多少任务挂起,拥有4个以上的线程都是无用的。
一般来说,在同一个系统中运行多个线程是没有效率的,因为上下文切换既昂贵又缓慢

我有固定的4个线程池,我在那里运行,比如说10个线程

通常情况下,您不会将线程对象提交给ExecutorService,因为这样会造成混乱

只有由于
Thread
类实现了
Runnable
,才有可能向ExecutorService提交线程对象。ExecutorService将把线程对象与Runnable的任何其他实现一样对待:

将线程对象提交到线程池时,它将添加到线程池的工作队列中。然后池中的一个线程将其拾取,并直接调用Thread.run()方法,就像对任何其他Runnable实例一样

因此,Thread对象的run()方法在线程池的一个线程中运行,而不是在它自己的新线程中运行。从未调用Thread.start()方法来启动新线程

这两个是等效的:

threadPool.submit(new Thread() {
    public void run() {
        doSomething();
    }
});

threadPool.submit(new Runnable() {
    public void run() {
        doSomething();
    }
});

不要将
Thread
对象与线程混淆。
Thread
对象只有在调用其
start
方法时才会映射到线程。如果将其作为任务传递给线程池,则
线程
将被视为
可运行
。不会为其创建线程,而是从现有线程之一执行其
run
方法。如果您需要具体的解释,请包含一些代码。我不理解您在“原始线程”和“线程”之间所做的区分。我不明白你所说的“我有固定的4个线程池,在那里运行,比如说10个线程”是什么意思。您可以有4个线程,也可以有10个线程。它是一个或另一个,而不是两者。@StephenC我认为“我有4个线程的固定池,我在其中运行,比如说10个线程”意味着用4个线程构建一个新的固定线程池,但在其中提交10个
Runnable
s(这里还要记住
thread
是一个
Runnable
)。非常感谢!谢谢你,乔尼!