Javaから外部プログラムを実行する際にプロセスを管理するjava.lang.Processクラスのソースコードを見てみよう。標準入出力とエラー出力へのStreamや,終了コードを返すexitValue()メソッド,プロセスを終了させるdestroy()メソッドは抽象メソッドとなっている。
/*
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.io.*;
import java.lang.ProcessBuilder.Redirect;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public abstract class Process {
public Process() {}
public abstract OutputStream getOutputStream();
public abstract InputStream getInputStream();
public abstract InputStream getErrorStream();
public abstract int waitFor() throws InterruptedException;
public boolean waitFor(long timeout, TimeUnit unit)
throws InterruptedException
{
long remainingNanos = unit.toNanos(timeout); // throw NPE before other conditions
if (hasExited())
return true;
if (timeout <= 0)
return false;
long deadline = System.nanoTime() + remainingNanos;
do {
Thread.sleep(Math.min(TimeUnit.NANOSECONDS.toMillis(remainingNanos) + 1, 100));
if (hasExited())
return true;
remainingNanos = deadline – System.nanoTime();
} while (remainingNanos > 0);
return false;
}
public abstract int exitValue();
public abstract void destroy();
public Process destroyForcibly() {
destroy();
return this;
}
public boolean supportsNormalTermination() {
throw new UnsupportedOperationException(this.getClass()
+ ".supportsNormalTermination() not supported" );
}
public boolean isAlive() {
return !hasExited();
}
private boolean hasExited() {
try {
exitValue();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
}
public long pid() {
return toHandle().pid();
}
public CompletableFuture<Process> onExit() {
return CompletableFuture.supplyAsync(this::waitForInternal);
}
private Process waitForInternal() {
boolean interrupted = false;
while (true) {
try {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
@Override
public boolean block() throws InterruptedException {
waitFor();
return true;
}
@Override
public boolean isReleasable() {
return !isAlive();
}
});
break;
} catch (InterruptedException x) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return this;
}
public ProcessHandle toHandle() {
throw new UnsupportedOperationException(this.getClass()
+ ".toHandle() not supported");
}
public ProcessHandle.Info info() {
return toHandle().info();
}
public Stream<ProcessHandle> children() {
return toHandle().children();
}
public Stream<ProcessHandle> descendants() {
return toHandle().descendants();
}
static class PipeInputStream extends FileInputStream {
PipeInputStream(FileDescriptor fd) {
super(fd);
}
@Override
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(2048, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n – remaining;
}
}
}
* Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.lang;
import java.io.*;
import java.lang.ProcessBuilder.Redirect;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
public abstract class Process {
public Process() {}
public abstract OutputStream getOutputStream();
public abstract InputStream getInputStream();
public abstract InputStream getErrorStream();
public abstract int waitFor() throws InterruptedException;
public boolean waitFor(long timeout, TimeUnit unit)
throws InterruptedException
{
long remainingNanos = unit.toNanos(timeout); // throw NPE before other conditions
if (hasExited())
return true;
if (timeout <= 0)
return false;
long deadline = System.nanoTime() + remainingNanos;
do {
Thread.sleep(Math.min(TimeUnit.NANOSECONDS.toMillis(remainingNanos) + 1, 100));
if (hasExited())
return true;
remainingNanos = deadline – System.nanoTime();
} while (remainingNanos > 0);
return false;
}
public abstract int exitValue();
public abstract void destroy();
public Process destroyForcibly() {
destroy();
return this;
}
public boolean supportsNormalTermination() {
throw new UnsupportedOperationException(this.getClass()
+ ".supportsNormalTermination() not supported" );
}
public boolean isAlive() {
return !hasExited();
}
private boolean hasExited() {
try {
exitValue();
return true;
} catch (IllegalThreadStateException e) {
return false;
}
}
public long pid() {
return toHandle().pid();
}
public CompletableFuture<Process> onExit() {
return CompletableFuture.supplyAsync(this::waitForInternal);
}
private Process waitForInternal() {
boolean interrupted = false;
while (true) {
try {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
@Override
public boolean block() throws InterruptedException {
waitFor();
return true;
}
@Override
public boolean isReleasable() {
return !isAlive();
}
});
break;
} catch (InterruptedException x) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return this;
}
public ProcessHandle toHandle() {
throw new UnsupportedOperationException(this.getClass()
+ ".toHandle() not supported");
}
public ProcessHandle.Info info() {
return toHandle().info();
}
public Stream<ProcessHandle> children() {
return toHandle().children();
}
public Stream<ProcessHandle> descendants() {
return toHandle().descendants();
}
static class PipeInputStream extends FileInputStream {
PipeInputStream(FileDescriptor fd) {
super(fd);
}
@Override
public long skip(long n) throws IOException {
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(2048, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n – remaining;
}
}
}