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

Context switching in java concrete case

我向您提出了一个关于 java 中发生的线程、进程和上下文切换的问题。我已经阅读了与此知识相关的其他问题,但我希望有人澄清一些我不太了解的事情的某些方面。这方面我做了一个例子。

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

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 对象作为参数,以便它们为它们获取正确的流,并在它们的 运行 方法中打印出它们从流中读取的内容(对于 input/error, 显然不是为了输出).

主要 class 我们有以下内容:

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();
    }
}

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

  1. 在每个新线程中创建的每个进程是否都有自己的虚拟 space 地址?

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

  3. 由于代码的制作方式,什么时候发生上下文切换?在流线程中,它会在哪里调用框架容器中的某些方法?

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

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

如果我的问题已经有了答案,请 link 帮我解答。我已经阅读了与此相关的问题和答案,但我没有找到关于当您 运行 新线程上的多个进程时会发生什么的解释。

1) Does each process created in each of the new Threads has it's own virtual space address?

这是 OS 相关的,但通常是。当您执行新的 Process 时,此 运行 位于一个全新的地址 space 中。对于大多数 ~unix 变体(Linux、OSX)都是如此。

2) Which threads are contained within the process? Since it's known that each process has it's own threads, in the case above, which threads are contained within the processes?

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

Process javadocs:

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

There is no requirement that a process represented by a Process object execute asynchronously or concurrently with respect to the Java process that owns the Process object.

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

3) Due to how the code is made, when does context-switch happen? Inside the stream threads, where it will call some method in the frame container?

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

可能 Java 进程正在执行大量 IO,而另一个进程 CPU 密集,因此 Java 进程立即被关闭。也许 Java 进程会继续 运行 并且在新进程从 OS 获得时间片之前还需要一段时间。 运行 在哪个处理器上使用哪个线程以及何时切换当前 运行ning 线程取决于 OS 并且高度依赖于每个进程正在做什么以及正在发生的其他事情在硬件上。

4) Does each process represent a child-process of the application? In this case, does it mean each process is created as a child of the java process?

这也取决于 OS。在大多数 ~unix 变体(Linux、OSX)中,有一个父进程的概念。就像您的 shell 是 /bin/ls 命令的父级一样,是的,Java 进程将是它创建的进程的父级。 "parent" 的含义取决于 OS。

5) If each process is indeed a child-process, does it mean that context-switch is limited to thread-context and all those threads in each different process actually perform only thread-context-switching ?

这个问题也不太正确,任何答案都高度 OS 依赖。通常 child/parent 关系与上下文切换无关。进程优先级可以影响上下文切换,但通常子进程和父进程具有相同的进程优先级。这将意味着来自 Java 进程的所有线程将在 OS 中与它创建的任何进程以及已经 运行ning.

的任何其他进程竞争。

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