Effect of anonymous class accessing outside variables in a multi threaded environment?

from the CommonsWare Community archives

At October 17, 2020, 10:49am, root-ansh asked:

I am trying to understand coroutines. For which I guess I need to understand the usual multi threading and what’s wrong with them, and for that i need to understand callbacks.
Here is a particular common code in both java and android dev :


public class Test {

    public static void main(String[] args) {

        String s = "Hello";
        Runnable r = new Runnable() {
            @Override public void run() { 
                System.out.println(s); 
            }
        
        };
        r.run();
    }

}

I get that here we created an anonymous class instance of an interface, but why is it able to access the variable s ?? I mean if there was some class say, AbcRunner implements Runnable nd instead of creating a runnable instance r , I would have created AbcRunner abc = new AbcRunner(), i wouldn’t be able to call abc.run() and achieve the same results (i.e of using the variable s )

More importantly, my concern is about threading and android. Runnables run in threads, and from the above example, what i understand is that using these magic powers of anonymous classes, we can pass any code and any variable to a Runnable’s run function and that would be executed in any thread we want.

Would I be correct to assume that android modifies the default behavior of java threading (and whatever this anonymous-class's-magic-of-accessing-same-scope-variables is) in a manner that if variable a s is a string/java sdk classes obj, then it allows passing it between different threads, but if a variable is from android sdk class object (like View or TextView) , it will be giving an error ?

If not then under what circumstance this statement “Do not access the Android UI toolkit from outside the UI thread” valid?


At October 17, 2020, 12:27pm, mmurphy replied:

It is an instance of an anonymous inner class. s is still in scope, though I am surprised that the Java compiler does not force you to declare it as final.

Not really. Runnable is a Java interface, and “runnables” are instances of that interface. Objects do not run on threads — methods do. run() will run on some thread, determined by whoever is calling run().

That is not unique to Runnable. Java methods like run() can be invoked on whatever thread the caller wants, simply by being on that thread at the time of the run() call.

No.

Again, I am surprised that your code compiles. I would expect s to need to be declared final.

No. However, most views will complain if their methods are invoked on threads other than the thread that created them, as Android’s UI system was built around a single-threaded architecture (way back in 2006 or so, when mobile CPUs were slow). But, there is code inside of the framework to detect whether the method is being called on their original thread, and that code throws exceptions when this rule is violated.