Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ITT 2016 - Blake Meike - Inside Concurrency

ITT 2016 - Blake Meike - Inside Concurrency

So, you now scorn AsyncTasks. ...Or maybe you've got battle tested patterns for using them. Maybe you have discovered RxAndroid and will just never need to worry about concurrency again. That's great! Do you actually know the details, though? Can you actually distinguish between snake oil and solution? Don't take somebody else's word for it! Take a deep dive into the internals of Android's concurrency constructs, look at the code, and understand them for yourself! In this talk, Blake Meike focuses on:
* AsyncTasks without the mythology
* Looper/Handler: the core of Android Concurrency
* IntentServices: palliative, not panacea
* Services: Binder, processes and lifecycles

Istanbul Tech Talks

April 05, 2016
Tweet

More Decks by Istanbul Tech Talks

Other Decks in Programming

Transcript

  1. G. Blake Meike Developer, Architect, Android Evangelist G. Blake MEIKE

    ANDROID DEEP DIVE ANDROID CONCURRENCY Zigurd MEDNIEKS Series Editor
  2. … but programming is not the real world The ENIAC

    computer, University of Pennsylvania, 1944 Von Neumann machines are giganFc balls of state. ! Programs are ordered rules for mutaFng that state
  3. Early computer languages Code snip from Von Neumann’s Merge Sort

    for the EDVAC SWITCH RST 1 LALPHA1 RST 1 LALPHA2 RST 1 ALPHA SUB YKEY,XKEY SEL LALPHA1,LALPHA2 STO SWITCH JMP SWITCH Nearly literal translaFons of the hardware they programmed
  4. Neither the world with which the code interacts, nor the

    hardware on which it runs, are actually sequenGal. This is an elaborate illusion!
  5. SequenGal execuGon is a contract between hardware designers and compiler

    writers, on one side, and developers on the other.
  6. Whenever more than one thread accesses a given state variable,

    and one of them might write to it, they all must coordinate their access to it using synchronization. Brian Goetz “Whenever more than one thread accesses a given state variable, and one of them might write to it, they all must coordinate their access to it using synchronizaFon.” ! Brian Goetz, et. al.
  7. Monitors and Synchroniza8on Object lock = new Object ! synchronized

    (lock) { // critical section } In Java, every object has a monitor. ! SynchronizaFon creates a happens- before edge between threads seizing the lock
  8. Most developers see the problem here: int mCount; ! new

    Thread() { public void run() { mCount++; doSomething(); } }.start(); ! new Thread() { public void run() { mCount++; doSomething(); } }.start();
  9. … but many do not see the problem here: boolean

    mStop; ! new Thread() { public void run() { while (!mStop) { doSomething(); } } }.start(); ! mStop = true;
  10. No happens-before Thread 1 Thread 2 fetch mStop (false) test

    (false) load true invoke store to goto 3
  11. This code was iden8fied as broken, late in 2000 public

    class LazySingleton { private static LazySingleton sInstance; ! public static getInstance() { if (sInstance == null) { synchronized (LazySingleton.class) { if (sInstance == null) { sInstance = new LazySingleton(); } } } return sInstance; } ! private LazySingleton() { // … } // … h]p:/ /www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
  12. Reference to unconstructed object. 0206106A mov eax,0F97E78h 0206106F call 01F6B210

    ; allocate space for ; singleton; return eax 02061074 mov dword ptr [ebp],eax ; EBP is singleton ref 02061077 mov ecx,dword ptr [eax] ; store obj handle ; to get raw pointer 02061079 mov dword ptr [ecx],100h ; Next 4 lines are 0206107F mov dword ptr [ecx+4],200h ; singleton's02061086 02061086 mov dword ptr [ecx+8],400h ; inlined constructor 0206108D mov dword ptr [ecx+0Ch],0F84030h h]p:/ /www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
  13. oom_adj Your app process will get killed, eventually most likely

    to be killed invisible ac7vity running service visible ac7vity system processes least likely to be killed
  14. This will cause an unresponsive UI: Cursor c = getContentResolver().query(

    DataProvider.URI, REQ_COLS, COL_LAST_NAME + "=?", new String[] { userName }, COL_LAST_NAME + “ ASC" );
  15. Ideally: Cursor c = doInBackground( () -> { getContentResolver().query( DataProvider.URI,

    REQ_COLS, COL_LAST_NAME + "=?", new String[] { userName }, COL_LAST_NAME + “ ASC" ); } );
  16. Limita8ons: • Android’s Java doesn’t support lambdas (yet) • throw,

    return, break and continue • In-scope variables • The return value!
  17. Actually: private class DbQueryGetNamesTask extends AsyncTask<String, Void, Cursor> { @Override

    protected Cursor doInBackground(String… userName) { return getContentResolver().query( DataProvider.URI, REQ_COLS, COL_LAST_NAME + "=?", new String[] { userName[0] }, COL_LAST_NAME + " ASC"); } ! @Override public onPostExecute(Cursor cursor) { onCursorReceived(cursor); } }
  18. Which thread? Android Single thread? Cupcake Thread pool executor 1

    - 10 threads Honeycomb Thread pool executor 1 - 10 threads Dequeue serializa7on Kitkat Thread pool executor (cpu + 1) - 2(cpu + 1) Dequeue serializa7on
  19. All the Java things! new AsyncTask<List<String>, Void, Void>() { @Override

    protected Void doInBackground(List<String>... args) { List<String> s = args[0] mWords = s.size() for (int i = 0, n = mWords, i < n; i++) { mTextView.setText(s.get(i)); try { Thread.sleep(100) } catch (Exception e) { } } return null; } }.execute(strings); !
  20. Enqueuing a Runnable @SuppressLint(“HandlerLeak") public void onCreate(Bundle state) { //

    .... uiHandler = new Handler(); } ! private void revealButtonDelayed() { uiHandler.postDelayed( new Runnable() { @Override public void run() { button.setVisibility(View.VISIBLE); ViewAnimationUtils .createCircularReveal( button, ctr, ctr, 0, buttonDiameter) .start(); } }, BUTTON_DELAY); }
  21. Sending a message @SuppressLint("HandlerLeak") public void onCreate(Bundle state) { //

    ... handler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case OP_START_ANIMATION: revealButton(); break; } } }; } ! private void revealButtonDelayed() { uiHandler.sendMessageDelayed(OP_START_ANIMATION, BUTTON_DELAY); } ! private void revealButton() { button.setVisibility(View.VISIBLE); ViewAnimationUtils .createCircularReveal(button, ctr, ctr, 0, buttonDiameter) .start(); }
  22. Which Handler? someHandler.obtainMessage(…) ! Message.obtain(someHandler, …) ! Message msg =

    new Message(); msg.setTarget(someHandler); Handler handler1 = new Handler(looper1); Handler handler2 = new Handler(looper2); ! handler1.sendMessage(handler2.obtainMessage(OP_CONFUSION)); All irrelevant!
  23. Crea8ng a Looper/Handler ! private volatile Handler hdlr; private Handler

    hdlr2; ! Thread looperThread = new Thread() { @Override public void run() { Looper.prepare(); hdlr = new Handler(); Looper.loop(); } }; looperThread.start() ! hdlr2 = hdlr;
  24. It is the Na8ve Looper that relinquishes the processor, using

    epoll ! Marshmallow publishes new methods that allow adding new file descriptors to epoll