InputStream到选择器的通道

时间:2014-01-28 23:35:28

标签: java nio

我搜索过高低,但无法找到关于NIO问题的最新,最新答案。

有没有办法从InputStream转换为Channel我可以使用Selector?似乎Channels.newChannel()是进行转换的唯一方法,但不提供AbstractSelectableChannel的实例,这正是我所需要的。

更具体地说,我想从子进程的stdoutstderr流中读取,而不是为每个流创建一个线程,而且似乎这是在纯Java中实现它的唯一方法。由于这些流使用管道来回传递I / O,我很惊讶.newChannel不会返回Pipe.SourceChannel,这是AbstractSelectableChannel的子类。

我正在使用Java 7(虽然如果8中有新功能,我仍然会很乐意回答)。

编辑:我也尝试将.newChannel()的结果投射到可选择的频道无效 - 它不是可选择的频道。

2 个答案:

答案 0 :(得分:3)

没有办法做你所要求的,但你不需要每个流一个线程。只需将流与为此目的提供的API合并,并读取当前线程中的输出。

答案 1 :(得分:0)

我遇到了同样的问题,但我可以将子进程的输出重定向到文件并稍后分析输出。您可以使用类似下面的代码,但它有一些缺点,应该添加一些代码。可以使用一些并发集合而不是锁。

import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class InputPrcocessSelector {

    final private Collection<Process> registeredProcesses = new HashSet<>();
    final private Lock registeredProcessesLock = new ReentrantLock();

    final private LinkedBlockingQueue<Process> readyProcesses = new LinkedBlockingQueue<>();

    final private ExecutorService executorService = Executors.newSingleThreadExecutor();

    final private static TimeUnit DEFAULT_TIME_UNIT = TimeUnit.MILLISECONDS;
    final private static int DEFAULT_TIMEOUT = 100;

    final private int timeOut;
    final private TimeUnit timeUnit;

    public InputPrcocessSelector() {
        this(DEFAULT_TIMEOUT, DEFAULT_TIME_UNIT);
    }

    public InputPrcocessSelector(int timeOut, TimeUnit timeUnit) {
        this.timeOut = timeOut;
        this.timeUnit = timeUnit;
        this.executorService.submit(new SelectorTask());
    }

    public boolean register(Process process) {
        try {
            registeredProcessesLock.lock();
            return registeredProcesses.add(process);
        } finally {
            registeredProcessesLock.unlock();
        }
    }

    public boolean unregister(Process process) {
        try {
            registeredProcessesLock.lock();
            return registeredProcesses.remove(process);
        } finally {
            registeredProcessesLock.unlock();
        }
    }

    public Collection<Process> select() throws InterruptedException {
        HashSet<Process> selectedInputs = new HashSet<>();

        Process firstProcess = readyProcesses.take();
        selectedInputs.add(firstProcess);

        Process nextProcess = null;
        while ((nextProcess = readyProcesses.poll()) != null) {
            selectedInputs.add(nextProcess);
        }

        return selectedInputs;
    }

    private class SelectorTask implements Runnable {
        public void run() {
            while (true) {
                try {
                    registeredProcessesLock.lock();

                    Iterator<Process> it = registeredProcesses.iterator();
                    while (it.hasNext()) {
                        Process p = it.next();
                        try {
                            int available = p.getInputStream().available();
                            if (available > 0)
                                readyProcesses.add(p);
                            if (p.isAlive() == false) {
                                System.err.println("Not alive");
                                it.remove();
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                    }

                } finally {
                    registeredProcessesLock.unlock();
                }

                try {
                    timeUnit.sleep(timeOut);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

}