Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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
忽略/捕获子进程输出的最简单方法是从Java开始_Java_Multithreading_Subprocess - Fatal编程技术网

忽略/捕获子进程输出的最简单方法是从Java开始

忽略/捕获子进程输出的最简单方法是从Java开始,java,multithreading,subprocess,Java,Multithreading,Subprocess,java中的子进程非常昂贵。每个进程通常由多个线程支持 托管进程的线程(linux上的JDK1.6) 要读取以读取/打印/忽略输入流的线程 另一个线程读取/打印/忽略错误流 应用程序需要更多线程来执行超时、监视和终止子进程 子流程返回的业务逻辑线程holdintil 如果有一个线程聚焦子进程池来执行任务,那么线程的数量就会失控。因此,峰值时可能会有两倍以上的并发线程 在许多情况下,我们分叉一个进程只是因为没有人能够编写JNI来调用JDK中缺少的本机函数(例如chmod、ln、ls)、触发sh

java中的子进程非常昂贵。每个进程通常由多个线程支持

  • 托管进程的线程(linux上的JDK1.6)
  • 要读取以读取/打印/忽略输入流的线程
  • 另一个线程读取/打印/忽略错误流
  • 应用程序需要更多线程来执行超时、监视和终止子进程
  • 子流程返回的业务逻辑线程holdintil
如果有一个线程聚焦子进程池来执行任务,那么线程的数量就会失控。因此,峰值时可能会有两倍以上的并发线程

在许多情况下,我们分叉一个进程只是因为没有人能够编写JNI来调用JDK中缺少的本机函数(例如chmod、ln、ls)、触发shell脚本等等

可以保存一些线程,但应该运行一些线程来防止最坏的情况(inputstream上的缓冲区溢出)

如何将在Java中创建子进程的开销降至最低? 我考虑的是NIO流处理、合并和共享线程、降低后台线程优先级、重用进程。但我不知道它们是否可能。

要回答您的主题(我不理解描述),我假设您指的是shell子流程输出,请检查以下问题:

或者,您可以为在Unix下执行的命令关闭stdout和stderr:

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;
}
}
}
您还可以像中一样使用反射,从中获取NIO
FileChannel