0

Let's say I have a class of this form.

class TestClass implements SomeInterface {

    Data myData;

    public TestClass() {
    }

    @Override
    public void onData(Data data) {
        // do stuff with data
        myData = data
    }
}

where SomeInterface does some data processing on a background thread and calls onData, which runs on a background thread as well. I want to be able to use the data returned in onData on the Main thread (updating UI, do other stuff on main thread, etc.) because I know exactly how long after I call the background thread, onData will be called. Since I'm using SomeInterface from some library, I can't modify this functionality (I'm not exactly using it as intended).

In Android I would have done something like this but I obviously can't do it in a pure Java application since there's no such thing as a Looper. Setting an instance variable from a background thread doesn't let me access it from the main thread as well.

Carpetfizz
  • 8,707
  • 22
  • 85
  • 146
  • If you use AWT or swing, then use [`EventQueue.invokeLater(Runnable)`](https://docs.oracle.com/javase/10/docs/api/java/awt/EventQueue.html#invokeLater(java.lang.Runnable)) – Johannes Kuhn Jul 23 '18 at 22:56
  • Have a look at `SwingWorker` which is basically the same thing for Java. https://docs.oracle.com/javase/10/docs/api/javax/swing/SwingWorker.html Note that on neither Android nor Java desktop does the main thread update the gui. – markspace Jul 23 '18 at 22:56
  • What GUI framework? Swing, for example, provides `SwingWorker` and `SwingUtilities.invokeLater` which provide you means to move execution onto the main thread – MadProgrammer Jul 23 '18 at 22:56
  • I’m not using Swing, AWT, or any UI library. I just used updating the UI as an example. – Carpetfizz Jul 23 '18 at 22:57
  • If it's not Swing or AWT, what UI is it? – markspace Jul 23 '18 at 22:57
  • I’m not using any UI. I just used UI as an example of what can be accomplished. Is there no way to do this independently of a UI framework? – Carpetfizz Jul 23 '18 at 22:58
  • Ah, have a look at `ExecutorService` then, look at thread pools, and the `Callable` interface. – markspace Jul 23 '18 at 22:59
  • GUI frameworks use a producer/consumer pattern. Basically thread x places a "object" of specific type onto the GUI's event queue. The main (or event dispatching) thread will process this queue. When it finds an instance of the "specific type of object" it will perform the required operation on it, which means that operation is executed within the context of the main thread - In Swing/AWT, this "specific" object is an instance of `Runnable` and the EDT executes the `run` method on it. You could devise something simular – MadProgrammer Jul 23 '18 at 23:03
  • @MadProgrammer how does thread x update a variable (event queue) on the Main thread? This is essentially the same functionality I want. Instead of adding to a queue I simply want to set an instance variable – Carpetfizz Jul 23 '18 at 23:13
  • @Carpetfizz As I said, you can use a producer/consumer pattern. The idea is. You have the "main" thread, which would be reading from the "queue" and processing it's content. You would have `onData` wrap `data` in the "queue"s expected type and push it onto the queue. The "main" thread would then pop it off the queue and execute it's functionality. In the case of Swing and Android, they use `Runnable`s, where the "main" thread would just call the `run` method – MadProgrammer Jul 23 '18 at 23:16
  • @MadProgrammer yes, I agree with you on the pattern. However I was asking how onData would write data into a queue that the Main thread can read from. In my example above onData is setting an instance variable but the Main thread was unable to read this instance variable. If onData writes into a queue which is an instance variable, how can the Main thread read from it? – Carpetfizz Jul 23 '18 at 23:20
  • @Carpetfizz Technically, you could use a `BlockingQueue` of some kind – MadProgrammer Jul 23 '18 at 23:25
  • cant you use volatile on the variable ?? – rohit thomas Jul 24 '18 at 02:41

1 Answers1

0

You could invent your own framework, but that would be kind of silly. ExecutorService and other classes from java.util.concurrent basically do this all for you with only a little bit of assembly.

Here I create some input data on the main thread, pass it to a background thread by using the Callable interface and an executor. Then the main thread gets the output data from the background thread using a Future object. Easy peasy.

public abstract class SimpleBackgroundService {

   public static void main( String[] args ) throws InterruptedException, ExecutionException {

      final InputData input = new InputData( 123, "Hi Mom" ); // really should be immutable

      Callable<OutputData> task = new Callable<OutputData>() {
         private final InputData taskInput = input;
         @Override
         public OutputData call() {
            return new OutputData( taskInput );
         }
      };

      ExecutorService es = Executors.newFixedThreadPool( 1 );
      Future<OutputData> taskOutput = es.submit( task );
      // do some stuff here while the task completes.
      OutputData data = taskOutput.get();  // will block and wait if needed
      System.out.println( data );
   }

   static class InputData {

      private final int num;
      private final String msg;

      public InputData( int num, String msg ) {
         this.num = num;
         this.msg = msg;
      }

   }
   static class OutputData {

      private final int num2;
      private final String msg2;

      public OutputData( InputData dat ) {
         num2 = dat.num;
         msg2 = dat.msg;
      }
   }

}
markspace
  • 10,621
  • 3
  • 25
  • 39
  • Thanks but I unfortunately don’t have the luxury of calling the task itself. I just subscribe to an event listener from some jar which calls the handler on my class – Carpetfizz Jul 23 '18 at 23:25
  • You should have mentioned that from the start. You really aren't making it easy to answer the question, are you? Put the full information in the OP and maybe someone will answer it. – markspace Jul 23 '18 at 23:26
  • I believe I said in the OP I can’t modify the functionality of the library – Carpetfizz Jul 23 '18 at 23:28