0

I have the following class and inner "AsyncTask" (http://developer.android.com/reference/android/os/AsyncTask.html) defined.

class SomeClassA {

    Long b = 0;

    void executeTask() {
       // executed on main thread.
       b = 1;
       new SomeAsyncTask().execute();
    }

    private class SomeAsyncTask extends AsyncTask<Void, Void, Void> {

        protected Void doInBackground(Void... params) {
           b = 3;
        }

        protected void onPostExecute(Void param) {
           System.out.println(b);
        }
    }
}

I am curious about what guarantees I am given about the "memory visibility" of an AsyncTask as well as thread safety. From my understanding, the call "doInBackground" is executed in a separate thread, and therefore any changes I make to "b" in "doInBackground" cannot be guaranteed to be "visible" in any of the callbacks executed on the main thread (e.g. "onPostExecute()", "onPreExecute", "onProgressUpdate" etc.).

Is this correct? So in the above example, the "System.out.println(b)" in "onPostExecute" can print 1 OR 3 but it's not guaranteed. What would I have to do to guarantee this memory observability?

In the AsyncTask website (posted above), I see the following snippet.

Memory Observability

AsyncTask guarantees that all callback calls are synchronized in such a way that the following operations are safe without explicit synchronizations.

  • Set member fields in the constructor or onPreExecute(), and refer to them in doInBackground(Params...).
  • Set member fields in doInBackground(Params...), and refer to them in onProgressUpdate(Progress...) and onPostExecute(Result).

I think this "might" explain my confusion but I don't understand what this means. Can someone explain this to me?

Jon
  • 1,381
  • 3
  • 16
  • 41

1 Answers1

1

So in the above example, the "System.out.println(b)" in "onPostExecute" can print 1 OR 3 but it's not guaranteed

This will always print 3. (Or nothing, if the task is cancelled). onPostExecute only runs if doInBackground finished correctly.

Can someone explain this to me?

This section just tells you that it is save to use members in the named methods which were set in the respective named methods.

F43nd1r
  • 7,690
  • 3
  • 24
  • 62
  • I thought "doInBackground" is invoked on some worker thread whereas onPostExecute() is invoked on the main thread. Since these are executed on two separate threads, isn't it possible that the write to b in doInBackground hasn't been flushed to memory and therefore onPostExecute is reading a stale value? – Jon May 09 '16 at 01:00
  • If these were any two threads, yes. But the second bullet point of the Quote tells you just that: Everything set in `doInBackground` is safe to use in `onPostExecute`. Basically AsyncTask assures that this won't happen. – F43nd1r May 09 '16 at 01:03
  • Ah I see. I looked at the source code here (https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/AsyncTask.java) and I wasn't sure where that guarantee was made. The code looks pretty straightforward. – Jon May 09 '16 at 01:11
  • 2
    "I wasn't sure where that guarantee was made" — the guarantee is made by `FutureTask`. It guarantees, that calculating it's result happens before it is returned by `get()`. Java Language Specification [automatically extends](https://stackoverflow.com/questions/17108541/) this guarantee to other involved variables and operations, that happened before/after read/write of `FutureTask` result on involved threads. – user1643723 May 09 '16 at 01:48