Java: вернуть результаты из Runnable
Предположим следующий упрощенный пример. Пусть B представляет класс, обрабатывающий некоторые растровые данные:
import java.awt.image.BufferedImage;
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();}
}
Метод process() может, но не может создавать выходной оценщик. Из-за вычислительных затрат процедура выполняется в отдельном потоке.
Пусть A представляет класс, внутри которого будет выполняться процедура. Он также содержит несколько шагов после обработки, ожидающих завершения потока:
import java.awt.image.BufferedImage;
public class A {
public A(){}
public void compute() {
boolean c = true;
B b = new B( c, new Runnable() {
public void run() {
//Post process, after the thread has been finished
BufferedImage img = ??? //Get resulting raster, how?
if (img != null) {
//Perform some steps
}
}
});
Thread t = new Thread(b);
t.start (); //Run procedure
}
}
Однако как получить результирующий растр, созданный с помощью метода process() из B "внутри" метода run() в A?
Избегайте модели, когда выходное изображение представляет элемент данных B вместе с
b.getImage();
Я прочитал пост о колбэках
Возвращаемое значение из Runnable
но как это реализовать здесь? Спасибо за вашу помощь и короткий пример.
2 ответа
Используйте ExecutorService
конкретно это submit(Callable)
метод, который возвращает Future
который get()
или же isDone()
Методы могут быть вызваны для получения результата:
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);
}
}
// Somewhere, e.g. in your A.compute() method
ExecutorService exe = Executors.newFixedThreadPool(2); // Two threads in parallel
B b = new B(true);
Future<BufferedImage> res = exe.submit(b); // Will return immediately. Processing will run in a thread of 'exe' executor
// ... do things
System.out.println("Finished: "+res.isDone());
BufferedImage img = res.get(); // Will block until image is available (i.e. b.call() returns)
Вы можете использовать разные вкусы ExecutorService
в котором вы можете поставить в очередь обработки, которые могут (submit(Callable)
) или не может (execute(Runnable)
) вернуть результат. Тип исполнителя, который вы хотите использовать, зависит от типа обработки и заказа, который вам нужен.
Вы можете попробовать сделать что-то вроде этого:
public class B{
private boolean c;
volatile boolean finished = false; // it can be shared among threads
BufferedImage output;
public B (boolean c_) { c = c_;}
public void process() {
Thread t = new Thread(new Runnable(){
@Override
public void run() {
if (c) output = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
finished = true;
}
});
t.start();
}
}
public class A {
public void compute() {
B b = new B(true);
b.process();
while(!b.finished){System.out.println("Processing");}
// when finished check if output is not null
// and then do some stuff
if(b.output!=null){System.out.println(b.output);}
}
}