java具体案例

时间:2017-05-22 09:07:34

标签: java multithreading process threadpool

我找到了一个关于java中出现的线程,进程和上下文切换的问题。我已经阅读了有关这些知识的其他问题,但我希望有人澄清某些我不太了解的事情。我为这方面做了一个例子。

假设我们有一个带有命令的类,然后运行(在一个新的Thread中)给定的命令,并创建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对象作为参数,因此它们为它们获取正确的流,并且在它们的run方法中,它们打印出它们从流中读取的内容(对于输入/错误,显然不是输出)

在主课程中我们有以下内容:

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容器上触发更新(Graphics g)或repaint()方法,并传递给它。我也想在输入流线程上使用相同的逻辑。关于这个特定的例子我有几个问题(请注意,关于代码部分可能存在问题,我对它背后的逻辑以及实际发生的事情更感兴趣):

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

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

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

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

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

  6. 如果我的问题已经有了答案,请将我与他们联系起来。我已经阅读了与此相关的问题和答案,但现在我找到了解释当您在新线程上运行多个进程时会发生什么。

1 个答案:

答案 0 :(得分:2)

  

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

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

  

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

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

Process javadocs

对此有所暗示
  

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

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

  

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

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

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

  

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

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

  

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

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

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