我在eclipse插件Job
中运行一个执行长操作而没有太多输出的进程
如果用户请求它,我希望能够取消Job
,但是实现后,Job
不会停止,除非进程向输出流输出内容。
Process process = new ProcessBuilder(args).start();
Scanner scanner = new Scanner(
(new InputStreamReader(
process.getInputStream(), UTF_8_CHARSET)));
while (scanner.hasNext())
{
if (monitor.isCanceled() {
// user canceled the job, destroy the process to return
process.destroy();
break;
}
CONSOLE.getStream().println(scanner.nextLine());
}
try {
process.waitFor();
} catch (InterruptedException e) {
Activator.log(ERROR, e.getMessage(), e);
} finally {
process.destroyForcibly();
}
我是否有其他选项可以处理取消作业并更快地停止处理而不是等待换行?
答案 0 :(得分:4)
您应该将读取进程输出流的代码放入单独的线程中,并在主循环中等待进程以短暂超时结束,以便检查是否已取消。
所以主要代码如下:
Process process = new ProcessBuilder(args).start();
// Read standard output
new StreamConsumer(process.getInputStream()).start();
// You should also always read stderr
new StreamConsumer(process.getErrorStream()).start();
// Wait for process to end and check for cancel
while (!process.waitFor(100, TimeUnit.MILLISECONDS) {
if (monitor.isCanceled() {
// user canceled the job, destroy the process to return
process.destroy();
break;
}
}
StreamConsumer
就像:
public class StreamConsumer extends Thread
{
private final InputStream _input;
public StreamConsumer(final InputStream inputStream)
{
super();
_input = inputStream;
setDaemon(true);
}
@Override
public void run()
{
// TODO your code to read the stream
}
}
答案 1 :(得分:0)
而不是Scanner
使用提供BufferedReader
方法的ready
,这是一种非阻塞方式,告诉您是否有东西需要阅读而不是使用Scanner' s nextLine()
阻塞,直到实际读取某些内容。
小例子实现:
volatile static boolean stop = false;
public static void main(String[] args) throws InterruptedException
{
// Create a new thread that reads input from System.in
new Thread(() -> {
BufferedReader read = new BufferedReader(new InputStreamReader(System.in));
while (!stop)
{
try
{
// If there is something to read read it and print it
if (read.ready())
{
System.out.println(read.readLine());
}
}
catch (IOException e)
{
// Do some handling...
}
}
}).start();
// Wait 5 seconds then stop the thread by making the flag false.
Thread.sleep(5000);
stop = true;
}
您的旗帜显然随进程提供。带走的是使用非阻塞操作(如果实际存在要打印的东西,则查看)而不是使用阻塞操作。
答案 2 :(得分:0)
就我而言,我不知道该过程要进行多长时间。因此,超时是没有选择的。
我的替代解决方案是启动一个单独的监视线程,该线程正在监视IProgressMonitor
的状态。如果进度监视器处于取消状态,则正在执行的线程将被中断。
public static void startMonitorThread(IProgressMonitor monitor) {
final Thread runThread = Thread.currentThread();
new Thread("Monitor") {
@Override
public void run() {
while (runThread.isAlive() && !monitor.isCanceled()) {
try {
Thread.sleep(100);
} catch (InterruptedException exception) {
break;
}
}
if (runThread.isAlive()) {
runThread.interrupt();
}
};
}.start();
}
下一个代码片段显示了如何使用它的示例:
startMonitorThread(monitor);
final Process process = new ProcessBuilder("...").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
while (process.isAlive()) {
if (reader.ready()) {
final String line = reader.readLine();
// ... do something with line
} else {
Thread.sleep(10);
}
}
}
首先,我使用阻塞的扫描器犯了同样的错误(并且中断不起作用)。就像Ben提到的答案一样,最好使用BufferedReader
和非阻塞ready()
方法来检查是否还有更多内容可供阅读。