java 具体案例中的上下文切换



我带着一个关于Java中发生的线程、进程和上下文切换的问题来找你。我已经阅读了有关这些知识的其他问题,但我希望有人澄清一些我不太理解的事情的某些方面。我在这方面做了一个例子。

假设我们有一个类,它接受一个命令,然后运行(在新线程中)给定的命令,并创建 3 个额外的线程,该线程获取它的每个流(输入、错误、输出),然后打印(对于前两个)它得到的内容。

public class ThreadA extends Thread {
String command;
private Frame container;
public ThreadA(String command,Frame container) {
this.command = command;
this.container = container;
}
@Override
public void run() {
Process p = null;
try {
p = Runtime.getRuntime().exec(command);
new ErrorReadThread(p,container).start();
new InputReadThread(p,container).start();
new OutputReadThread(p).start();
int exitValue = p.waitFor();
System.out.println("Exit value is : " + exitValue);
} catch (IOException ex) {
Logger.getLogger(ThreadA.class.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadA.class.getName()).log(Level.SEVERE, null, ex);
}
}
}

其他 3 种类型的线程只是将 Process 对象作为参数,因此它们为它们获取正确的流,并在它们的运行方法中打印出它们从流中读取的内容(用于输入/错误,显然不是用于输出)。

在主类中,我们有以下内容:

public static void main(String[] args) {
String[] listOfCommands = null;
MainFrame frame = new MainFrame();
SwingUtilities.invokeLater(()->{
frame.setVisible(true); 
});
//suppose we initialize list with many different command
for (String string : listOfCommands) {
new ThreadA(string,frame).start();
}
}

现在,假设在错误流线程上读取的某一行上,我希望它在传递给它的 Frame 容器上触发更新(图形 g)或 repaint() 方法。我也希望在输入流线程上使用相同类型的逻辑。关于这个特定的例子,我有几个问题(请注意,代码部分可能存在问题,我对它背后的逻辑和实际发生的事情更感兴趣):

  1. 在每个新线程中创建的每个进程都有自己的虚拟空间地址吗?

  2. 进程中包含哪些线程?既然已知每个进程都有自己的线程,那么在上面的例子中,进程中包含哪些线程?

  3. 由于代码的制作方式,上下文切换何时发生?在流线程内部,它将在哪里调用框架容器中的某个方法?

  4. 每个进程是否表示应用程序的一个子进程?在这种情况下,这是否意味着每个进程都是作为 java 进程的子进程创建的?

  5. 如果每个进程
  6. 确实是一个子进程,这是否意味着上下文切换仅限于线程上下文,并且每个不同进程中的所有这些线程实际上只执行线程上下文切换?

如果我的问题已经有了答案,请将我链接到它们。我已经阅读了与此相关的问题和答案,但是我找不到有关在新线程上运行多个进程时会发生什么的解释。

1)在每个新线程中创建的每个进程都有自己的虚拟空间地址吗?

这取决于操作系统,但通常是的。 当你执行一个新的Process时,这将在一个全新的地址空间中运行。 对于大多数~unix变体(Linux,OSX)都是如此。

2) 进程中包含哪些线程?既然已知每个进程都有自己的线程,那么在上面的例子中,进程中包含哪些线程?

这是一个不太有意义的奇怪问题。 Java进程有自己的线程。 当您的代码调用Runtime.getRuntime().exec(command)这会启动另一个进程,该进程至少具有 1 个线程,但可能有许多线程,这些线程与启动它的进程完全分开。

Processjavadocs 在某种程度上暗示了这一点:

不要求由Process对象表示的进程相对于拥有Process对象的 Java 进程异步或并发执行。

翻译:进程在后台运行,与启动它的 java 进程分开运行。

3)由于代码的制作方式,上下文切换何时发生?在流线程内部,它将在哪里调用框架容器中的某个方法?

这也说不通。 如果有足够的处理器,则上下文切换实际上可能不会发生,新进程可能只是在启动它的另一个处理器中运行。

也许 Java 进程正在执行大量 IO,而另一个进程是 CPU 密集型的,因此 Java 进程立即被切换掉。 也许 Java 进程将继续运行,新进程还需要一段时间才能从操作系统获得时间片。 在哪个处理器上运行哪个线程以及何时切换当前正在运行的线程取决于操作系统,并且高度依赖于每个进程正在执行的操作以及硬件上正在发生的其他操作。

4) 每个进程是否代表应用程序的一个子进程?在这种情况下,这是否意味着每个进程都是作为 java 进程的子进程创建的?

这也取决于操作系统。 在大多数~unix变体(Linux,OSX)中,有一个父进程的概念。 就像你的 shell 是/bin/ls命令的父级一样,是的,Java 进程将是它创建的进程的父级。 由操作系统决定成为"父母"意味着什么。

5)如果每个进程确实是一个子进程,这是否意味着上下文切换仅限于线程上下文,并且每个不同进程中的所有这些线程实际上只执行线程上下文切换?

这个问题也不是很正确,任何答案都高度依赖于操作系统。 通常,子/父关系与上下文切换无关。 进程优先级可能会影响上下文切换,但子进程和父进程通常具有相同的进程优先级。 这意味着来自 Java 进程的所有线程都将在操作系统中与其创建的任何进程以及已在运行的任何其他进程竞争。

我不能 100% 确定"线程"和进程上下文切换之间的区别,或者是否有任何区别。 线程或整个进程是否从处理器中切换出来,很大程度上取决于操作系统内部和硬件上发生的争用级别。

最新更新