Java 为什么在使用多线程appraoch后,我的GUI仍然冻结?
我已经使用基于MVC的java创建了一个基于GUI的应用程序。我的应用程序的主要任务是从互联网上获取一些数据并开始解析它 为了从internet获取数据,我使用以下类:Java 为什么在使用多线程appraoch后,我的GUI仍然冻结?,java,multithreading,swing,Java,Multithreading,Swing,我已经使用基于MVC的java创建了一个基于GUI的应用程序。我的应用程序的主要任务是从互联网上获取一些数据并开始解析它 为了从internet获取数据,我使用以下类: public class WebReader implements Runnable { WebRecordResult WRResult = new WebRecordResult (); private void getData(args){ . . .
public class WebReader implements Runnable {
WebRecordResult WRResult = new WebRecordResult ();
private void getData(args){
.
.
.
setResult(result);
}
public void run() {
getData(args);
WRResult.setResult(getResult());
}
}
public class WebReaderResult {
private AtomicReference<String> result = new AtomicReference<>("");
public String getResult() {
return result.get();
}
public void setResult(String s) {
result.set(s);
}
}
公共类WebReader实现可运行{
WebRecordResult WRResult=新的WebRecordResult();
私有void getData(args){
.
.
.
setResult(result);
}
公开募捐{
获取数据(args);
WRResult.setResult(getResult());
}
}
公共类WebReaderResult{
私有原子引用结果=新原子引用(“”);
公共字符串getResult(){
返回result.get();
}
公共void setResult(字符串s){
结果集(s);
}
}
在我的控制器中,我创建了如下内容:
WebReaderResult wrr = new WebReaderResult();
ExecutorService executor = Executors.newSingleThreadExecutor();
WebReader wr =new WebReader(args);
Future<?> f1 = executor.submit(wr);
executor.shutdown();
try {
f1.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
wrr.getResult();
WebReaderResult wrr=new WebReaderResult();
ExecutorService executor=Executors.newSingleThreadExecutor();
WebReader wr=新的WebReader(args);
未来f1=执行人提交(wr);
executor.shutdown();
试一试{
f1.get();
}捕获(中断异常|执行异常e){
e、 printStackTrace();
}
wrr.getResult();
使用此代码后,我的GUI仍然会冻结,直到数据可用为止。我不希望我的GUI被冻结。我该怎么办
注意:我的GUI是swing行
f1.get();
阻塞,直到线程执行完毕。如果在UI线程中执行这一行,UI当然会冻结。但你对结果做了什么?如果没有更具体的代码,就很难给出问题的正确解决方案
**编辑**
控制器应该在自己的线程中执行和处理任务,并且应该与UI完全分离(对于适当的MVC模型)。由于您的代码中缺少信息(args
,等等),示例如下:
结果
最后一个编辑没有第一个示例那么清晰,但是SwingWorker
类确实提供了您所需要的内容。现在,您只需使用WebReader
类(即通过调用wr.run();
在doInBackground
中,或通过其他方式)在doInBackground
和done
中委托处理。无论如何,我相信你现在有很多事情要做
f1.get();
阻塞,直到线程执行完毕。如果在UI线程中执行这一行,UI当然会冻结。但你对结果做了什么?如果没有更具体的代码,就很难给出问题的正确解决方案
**编辑**
控制器应该在自己的线程中执行和处理任务,并且应该与UI完全分离(对于适当的MVC模型)。由于您的代码中缺少信息(args
,等等),示例如下:
结果
最后一个编辑没有第一个示例那么清晰,但是SwingWorker
类确实提供了您所需要的内容。现在,您只需使用WebReader
类(即通过调用wr.run();
在doInBackground
中,或通过其他方式)在doInBackground
和done
中委托处理。无论如何,我相信你现在有很多事情要做
我该怎么办
阅读文档。:)
严肃地说:
Future#get()
上的JavaDoc这样说(我强调):
根据需要等待计算完成,然后检索其结果
因此,您可以偶尔尝试调用f1.isDone()
,直到它返回true,在这种情况下,您可以调用get()
我该怎么办
阅读文档。:)
严肃地说:
Future#get()
上的JavaDoc这样说(我强调):
根据需要等待计算完成,然后检索其结果
因此,您可以偶尔尝试调用f1.isDone()
,直到它返回true,在这种情况下,您可以调用get()
代码f1.get()是一个阻塞调用
1) 您应该将您的任务分解为粒度单位,然后可能使用多个线程
2) 另外,使用回调机制而不是阻塞,您的任务应该接受一个完成侦听器并通知感兴趣的观察者任务完成,而不是进行阻塞调用。代码f1.get()是一个阻塞调用
1) 您应该将您的任务分解为粒度单位,然后可能使用多个线程
2) 另外,使用回调机制而不是阻塞,您的任务应该接受一个完成侦听器,并将任务完成情况通知感兴趣的观察者,而不是直接进行阻塞调用。来自官方javadocs(希望有一些有用的注释):
直接来自官方javadocs(希望有一些有用的评论):
Swing是单线程的。此线程的名称是事件调度线程(EDT)。当EDT中出现长时间运行的任务时,Swing应用程序将显示为冻结。为了避免这种情况,开发了一些实用程序,例如,
javax.swing.Timer
,javax.swing.SwingUtilities
,以及javax.swing.SwingWorker
。这些实用程序类确保修改Swing组件的任何操作都发生在EDT中,并且所有长时间运行的任务都发生在单独的线程(也称为后台线程)中
我建议您检查代码,并进一步研究哪些方法可以阻止线程(通常有文档记录)。之后,您可以通过在执行之前调用来检查这些方法是否出现在EDT中(这只是为了验证)。Swing是单线程的。此线程的名称是事件调度线程(EDT)。秋千
public abstract class WebTask<V> {
private WebReaderResult<V> res = new WebReaderResult<V>();
public WebReaderResult<V> getWebReaderResult() { return res; }
// handle task here
public abstract void handle();
}
public interface WebControllerCallback<V> {
public void done(V result);
}
public class WebController {
static private WebController instance;
static public WebController getInstance() {
if (null == instance) instance = new WebController();
return instance;
}
private ExecutorService executor = Executors.newSingleThreadExecutor();
public void handleTask(WebTask<?> t, WebControllerCallback<?> cb) {
executor.submit(new Runnable() {
public void run() {
t.handle();
cb.done(t.getWebReaderResult());
}
});
}
// other methods here
}
WebTask<String> task = new WebTask<String>() {
public void handle() {
WebReaderResult<String> result = getWebReaderResult();
// TODO : handle task and set result here result.getResult();
}
};
WebControllerCallback<String> callback = new WebControllerCallback<String>() {
public void done(String result) {
// TODO : update UI here from result value
}
};
WebController.getInstance().handleTask(task, callback);
new SwingWorker<String, Object>() {
@Override
protected String doInBackground() throws Exception {
// TODO : process result
return "some result";
}
protected void done() {
// TODO : refresh UI with the value of this.get(); which return a String
}
}.execute();
final JLabel label;
class MeaningOfLifeFinder extends SwingWorker<String, Object> {
@Override
public String doInBackground() {
// In here put the time consuming task
return findTheMeaningOfLife();
}
@Override
protected void done() {
// In here you'd be in UI thread, so you can actually render some text in a JLabel
try {
label.setText(get());
} catch (Exception ignore) {
}
}
}
(new MeaningOfLifeFinder()).execute();