忽略/捕获子进程输出的最简单方法是从Java开始
java中的子进程非常昂贵。每个进程通常由多个线程支持忽略/捕获子进程输出的最简单方法是从Java开始,java,multithreading,subprocess,Java,Multithreading,Subprocess,java中的子进程非常昂贵。每个进程通常由多个线程支持 托管进程的线程(linux上的JDK1.6) 要读取以读取/打印/忽略输入流的线程 另一个线程读取/打印/忽略错误流 应用程序需要更多线程来执行超时、监视和终止子进程 子流程返回的业务逻辑线程holdintil 如果有一个线程聚焦子进程池来执行任务,那么线程的数量就会失控。因此,峰值时可能会有两倍以上的并发线程 在许多情况下,我们分叉一个进程只是因为没有人能够编写JNI来调用JDK中缺少的本机函数(例如chmod、ln、ls)、触发sh
- 托管进程的线程(linux上的JDK1.6)
- 要读取以读取/打印/忽略输入流的线程
- 另一个线程读取/打印/忽略错误流
- 应用程序需要更多线程来执行超时、监视和终止子进程
- 子流程返回的业务逻辑线程holdintil
command > /dev/null 2>&1
既然您提到了,
chmod
,ln
,ls
,以及shell脚本,听起来您好像在尝试使用Java进行shell编程。如果是这样,您可能需要考虑一种更适合于该任务的不同语言,如Python、Perl或Bash。尽管可以用Java创建子流程,通过它们的标准输入/输出/错误流等与它们交互,但我认为您会发现脚本语言使此类代码比Java更不冗长,更易于维护。nio不起作用,因为当您创建一个流程时,您只能访问输出流,不是频道
您可以让一个线程读取多个输入流
大概
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class MultiSwallower implements Runnable {
private List<InputStream> streams = new CopyOnWriteArrayList<InputStream>();
public void addStream(InputStream s) {
streams.add(s);
}
public void removeStream(InputStream s) {
streams.remove(s);
}
public void run() {
byte[] buffer = new byte[1024];
while(true) {
boolean sleep = true;
for(InputStream s : streams) {
//available tells you how many bytes you can read without blocking
while(s.available() > 0) {
//do what you want with the output here
s.read(buffer, 0, Math.min(s.available(), 1024));
sleep = false;
}
}
if(sleep) {
//if nothing is available now
//sleep
Thread.sleep(50);
}
}
}
}
class ProcessWatcher implements Runnable {
private MultiSwallower swallower = new MultiSwallower();
private ConcurrentMap<Process, InputStream> proceses = new ConcurrentHashMap<Process, InputStream>();
public ProcessWatcher() {
}
public void startThreads() {
new Thread(this).start();
new Thread(swallower).start();
}
public void addProcess(Process p) {
swallower.add(p.getInputStream());
proceses.put(p, p.getInputStream());
}
@Override
public void run() {
while(true) {
for(Process p : proceses.keySet()) {
try {
//will throw if the process has not completed
p.exitValue();
InputStream s = proceses.remove(p);
swallower.removeStream(s);
} catch(IllegalThreadStateException e) {
//process not completed, ignore
}
}
//wait before checking again
Thread.sleep(50);
}
}
}
import java.io.InputStream;
导入java.util.List;
导入java.util.concurrent.CopyOnWriteArrayList;
类MultiWallower实现可运行{
私有列表流=新CopyOnWriteArrayList();
公共void addStream(输入流){
流。添加(s);
}
public void removeStream(输入流){
流。移除(s);
}
公开募捐{
字节[]缓冲区=新字节[1024];
while(true){
布尔睡眠=真;
用于(输入流:流){
//available告诉您在不阻塞的情况下可以读取多少字节
而(s.available()>0){
//对此处的输出执行所需操作
s、 读取(缓冲区,0,Math.min(s.available(),1024));
睡眠=假;
}
}
如果(睡眠){
//如果现在什么都没有
//睡眠
睡眠(50);
}
}
}
}
您可以将上面的类与另一个等待进程完成的类配对,例如
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
class MultiSwallower implements Runnable {
private List<InputStream> streams = new CopyOnWriteArrayList<InputStream>();
public void addStream(InputStream s) {
streams.add(s);
}
public void removeStream(InputStream s) {
streams.remove(s);
}
public void run() {
byte[] buffer = new byte[1024];
while(true) {
boolean sleep = true;
for(InputStream s : streams) {
//available tells you how many bytes you can read without blocking
while(s.available() > 0) {
//do what you want with the output here
s.read(buffer, 0, Math.min(s.available(), 1024));
sleep = false;
}
}
if(sleep) {
//if nothing is available now
//sleep
Thread.sleep(50);
}
}
}
}
class ProcessWatcher implements Runnable {
private MultiSwallower swallower = new MultiSwallower();
private ConcurrentMap<Process, InputStream> proceses = new ConcurrentHashMap<Process, InputStream>();
public ProcessWatcher() {
}
public void startThreads() {
new Thread(this).start();
new Thread(swallower).start();
}
public void addProcess(Process p) {
swallower.add(p.getInputStream());
proceses.put(p, p.getInputStream());
}
@Override
public void run() {
while(true) {
for(Process p : proceses.keySet()) {
try {
//will throw if the process has not completed
p.exitValue();
InputStream s = proceses.remove(p);
swallower.removeStream(s);
} catch(IllegalThreadStateException e) {
//process not completed, ignore
}
}
//wait before checking again
Thread.sleep(50);
}
}
}
类ProcessWatcher实现可运行{
专用多墙吞咽器=新的多墙吞咽器();
私有ConcurrentMap进程=新ConcurrentHashMap();
公共ProcessWatcher(){
}
public void startThreads(){
新线程(this.start();
新线程(吞咽器).start();
}
公共流程(流程p){
add(p.getInputStream());
process.put(p,p.getInputStream());
}
@凌驾
公开募捐{
while(true){
for(进程p:Process.keySet()){
试一试{
//如果进程尚未完成,将抛出
p、 exitValue();
InputStream s=process.remove(p);
吞咽器。移除味精;
}捕获(非法)
//进程未完成,忽略
}
}
//请等待,然后再检查
睡眠(50);
}
}
}
同样,如果使用ProcessBuilder.redirectErrorStream(true),则每个错误流不需要1个线程,也不需要1个线程来读取流程输入流,如果不向输入流写入任何内容,则可以忽略输入流 在java中运行子进程不需要任何额外的线程,尽管处理超时会使事情变得有点复杂:
import java.io.IOException;
import java.io.InputStream;
public class ProcessTest {
public static void main(String[] args) throws IOException {
long timeout = 10;
ProcessBuilder builder = new ProcessBuilder("cmd", "a.cmd");
builder.redirectErrorStream(true); // so we can ignore the error stream
Process process = builder.start();
InputStream out = process.getInputStream();
long endTime = System.currentTimeMillis() + timeout;
while (isAlive(process) && System.currentTimeMillis() < endTime) {
int n = out.available();
if (n > 0) {
// out.skip(n);
byte[] b = new byte[n];
out.read(b, 0, n);
System.out.println(new String(b, 0, n));
}
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
}
}
if (isAlive(process)) {
process.destroy();
System.out.println("timeout");
}
else {
System.out.println(process.exitValue());
}
}
public static boolean isAlive(Process p) {
try {
p.exitValue();
return false;
}
catch (IllegalThreadStateException e) {
return true;
}
}
}
import java.io.IOException;
导入java.io.InputStream;
公共类进程测试{
公共静态void main(字符串[]args)引发IOException{
长超时=10;
ProcessBuilder=newProcessBuilder(“cmd”、“a.cmd”);
redirectErrorStream(true);//因此我们可以忽略错误流
Process=builder.start();
InputStream out=process.getInputStream();
long-endTime=System.currentTimeMillis()+超时;
while(isAlive(进程)和&System.currentTimeMillis()0){
//out.skip(n);
字节[]b=新字节[n];
读出(b,0,n);
System.out.println(新字符串(b,0,n));
}
试一试{
睡眠(10);
}
捕捉(中断异常e){
}
}
if(isAlive(流程)){
process.destroy();
System.out.println(“超时”);
}
否则{
System.out.println(process.exitValue());
}
}
公共静态布尔isAlive(进程p){
试一试{
p、 exitValue();
返回false;
}
捕获(非法){
返回true;
}
}
}
您还可以像中一样使用反射,从中获取NIOFileChannel