Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/389.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
线程启动的运行进程赢得';t销毁(Java)_Java_Multithreading_Process_Destroy - Fatal编程技术网

线程启动的运行进程赢得';t销毁(Java)

线程启动的运行进程赢得';t销毁(Java),java,multithreading,process,destroy,Java,Multithreading,Process,Destroy,启动多个线程并让每个exec()然后销毁()一个正在运行的java进程会导致某些进程没有被销毁,并且在程序退出后仍在运行。下面是一些重现问题的代码。我注意到,启动的线程越多,保持活动状态的进程就越多。destroy()之前的睡眠越多,进程存活的时间就越少。(我以InfiniteLop为例,任何运行的进程都可以做到。) 编辑:错误已报告给Oracle,等待答复。请随意分享关于该主题的任何知识/实验 for(int i = 0; i < 100; i++) { new Thread(new

启动多个线程并让每个exec()然后销毁()一个正在运行的java进程会导致某些进程没有被销毁,并且在程序退出后仍在运行。下面是一些重现问题的代码。我注意到,启动的线程越多,保持活动状态的进程就越多。destroy()之前的睡眠越多,进程存活的时间就越少。(我以InfiniteLop为例,任何运行的进程都可以做到。)

编辑:错误已报告给Oracle,等待答复。请随意分享关于该主题的任何知识/实验

for(int i = 0; i < 100; i++)
{
  new Thread(new Runnable()
  {
    public void run()
    {
      try
      {
        Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
        Thread.sleep(1);
        p.destroy();
      }catch(IOException | InterruptedException e){e.printStackTrace();}                    
    }
  }).start();
}
for(int i=0;i<100;i++)
{
新线程(newrunnable())
{
公开募捐
{
尝试
{
进程p=Runtime.getRuntime().exec(新字符串[]{“java”,“InfiniteLop”});
睡眠(1);
p、 破坏();
}catch(IOException | interruptedeexception e){e.printStackTrace();}
}
}).start();
}

我相信,根据,操作系统会生成一个不同的进程来响应此调用。这个进程的生命周期独立于Java程序和其中的线程,因此您希望它在程序退出后继续运行。我刚在我的机器上试用过,它似乎能按预期工作:

import java.io.*;

class Mp {
public static void main(String []args) {
    for(int i = 0; i < 100; i++) {
        new Thread(new Runnable() {
            public void run() {
                try {
                    System.out.println("1");
                    Process p = Runtime.getRuntime().exec
                        (new String[]{"notepad", ""});
                    System.out.println("2");
                    Thread.sleep(5);
                    System.out.println("3");
                    p.destroy();
                    System.out.println("4");
                }
                catch(IOException | InterruptedException e) {
                    e.printStackTrace();
                }                    
            }
        }).start();
    }
}
}
import java.io.*;
Mp级{
公共静态void main(字符串[]args){
对于(int i=0;i<100;i++){
新线程(newrunnable()){
公开募捐{
试一试{
系统输出打印项次(“1”);
进程p=Runtime.getRuntime().exec
(新字符串[]{“记事本”,“记事本”);
系统输出打印项次(“2”);
睡眠(5);
系统输出打印项次(“3”);
p、 破坏();
系统输出打印项次(“4”);
}
捕获(IOException | InterruptedException e){
e、 printStackTrace();
}                    
}
}).start();
}
}
}

如果子进程向stdout或stderr写入任何内容(有意或无意),则可能会导致问题:

“因为某些本机平台仅为用户提供有限的缓冲区大小 标准输入和输出流,未能及时写入输入 流或读取子流程的输出流可能会导致 子进程阻塞,甚至死锁。“

资料来源:


如果您需要使用Runtime.exec(),整篇文章值得一读。

这不是答案;我张贴完整的来源,为我自己的尝试重新创建这个问题,根据讨论中的问题评论

我无法在Ubuntu 12.04上重现这个问题;OpenJDK 6b_27(但请参见下文)

ProcessTest.java:

import java.io.*;

public class ProcessTest {

    public static final void main (String[] args) throws Exception {

        for(int i = 0; i < 100; i++) {
            new Thread(new Runnable() 
                {
                    public void run() {
                        try {
                            Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
                            Thread.sleep(1);
                            p.destroy();
                        }catch(IOException e) {
                            System.err.println("exception: " + e.getMessage());
                        } catch(InterruptedException e){
                            System.err.println("exception: " + e.getMessage());
                        }                    
                    }
                }).start();
        }

    }

}
我无法重现JVM终止后进程仍在运行的问题。然而,如果我在启动线程之后但从主线程返回之前在主线程中添加一个长延迟,我确实会看到大约十几个运行的java进程仍然存在(尽管它们在主程序终止时被终止)

更新:

我只是让它在终止后留下大约5个进程运行。这并不总是发生。奇怪的我也想知道更多关于这方面的事情。我有一种预感,它与太快地破坏进程或某种种族状况有关;可能是java做了一些事情,或者创建了一个新的进程,如果在错误的时间调用过快,destroy()将无法处理

我发现了一个旧bug(但它没有被标记为已解决),指出如果一个进程生成子进程,它们可能不会被destroy()杀死。您正在使用哪个版本的JDK

这里还有一个类似的问题:如果我只是给你的生活增添了困惑,我想向你道歉,我实际上没有太多地使用这个过程,也不熟悉其中的怪癖。希望其他人能给出一个明确的答案。它似乎不能很好地处理子流程,我认为java会产生一些问题。这就是我所能得到的。

使用
p.waitFor()
p.destroy()之前,


这将确保前一个过程的完成。我认为p.destroy命令比
exec()
命令执行操作更快地被调用。因此,它变得毫无用处

时间运行时之间存在争用条件。exec启动一个新线程来启动一个进程,当您告诉该进程销毁自身时

我在linux机器上,所以我将使用UNIXProcess.class文件来说明

Runtime.exec(…)
将创建一个新的
ProcessBuilder
并启动它,它将在unix计算机上创建一个新的
UNIXProcess
实例。在
UNIXProcess
的构造函数中,有一段代码实际上在后台(分叉)线程中执行进程:

请注意,后台线程设置字段
pid
,这是UNIX进程id。这将被
destroy()
用来告诉操作系统要终止哪个进程

由于无法确保在调用
destroy()
时此后台线程已运行,因此我们可以尝试在进程运行之前终止进程,或者在设置pid字段之前终止进程;pid未初始化,因此为0。因此,我认为过早调用destroy相当于一个
kill-90

UNIXProcess
destroy()
中甚至有一条注释暗指这一点,但只考虑在进程完成后调用destroy,而不是在进程启动之前调用:

// There is a risk that pid will be recycled, causing us to
// kill the wrong process!  So we only terminate processes
// that appear to still be running.  Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.

pid字段甚至没有标记为volatile,因此我们可能无法始终看到最新的值。

这只是因为在线程执行销毁调用之前,主程序终止,所有相关的线程都将被删除
java.security.AccessController.doPrivileged(
            new java.security.PrivilegedAction() {
    public Object run() {
    Thread t = new Thread("process reaper") {
        public void run() {
                    try {
                        pid = forkAndExec(prog,
                      argBlock, argc,
                      envBlock, envc,
                      dir,
                      redirectErrorStream,
                      stdin_fd, stdout_fd, stderr_fd);
                    } catch (IOException e) {
                        gate.setException(e); /*remember to rethrow later*/
                        gate.exit();
                        return;
                    }
                    java.security.AccessController.doPrivileged(
                    new java.security.PrivilegedAction() {
                        public Object run() {
                        stdin_stream = new BufferedOutputStream(new
                                                FileOutputStream(stdin_fd));
                        stdout_stream = new BufferedInputStream(new
                                                FileInputStream(stdout_fd));
                        stderr_stream = new FileInputStream(stderr_fd);
                        return null;
                    }
                    });
                    gate.exit(); /* exit from constructor */
        int res = waitForProcessExit(pid);
        synchronized (UNIXProcess.this) {
            hasExited = true;
            exitcode = res;
            UNIXProcess.this.notifyAll();
        }
        }
    };
            t.setDaemon(true);
            t.start();
    return null;
    }
});
// There is a risk that pid will be recycled, causing us to
// kill the wrong process!  So we only terminate processes
// that appear to still be running.  Even with this check,
// there is an unavoidable race condition here, but the window
// is very small, and OSes try hard to not recycle pids too
// soon, so this is quite safe.
public class ProcessTest {

public static final void main (String[] args) throws Exception {

    for(int i = 0; i < 100; i++) {
        new Thread(new Runnable()
            {
                public void run() {
                    try {
                        Process p = Runtime.getRuntime().exec(new String[]{"java", "InfiniteLoop"});
                        Thread.sleep(1);
                        p.destroy();
                        System.out.println("Destroyed");
                    }catch(IOException e) {
                        System.err.println("exception: " + e.getMessage());
                    } catch(InterruptedException e){
                        System.err.println("exception: " + e.getMessage());
                    }
                }
            }).start();
    }


    Thread.sleep(1000);

}
Process process = processBuilder(ForeverRunningMain.class).start()
long endTime = System.currentTimeMillis() + TIMEOUT_MS; 
while (System.currentTimeMillis() < endTime) {
    sleep(50);
}
process.destroy();
Thread.sleep(300);
process.destroy();