3

In Android we have Handler#post(Runnable) method to post some code to the main thread from another

Is it possible to make same thing in plain java (for instance while using swing)?

Explaining the question: Assume we have two threads: ThreadA and ThreadB. Both are started already and running side-by-side. And ThreadB wants ThreadA to invoke some method (again, ThreadA is already running).

Addition optional question (you may not answer it): And if it's possible, someone explain me how does exactly Handler do in Android. How it's able to post some code to MainThread? What is a purpose of the Looper?

GV_FiQst
  • 1,487
  • 14
  • 30
  • 1
    Please post a more concrete example of what you're trying to do. – Hovercraft Full Of Eels May 31 '17 at 22:07
  • GV, no, I don't do Android programming, but I do do a lot of Swing coding, including working with background threads. – Hovercraft Full Of Eels May 31 '17 at 22:16
  • @HovercraftFullOfEels Did you work with Android? There is a class Handler. Usage is simple: new Hanldler(Looper.getMainLooper()).post(new Runnable() { void run() {}}); Dosen't matter what thread is current now, the run() method will be invoked only in MainThread. – GV_FiQst May 31 '17 at 22:17
  • 1
    For Handlers **ThreadLocal, Thread, Looper** follwed by **Handler** study these three concepts along with as how Thread.java uses a map structure to associate value set by thread local object. You will really have a good learning expierence if you dive into above topics. These cover the concept of Handler internal working. While studying above 1. Why handler object cant be created in a thread not having a looper object with it 2. How looper object gets accociated with current thread 3. What and how does Looper.prepare() does and finally about Looper.loop() method – nits.kk May 31 '17 at 22:19
  • *"how does exactly Handler do in Android"* - Without knowing the specifics of how the API works, I would suggest that `Handler#post` places the `Runnable` on a queue, which the "main thread" processes, when it "pops" a `Runnable` off the queue, it simply calls the `Run` method – MadProgrammer May 31 '17 at 22:23
  • @nits.kk Thanks a lot. I will read about those concepts. As I understood in Android threads don't touch each other. It's only a loop (in MainThread) that invokes all runnables that was written to a field. Am I right? – GV_FiQst May 31 '17 at 22:33
  • I think that you may be looking into using a LinkedBlockingQueue for creating a producer/consumer structure that accepts Runnables or Callables. – Hovercraft Full Of Eels May 31 '17 at 22:40

2 Answers2

6

Addressing your additional question:

You said "In Android we have Handler#post(Runnable) method to post some code to the main thread from another"

It is not exactly correct. You can 'post some code' from any thread A to any thread B provided that thread B is initialized as a Looper and the thread A has a reference to a Handler for the target thread B.

It is very convenient when you need to do something on the UI thread because the UI thread already has a Looper and you can retrieve it from nearly everywhere. The static method Looper.getMainLooper is a way to get a Looper for the main thread. If you initialize a Handler with this Looper you can post a Runnable or send a Message to it (though if you post Runnable it also gets wrapped into a Message) and it will be executed on the UI thread.

Looper, as the name hints, is basically running a non-terminating loop for a thread. The Looper has an associated MessageQueue which it constantly checks for new Messages. Via the Handler initialized with a Looper you can enqueue Messages on this thread. The Messages are processed in a sequential order, depending on the when field of a Message.

Here's a basic implementation of a Looper thread:

  class LooperThread extends Thread {
      public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // process incoming messages here
              }
          };

          Looper.loop();
      }
  }

I suggest you read the Chapter 5 of Meike G.B. Android Concurrency. It will give you a comprehensive insight into the Looper/Handler framework. It is also great to browse the source code while you are reading, it is rather simple and self-explanatory.

Varvara Kalinina
  • 2,043
  • 19
  • 29
  • 1
    I recently posted an answer to a similar question where I in more detail explain the internals of posting Messages: https://stackoverflow.com/a/44478689/2611340 – Varvara Kalinina Jun 15 '17 at 17:42
0

Within Swing you would use

https://docs.oracle.com/javase/8/docs/api/javax/swing/SwingUtilities.html#invokeLater-java.lang.Runnable-

to run something on the main thread.

In general Java, an ExecutorService is like a thread pool and allows you to submit Runnable or Callable instances

https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html

However, if you aren't using an ExecutorService or Swing, there is no standard Java API to tell another thread to do something.

clay
  • 18,138
  • 28
  • 107
  • 192