对于我在一个单独的线程中运行计算有点“初学者”的问题感到抱歉,但我是一名C ++程序员。
处理大图像的计算成本高昂。在处理过程中,我希望能够使用我的软件(包括缩放操作)。
基于您的advice(程序返回数据 - 新图像) 已使用Callable接口:
public class B implements Callable<BufferedImage> {
private boolean c;
public B (boolean c) { this.c = c; }
public BufferedImage call() {
//Some operations
if (!c)
return null;
return new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
}
}
最初,创建执行程序服务:
ExecutorService exe = Executors.newFixedThreadPool(2);
B b = new B(true);
随后,将返回未来:
Future<BufferedImage> res = exe.submit(b);
最后,我们正在等待数据:
BufferedImage img = res.get();
不幸的是,这种实现方式并不像我预期的那样。虽然它在一个单独的线程中工作,但“响应”不会返回到主窗口,我无法在计算期间正确使用该软件。
因此,我尝试修改get()方法以便
try
{
BufferedImage img_proj = results.get(5, TimeUnit.MILLISECONDS);
}
catch (Exception e)
{
results.cancel(true);
e.printStackTrace();
}
但是,会出现TimeoutException。使用Runnable接口重写代码
public class B implements Runnable{
private boolean c;
private Runnable f;
public B (boolean c_, Runnable f_) { c = c_; f = f_;}
public BufferedImage process() {
//Some operations
BufferedImage output = null;
if (c) output = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
return output;
}
public void run() { process();}
}
与
一起Thread t = new Thread(b);
t.start ();
并且多任务处理按预期工作......
所以我的问题是:是否有必要另外“调整”或调整Callable接口,若然,怎么做?
答案 0 :(得分:2)
BufferedImage img = res.get();
这将阻止调用它的整个线程,直到计算出图像。 我假设您从主要或UI消息调度线程调用此函数,因此这就是您的UI被阻止的原因。
有几种方法可以解决这个问题:
isDone()
),然后执行操作。编辑:请求举例:
如果不了解完整的应用程序,或者至少是技术堆栈,很难给出一个很好的例子。
为了避免实现自己的接口(我将在我的应用程序中执行),我将重用Java的ChangeListener接口:
public void myButtonWasClicked() {
// all your stuff setting up executor...
// yes, this could be written much shorter with Java 8
ChangeListener myChangeListener = new ChangeListener() {
public void stateChanged(ChangeEvent evt) {
handleImageReady((BufferedImage)evt.getSource());
}
}
B b = new B(true, myChangeListener);
exe.submit(b);
}
你的B班延长:
public class B implements Callable<BufferedImage> {
private boolean c;
private ChangeListener listener;
public B (boolean c, ChangeListener listener) { this.c = c; this.listener = listener; }
public BufferedImage call() {
//Some operations
if (!c)
return null;
BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
// pass finished image to listener who will handle in the UI
listener.stateChanged(new ChangeEvent(img));
return img; // as nobody will consume this any longer, you could as well switch back to Runnable instead of Callable...
}
}
请注意,对于Java初学者来说,这是一个非常粗略的例子。有很多事情需要改进。例如,必须在某处关闭Executor服务......
答案 1 :(得分:2)
我建议您使用遗嘱执行人服务。
exe.submit(()->{
BufferedImage img = res.get();
uiRelatedMethod(img);
});
这样你的gui线程就不会阻塞,一旦缓冲的图像可用就会得到通知。当然你必须使用try / catch块。