我创造了一个有3个按钮的gui;连接,断开,中止。它们共享一个共同的SwingWorker线程,但由于某种原因线程永远不会完成,除非我点击中止按钮。
我还没有为断开按钮编写任何代码,但即便如此,这与我的问题无关。但是,为什么线程不会完成并打印Done
语句?我的猜测是它被卡在this.isCancelled()
循环中,但即使我这样做:
while(!this.isCancelled() || !this.isDone()) { // run loop }
它从不打印Done
一旦我点击中止按钮,线程就会完成。我正在使用isCancelled()
循环方法,因为这似乎是取消SwingWorker的推荐方法。
我只发布下面的相关代码,因为有数百行。
private class ButtonListener implements ActionListener {
private MyWorker worker;
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(connectButton)) {
worker = new MyWorker(activityTextArea);
worker.execute();
activityTextArea.append("Connect Button Pressed");
}
if(e.getSource().equals(disconnectButton)) {
activityTextArea.append("Disconnect Button Pressed");
}
if(e.getSource().equals(abortButton)) {
worker.cancel(true);
activityTextArea.append("Abort Button Pressed");
}
}
}
这是SwingWorker:
public class MyWorker extends SwingWorker<Void, Void> {
private JTextArea textArea;
MyWorker(JTextArea textArea) {
this.textArea = textArea;
}
private void startWorker() {
ProcessBuilder pb = new ProcessBuilder();
pb.command("aCmd");
Process p;
try {
p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while((line = br.readLine()) != null) {
textArea.append(line + "\n");
}
br.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected Void doInBackground() throws Exception {
// TODO Auto-generated method stub
boolean isFirstTime = true;
while(!this.isCancelled()) {
if(this.isDone()) { break; }
Thread.sleep(3000);
if(isFirstTime) {
startWorker();
isFirstTime = false;
}
}
return null;
}
@Override
protected void done() {
textArea.append("Done\n");
}
}
答案 0 :(得分:1)
这里的问题是在MyWorker.doInBackground()方法的实现中,isDone()用于控制循环的执行。这可能不是你打算如何使用doInBackground()。
要真正了解最新情况,我们需要考虑isDone()的行为和SwingWorker的生命周期。
对于这些场景,isDone()方法返回true:
SwingWorker LifeCycle
doInBackground()
前不久的时间段内调用done()
前的状态。在进入此状态之前,SwingWorker会分配一个工作线程,并且此工作线程执行doInBackground()。
doInBackground()
时,工作人员可以使用publish(..)
发送中间结果,然后通过事件调度线程(EDT)获取process(..)
。done()
在事件调度线程(EDT)中执行完毕后,转换到此状态。这是对象存在的剩余部分的最终状态。 了解上述工作流程非常重要,以便编写一个高性能且无故障的GUI。
根据上面的讨论,您可能希望将if(this.isDone()) { break; }
替换为反映预期处理完成情况的内容。
这里的另一个问题是你在由doInBackground()
调用的方法中进行与swing相关的活动。 textArea.append(line + "\n");
应该发生在Event Dispatch Thread中执行的process(..)方法中,如下所示:
public class MyWorker extends SwingWorker<Void, String> {
@Override
protected void process(List<String> chunks) {
for (String line : chunks) {
textArea.append(line + "\n"); // display intermediate results from publish()
}
}
private void startWorker() throws IOException {
ProcessBuilder pb = new ProcessBuilder("aCmd");
BufferedReader br = null;
try {
Process p = pb.start();
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
publish(line); // publish a chunk of result to process(..)
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) br.close();
}
}
参考:http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html