Below is sample code examples of a custom App class and MainActivity class code:
public class App extends Application {
private static String TAG = "APP";
private int i;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, Thread.currentThread().getName());
HandlerThread t = new HandlerThread("init-thread");
t.start();
i = -100;
Handler handler = new Handler(t.getLooper());
handler.post(new Runnable() {
@Override
public void run() {
i = 100;
}
});
handler.post(new Runnable() {
@Override
public void run() {
MainActivity.MainHandler h = new MainActivity.MainHandler(Looper.getMainLooper(), App.this);
h.sendEmptyMessage(0);
}
});
}
public int getI() {
return i;
}
}
And MainActivity Class:
public class MainActivity extends Activity {
private static String TAG = "ACT-1";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
protected void onResume() {
super.onResume();
App app = (App) getApplication();
Log.e(TAG, "i: " + app.getI()); //prints 100
}
public static class MainHandler extends Handler {
private Application application;
public MainHandler(Looper looper, Application app) {
super(looper);
this.application = app;
}
@Override
public void handleMessage(Message msg) {
App app = (App) application;
Log.e(TAG, "MSG.what: " + msg.what);
Log.e(TAG, "i: " + app.getI()); //prints 100
}
}
}
What I'm trying to do is change the value of "i" to 100 in INIT-THREAD and from MAIN thread trying to read the value back.
I was expecting the value of "i" in onResume and handleMessage to be -100 because they are executing in MAIN thread but the Log printed value is actually 100.
In a way I'm trying to reproduce the classic mistake everyone does in regular java programs but android seems to intelligently avoid it.
So i'm interested in understanding how android is achieving the happens-before relation between two threads.
There is no happens-before relationship in setting the value of i
in this program. The program contains a data race and is in error.
The fact that you've seen it produce some particular result, in a couple of test runs, is no proof of anything at all. While the behavior of the code is undefined, when you run it, it will do something. On any particular bit of hardware, it may even do that something most of the time.
Quickly looking at the code, I don't see any read-alter-rewrites, so I think that making i
volatile would make the program correct. It would not, however, make any of the comment assertions about the value that a particular Log
statement prints, accurate.