为什么主线程上的队列没有更新?



我正在打开一个PowerShell实例并通过系统发送命令。,我想将输出收集到一个队列中,这样我就可以在不干扰输入命令的情况下打印结果。但是,主线程上的队列没有填充,在主线程上休眠只能稍微修复这个问题。我想问题是没有同步队列,但我不确定如何。

package PWST;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
public class PWST {
public static void main(String[] args) {
try {
Scanner in = new Scanner(System.in);
System.out.print("33[H33[2J > "); // clear console.
String[] tokens = in.nextLine().split(",");
Queue<String> stdout = new LinkedList<>();
Queue<String> stderr = new LinkedList<>();
Process process = Runtime.getRuntime().exec("powershell.exe");
new Thread(new SPQ(process.getInputStream(), stdout)).start();
new Thread(new SPQ(process.getErrorStream(), stderr)).start();
PrintWriter out = new PrintWriter(process.getOutputStream());

for (String token : tokens) // parse commands (will be expanded to continuously ask for input)
out.println(token.strip());
// print powershell output after:
System.out.println(stdout);
System.out.println(stderr);
in.close();
out.close();
process.waitFor();
System.out.println("Shell link closed");

} catch (Exception e) { e.printStackTrace(); }
}
}
package PWST;
import java.io.InputStream;
import java.util.Queue;
class SPQ implements Runnable {
private Queue<String> queue;
private InputStream istrm;
public SPQ(InputStream istrm, Queue<String> queue) {
this.istrm = istrm;
this.queue = queue;
}
public void run() {
try {
final byte[] buffer = new byte[1024];
for (int length = 0; (length = istrm.read(buffer)) != -1; )
queue.add(new String(buffer, 0, length)); // store output in queue

} catch (Exception e) { e.printStackTrace(); }
}
}

至少有两个问题。

首先,关闭ScannerPrintWriter也将关闭它们的不死流(在这种情况下,Scanner正在从stdin读取)。这是不希望的,因为,首先,您永远不想关闭stdin流,其次,进程可能还没有完成对流的处理,但更重要的是,我会非常小心地关闭不是您自己创建的流,只是说。

第二个问题是,在SPQ实际有时间处理输出之前,您试图读取输出(流),例如,如果我调整您的代码并使用…

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Queue;
public final class Main {
public static void main(String[] args) throws IOException, InterruptedException {
new Main();
}
public Main() throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("bash", "-c", "ls");
pb.redirectErrorStream(true);
System.out.println(">> Start process");
Process p = pb.start();
Queue<String> stdout = new LinkedList<>();
Thread thread = new Thread(new SPQ(p.getInputStream(), stdout));
System.out.println(">> Start thread");
thread.start();
System.out.println(">> Waiting for process to exit");
p.waitFor();
System.out.println("<< Process has exited");
System.out.println(stdout);
}
class SPQ implements Runnable {
private Queue<String> queue;
private InputStream istrm;
public SPQ(InputStream istrm, Queue<String> queue) {
this.istrm = istrm;
this.queue = queue;
}
public void run() {
System.out.println(">> Started reading stream");
try {
final byte[] buffer = new byte[1024];
for (int length = 0; (length = istrm.read(buffer)) != -1;) {
queue.add(new String(buffer, 0, length)); // store output in queue
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("<< Done reading stream");
}
}
}

它将输出…

>> Start process
>> Start thread
>> Waiting for process to exit
<< Process has exited
>> Started reading stream
[]
<< Done reading stream

如您所见,在线程完成处理流之前,我已经打印了Queue的内容。

如果我在p.waitFor();之后添加thread.join();,它将打印…

>> Start process
>> Start thread
>> Waiting for process to exit
>> Started reading stream
<< Done reading stream
<< Process has exited
[contents
of
my
working
directory
which
is
not
very
interesting]
<标题>运行的例子…
import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.Queue;
public final class Main {
public static void main(String[] args) throws IOException, InterruptedException {
new Main();
}
public Main() throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("bash", "-c", "ls");
pb.redirectErrorStream(true);
System.out.println(">> Start process");
Process p = pb.start();
Queue<String> stdout = new LinkedList<>();
Thread thread = new Thread(new SPQ(p.getInputStream(), stdout));
System.out.println(">> Start thread");
thread.start();
System.out.println(">> Waiting for process to exit");
p.waitFor();
thread.join();
System.out.println("<< Process has exited");
System.out.println(stdout);
}
class SPQ implements Runnable {
private Queue<String> queue;
private InputStream istrm;
public SPQ(InputStream istrm, Queue<String> queue) {
this.istrm = istrm;
this.queue = queue;
}
public void run() {
System.out.println(">> Started reading stream");
try {
final byte[] buffer = new byte[1024];
for (int length = 0; (length = istrm.read(buffer)) != -1;) {
queue.add(new String(buffer, 0, length)); // store output in queue
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("<< Done reading stream");
}
}
}

请注意-我没有运行Windows,所以我不能测试Powershell,我已经做了最小的例子,我能想到的,所以我不写内容到流,但从概念上讲,这解决了问题,你似乎有

最新更新