【问题标题】:Context switching in java concrete casejava具体案例中的上下文切换
【发布时间】:2017-05-22 09:07:34
【问题描述】:

我向您提出了一个关于 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();
    }
}

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

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

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

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

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

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

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

【问题讨论】:

    标签: java multithreading process threadpool


    【解决方案1】:

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

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

    2) 进程中包含哪些线程?既然已知每个进程都有自己的线程,那么在上述情况下,进程中包含哪些线程?

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

    Process javadocs 暗示了这一点:

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

    翻译:进程在后台运行,独立于启动它的java进程。

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

    这也没有任何意义。如果您有足够多的处理器,则可能不会真正发生上下文切换,新进程可能只是在启动它的处理器的另一个处理器中运行。

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

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

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

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

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

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

    【讨论】:

    • 感谢您的回答!你清除了我脑海中的一些东西,我知道有些问题不太有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多