1

Suppose the following simplified example. Let B represent a class processing some raster data:

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();}
}

The process() method may but may not create an output rater. Due to the computational cost, the procedure runs in a separate thread.

Let A represent a class inside which the procedure will be run. It also contains some post process steps waiting until the thread is finished:

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
    }
}

However, how to get resulting raster created using the process() method of B "inside" the run() method in A?

Avoid the model, when the output image represents a data member of B together with

b.getImage();

I read a post about callbacks

Return value from Runnable

but how to implement it here? Thanks for your help and a short example.

justik
  • 4,145
  • 6
  • 32
  • 53

2 Answers2

7

Use an ExecutorService, specifically it submit(Callable) method which returns a Future which get() or isDone() methods can be called to retrieve the result:

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)

You can use different flavors of ExecutorService in which you can queue processings which may (submit(Callable)) or may not (execute(Runnable)) return a result. The type of Executor you want to use depends on the type of processing and order you need.

Matthieu
  • 2,736
  • 4
  • 57
  • 87
  • @ Matthieu: May I kindly ask you for an example? – justik Jul 09 '17 at 21:06
  • @justik I updated with a simple example, somewhat linked to the code you gave – Matthieu Jul 09 '17 at 21:24
  • Thanks @Yahya, `Executors` and `Future` are a must-know for concurrent programming! :) – Matthieu Jul 09 '17 at 21:30
  • You're right, I will, but I'm still have the habit of thinking myself writing in C like the old days. I really need to consider going with the flow :) – Yahya Jul 09 '17 at 21:32
  • 2
    @Yahya (and others as well): the huge advantage with `ExecutorService` is you can tune it to allow for graceful degradation of System resources, by e.g. tuning the number of threads running concurrently, or to schedule processes later in time, repeating, etc. Welcome to the wonderful world of OOP (I made the C > Java jump a few years ago and don't regret it :)). – Matthieu Jul 09 '17 at 21:38
  • 1
    @ Matthieu: Merci et bonne soirée :-) – justik Jul 09 '17 at 21:48
  • @ Yahya: the same problem, I am an old-school C++ programmer and Java is sometimes like the black-box :-) – justik Jul 09 '17 at 21:50
1

You can try doing something like this:

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);}
   }
}
Yahya
  • 13,349
  • 6
  • 30
  • 42