7

我正在阅读有关线程和进程之间的差异的信息,并且几乎在网上到处都是,通常写有一个差异而没有太多解释:

如果一个进程被阻塞,剩余的进程可以继续执行。如果一个用户级线程被阻塞,它的所有对等线程也会被阻塞。

这对我来说没有任何意义。如果调度程序无法在阻塞线程和就绪/可运行线程之间切换,那么并发的意义是什么?给出的原因是,由于操作系统不区分给定父进程的各种线程,它会立即阻止所有线程。

我觉得这很不令人信服,因为所有现代操作系统都有带有线程 ID 的线程控制块,即使它仅在父进程的内存空间内有效。就像 Galvin 的操作系统书中给出的示例一样,如果拼写检查线程无法连接到某些在线词典,我不希望处理我的输入的线程被阻塞。

要么我对这个概念的理解有误,要么所有这些网站多年来都只是复制了一些旧线程差异。此外,我无法在诸如 Galvin 的书籍或 William Stalling 的 COA 书中讨论过线程的书中找到此声明。

这些是我找到陈述的资源:

4

3 回答 3

5

内核级线程和用户级线程是有区别的。简单来说:

  • 内核级线程:由操作系统管理的线程,包括调度。它们是在处理器上执行的。这可能是我们大多数人对线程的看法。
  • 用户级线程:由程序本身管理的线程。在某些情况下,它们也称为纤维或协程。与内核级线程相比,它们需要“让出执行”,即从一个用户级线程切换到另一个用户级线程是由程序显式完成的。用户级线程映射到内核级线程。

由于用户级线程需要映射到内核级线程,因此您需要选择合适的映射。您可以将每个用户级别映射到单独的内核级别线程。您还可以将许多用户级映射到一个内核级线程。在后一个映射中,您让多个并发执行路径由单个线程“正如我们所知”执行。如果这些路径之一阻塞,请记住用户级线程需要让出执行,然后执行(内核级)线程阻塞,这会导致所有其他分配的路径也被有效阻塞。我想,这就是声明所指的。仅供参考:在 Java 中,用户级线程(您在程序中执行的多线程)由 JVM(即运行时系统)映射到内核级线程。


相关资料:

于 2021-08-30T11:12:31.023 回答
2

好的,其他答案提供了详细信息。

但是要在中间击中你的主要convern:

  • 这篇文章有点错误,缺少必要的上下文(请参阅@akuzminykh 对用户级线程和内核级线程的解释中的所有详细信息)
  • 这对 Java 程序员意味着什么:不要理会这些解释。如果您的 Java 线程之一阻塞(由于 I/O 等),则不会对您的任何其他线程产生影响(当然,除非您明确希望它们这样做,但是您必须明确使用机制那)

Java中的线程是如何被阻塞的?

  • 如果您调用sleep()orwait()等​​,当前执行该代码的线程(而不是您调用它们的对象)将被阻止。这些将在某些事件上被释放:一旦计时器用完或线程被另一个线程中断,睡眠将完成,一旦被另一个线程通知,等待将释放。
  • 如果您遇到一个synchronized(lockObj)块或方法:一旦占用该lockObj的其他线程释放它,它将释放它
    • 与此密切相关,如果您输入 ThreadGates、互斥锁等,那么所有用于扩展线程控制的 1000 个专用类(如集合点等)
  • 如果您调用阻塞 I/O 方法,例如从InputStreametc:中读取块int amountOfBytesRead = read(buffer, offset, length),或者String line = myBufferedReader.readLine();
    • 与此相反,有许多非阻塞 I/O 操作,如大多数 java.nio(非阻塞 I/O)包,立即返回,但可能指示无效的结果值
  • 如果垃圾收集器进行快速清理周期(通常很短你甚至不会注意到,并且线程会再次自动释放)
  • 如果您在.parallelStream()流(如myList.parallelStream().forEach(myConsumerAction)线程将正常恢复,就像调用正常方法一样)。在此处查看更多信息:https ://www.baeldung.com/java-when-to-use-parallel-stream
于 2021-08-30T20:57:26.810 回答
2

至少在 Java 的早期,用户级线程被称为“绿色线程”,用于在不支持本机线程的操作系统上实现 Java 线程。还有一篇 Wiki 文章https://en.wikipedia.org/wiki/Green_threads解释了起源和含义。

(这可以追溯到台式机/笔记本电脑是单处理器系统时,它们的 1 个物理插槽中有一个单核 CPU,而 SMP 机器大多仅作为多插槽存在。)

你是对的,这太糟糕了,一旦主流操作系统发展为支持本地线程,人们大多不再这样做了。至少对于 Java,Green threads 指的是 Java 编程语言的原始线程库的名称(在 1.1 版中发布,然后在 1.3 版中将 Green 线程放弃为原生线程)。

因此,如果您不希望拼写检查线程阻塞整个应用程序,请使用 Java 1.3 或更高版本。:P 这是古老的历史。

虽然当系统调用返回它会阻塞时使用非阻塞 IO 和上下文切换有一定的范围,但通常最好让内核处理线程阻塞和解除阻塞,这就是正常的现代系统所做的。


Solaris 上的 IIRC 还使用了 N:M 模型,其中 N 个用户空间线程可能由少于 N 个内核线程处理。这可能意味着在您的报价中拥有一些“对等”线程(共享相同的内核线程),而不是完全可怕的纯用户空间绿色线程。

(即只有部分线程共享同一个内核线程。)

Linux 上的 pthreads 使用 1:1 模型,其中每个软件线程都是内核调度的单独任务。

谷歌发现https://flylib.com/books/en/3.19.1.51/1/定义了这些线程模型并讨论了它们,包括 N:M 混合模型和 N:1 用户空间又名绿色线程如果要避免阻塞其他线程,则需要使用非阻塞 I/O 的模型。(例如,如果系统调用返回EAGAIN或在异步读取或写入队列之后进行用户空间上下文切换。)

于 2021-08-30T17:57:06.623 回答