1

我有一个从进程读取输出的 gobbler。

有一种情况是我们使用它的 PID 和外部 Windows taskkill 命令以编程方式终止进程。

它是一个 16 位 DOS 进程

我们 taskkill 因为它是一个 DOS 16 位进程,而 Process.destroyForcibly() 不适用于它,因为它位于 ntvdm 子系统中,最好的方法是获取 PID 并使用 'taskkill /T /F' 确实可以杀死它和任何孩子。

通常,我们的 DOS 16 位(或 32 位)进程没有问题。这个有一些文件锁。尤其重要的是,我们确保让操作系统释放锁是死的。

我们在杀戮之前和之后关闭所有流

在调用 taskkill 之前,我们尝试刷新和关闭 executor 中的所有流:in,out,err。调用 taskkill 后,我们通过重新关闭所有流来验证它们是否已关闭。

杀死后我们在所有 gobbler 上调用 Thread.interrupt()

现在,在操作系统中也确认了 kill 成功后,gobbler 仍在运行,它不响应 Thread.interrupt()。

我们甚至做了最后的 Thread.stop(喘气!)

此外,我们在它上面调用了 Thread.stop() ,它仍然在读取阶段等待......

因此,我们似乎无法停止 Processes 流上的 std-out 和 std-in gobbler。

我们知道 Thread.stop() 已被弃用。为了安全起见,我们捕获 ThreadDeath,然后清理所有监视器,然后重新抛出 ThreadDeath。然而, ThreadDeath 实际上从来没有被抛出,线程只是继续等待 inputStream.read .. 所以 Thread.stop 在这种情况下被弃用是一个有争议的问题......因为它没有做任何事情。就这样没有人会激怒我,这样我就可以问心无愧,我们已经从生产代码中删除了 Thread.stop() 。

线程不会中断我并不感到惊讶,因为这只发生在某些 InputStreams 上,并且并非所有读取都是不可破坏的。但令我惊讶的是,调用 Thread.stop 时 Thread 不会停止。

线程跟踪显示

线程跟踪显示 main-in 和 main-er(进程的两个输出)仍然在运行,即使在流关闭、线程被中断并且最后一次 Thread.stop 被调用之后。

任务已经死了,那么为什么要关心空闲的被阻塞的gobblers呢?

并不是我们在乎狼吞虎咽不会退出。但是我们讨厌运行的线程只会堆积并阻塞系统。这个特定的进程由网络服务器调用,然后......它可能相当于数百个处于阻塞状态的空闲线程在死进程上......

我们已经尝试以两种方式启动该过程,没有区别......

run(working, "cmd", "/c", "start", "/B", "/W", "/SEPARATE", "C:\\workspace\\dotest.exe");

run(working, "cmd", "/c", "C:\\workspace\\dotest.exe");

狼吞虎咽的读法是这样的:

try (final InputStream is = inputStream instanceof BufferedInputStream
                ? inputStream : new BufferedInputStream(inputStream, 1024 * 64);
                final BufferedReader br = new BufferedReader(new InputStreamReader(is, charset))) {

            String line;
            while ((line = br.readLine()) != null) {
                lineCount++;
                lines.add(line);
                if (Thread.interrupted()) {
                    Thread.currentThread().interrupt();
                    throw new InterruptedException();
                }
            }

            eofFound = true;   
        }

我们的销毁器在 taskkill 之后在 gobbler 线程上调用它:

int timeLimit = 500;
t.interrupt();
try {
    t.join(timeLimit);
    if (t.isAlive()) {
        t.stop();
        // we knows it's deprecated but we catch ThreadDeath
        // then clean any monitors and then rethrow ThreadDeath
        // But ThreadDeath never in fact gets thrown and the thread 
        // just keeps on waiting on inputStream.read .. 
        logger.warn("Thread stopped because it did not interrupt within {}ms: {}", timeLimit, t);
        if (t.isAlive()) {
            logger.warn("But thread is still alive! {}", t);
        }
    }
} catch (InterruptedException ie) {
    logger.info("Interrupted exception while waiting on join({}) with {}", timeLimit, t, ie);
} 

这是日志输出的片段:

59.841 [main] INFO  Destroying process '5952'

04.863 [main] WARN  Timeout waiting for 'Close java.io.BufferedInputStream@193932a' to finish
09.865 [main] WARN  Timeout waiting for 'Close java.io.FileInputStream@159f197' to finish

09.941 [main] DEBUG Executing [taskkill, /F, /PID, 5952].
10.243 [Thread-1] DEBUG SUCCESS: The process with PID 5952 has been terminated.
10.249 [main] DEBUG java.lang.ProcessImpl@620197 stopped with exit code 0
10.638 [main] INFO  Destroyed WindowsProcess(5952) forcefully in 738 ms.

11.188 [main] WARN  Thread stop called because it did not interrupt within 500ms: Thread[main-in,5,main]
11.188 [main] WARN  But thread is still alive! Thread[main-in,5,main]

11.689 [main] WARN  Thread stop because it did not interrupt within 500ms: Thread[main-err,5,main]
11.689 [main] WARN  But thread is still alive! Thread[main-err,5,main]

注意:在调用 taskkill 之前,进程 std-out 和 std-err 不会关闭。但是它们在 taskkill 之后手动关闭(因为成功而未显示在日志中)。

4

0 回答 0