0

I had this code (which was working fine):

public static void runOnUiThread(Activity c, final Runnable action) {
    // Check if we are on the UI Thread
    if (Looper.getMainLooper() == Looper.myLooper()) {
        // If we are, execute immediately
        action.run();
        return;
    } // Else run the runnable on the UI Thread and wait
    Runnable r = new Runnable() {
        @Override
        public void run() {
            action.run();
            synchronized (this) {
                this.notify();
            }
        }
    };
    synchronized (r) {
        try {
            c.runOnUiThread(r);
            r.wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

And I was getting Synchronization on local variable warning. As suggested, I removed the synchronization on the local variable, in order to fix the warning:

public static void runOnUiThread(Activity c, final Runnable action) {
    // Check if we are on the UI Thread
    if (Looper.getMainLooper() == Looper.myLooper()) {
        // If we are, execute immediately
        action.run();
        return;
    } // Else run the runnable on the UI Thread and wait
    Runnable r = new Runnable() {
        @Override
        public void run() {
            action.run();
            this.notify();
        }
    }
    try {
        c.runOnUiThread(r);
        r.wait();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

And now I am getting an exception when calling this method:

06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               FATAL EXCEPTION: main
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               java.lang.IllegalMonitorStateException: object not locked by thread before notify()
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at java.lang.Object.notify(Native Method)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at org.matapps.android.simpleappcreator.Utils$100000007.run(Utils.java:673)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at android.os.Handler.handleCallback(Handler.java:615)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at android.os.Handler.dispatchMessage(Handler.java:92)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at android.os.Looper.loop(Looper.java:137)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at android.app.ActivityThread.main(ActivityThread.java:4867)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at java.lang.reflect.Method.invokeNative(Native Method)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at java.lang.reflect.Method.invoke(Method.java:511)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1007)
06-15 09:18:13.252 27282 27282 E   AndroidRuntime                               at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:774)

I'm pretty sure I need the synchronization (as the runnable runs on a different thread), but I was told local variables shouldn't have synchronization. Any tips? Thanks!

6
  • Both wait and notify must be invoked in a synchronized block Commented Jun 15, 2015 at 6:33
  • Have you searched for java.lang.IllegalMonitorStateException? Commented Jun 15, 2015 at 6:34
  • But I am getting a warning Commented Jun 15, 2015 at 6:34
  • 2
    add a @SuppressWarnings if it's bothering you Commented Jun 15, 2015 at 6:35
  • 1
    First you must understand why there is a "synchronization on local variable" warning in the first place. Which is that it's usually a mistake. But in this case, it's not a mistake. Commented Jun 15, 2015 at 6:44

1 Answer 1

1

I don't know Android development tools, but the warning sounds over-zealous. The compiler is trying to help you to avoid synchronizing on an instance that is only visible to a single thread. It's smart enough to know that the local variable, r, can only be seen by one thread, but apparently it is not smart enough to know that r in the original thread and this in the new thread both refer to the same instance.

I would try to work around the problem by making r an instance variable.

Sign up to request clarification or add additional context in comments.

1 Comment

All I needed to know is that the code is OK, and simply the compiler doesn't know that runOnUiThread actually runs the runnable on a different thread... Anyway, I fixed it with a '@SuppressWarnings'. Thanks to anybody who helped!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.