Android concurrency
-
Upload
ruslan-novikov -
Category
Software
-
view
529 -
download
0
Transcript of Android concurrency
Why is concurrency in Android important?
• Until pretty recently, real, concurrent execution happened only on expensive server hardware
• – Android already runs on multi-core devices.
• – It will get worse: Moore's law is now about number, not speed, of CPUs
• – Android devices actually need to do multiple things at the same time: Real Time Computing
Android Puts Concurrency in your Face
• The UI is single threaded but will not tolerate long running, synchronous tasks
• IPC (Binder) calls appear on non-UI threads and you can't use the UI from a non-UI thread (a topic for another day...)
Java Concurrency Primitives
• Language level constructs – Synchronized – Thread/Runnable • Concurrency library (java.util.concurrent) – Executor/Callable/Future – Atomics • All are available in Android – Low level Java tools are really low level. If you find yourself using them you might want to review your architecture • – Android Concurrency tools are firmly based on the
concurrency library (java.util.concurrent)
Java Memory Model
Compiler Optimizations
Is Vector Really so Thread Safe?
Synchronized Collections
Concurrent Collections
• CopyOnWriteArrayList
• ConcurrentHashMap
• BlockingQueue
• Vector
• Hashtable
• Collections.synchronizedMap()
• …
Executor
• Executor
• ExecutorService
• ScheduledExecutorService
• Future
• Callable
• Executors
ExecutorService Executor
Task submission:
executorService.submit(MyTask);
executorService.invokeAll(Collection<Tasks>);
executorService.invokeAny(Collection<Tasks>);
Lifecycle management:
executorService.shutdown();
executorService.shutdownNow();
Lifecycle observation:
executorService.isShutdown();
executorService.isTerminated();
executorService.awaitTermination();
Running Shutting
Down Terminated
shutdown()
Task / Execution Environment Executor
Task: Independent unit of work executed anywhere
Runnable run()
Callable call()
Execution Environment:
Technique used to execute the task
Executor execute(Runnable)
Future future = executorService.submit(Callable);
Future isDone()
isCancelled() cancel()
Task manager/observer:
Threads on Android
UI
Android App
Linux Process
Native Threads Java Threads
BG BG BG
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
Android App
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
App A
App A
Foreground Thread Group
Background Thread Group
App B App B
> 90%
< 10%
Android Scheduling
1. Foreground
2. Visible
3. Service
4. Background
Process level:
App A
App A
Foreground Thread Group
Background Thread Group
App B App B
> 90%
< 10%
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
Activity Lifecycle
Time
Activity Component
onCreate() onDestroy() onCreate() onDestroy()
Activity Object
new() GC
Activity Object
new() GC
Activity Lifecycle
Time
Activity Component
onCreate() onDestroy() onCreate() onDestroy()
Activity Object
new()
Activity Object
new()
Start
BG
Reference
Goal
What technique shall I use for my background thread
execution?
Android Asynchronous Techniques
• HandlerThread
• AsyncTask
• Service
• IntentService
• AsyncQueryHandler
• Loader
HandlerThread
• Inherits from Thread and encapsulates a Looper-object
• Thread with a message queue and processing loop
• Handles both Message and Runnable
Running Dead t.quit() t = new HandlerThread().start();
How it works HandlerThread
Handler Thread
Create and Start
Add Process
Message Queue
1
2 3
t = new HandlerThread("BgThread"); t.start();
1 Handler h = new Handler(t.getLooper()) {
@Override
public void handleMessage(Message msg) {
//Process message
} };
2
h.sendEmptyMessage(42); 3
Handler HandlerThread
Runnable/Message submission:
Lifecycle management:
Runnable/Message removal:
removeCallbacks(Runnable);
removeMessages(Message)
post(Runnable);
postDelayed(Runnable);
postAtTime(Runnable)
postAtFrontOfQueue(Runnable);
sendMessage(Message);
sendMessageDelayed(Message);
sendMessageAtTime(Message);
sendMessageAtFrontOfQueue(Message);
AsyncTask
• Wraps Handler/Looper thread communication.
• Utilizes the Executor framework.
• Callbacks for UI operations and Background operation.
onCancelled() 4b
How it works AsyncTask
UI Thread
BG Thread
new AsyncTask.execute() 1
onPreExecute() 2
3 doInBackground()
onPostExecute() 4a
AsyncTask.cancel()
Application Global Behavior AsyncTask > Pitfalls
execute()
Queue Thread Pool
Activity
execute() Activity
execute() Service
execute() Receiver
execute() *
execute()
•Execution behavior has changed over time
AsyncTask > Pitfalls
execute() < Donut:
execute() < Honeycomb:
execute()
executeOnExecutor(Executor)
>= Honeycomb:
execute() AsyncTask > Pitfalls
<uses-sdk android:targetSdkVersion="12" />
<uses-sdk android:targetSdkVersion="13" />
“So, if I call AsyncTask.execute on Honeycomb and later my tasks will run
sequentially, right?”
“Right?!?”
“Eh, it depends…”
Possible solutions: In reverse order of appeal
• Weak Reference
• Persistent
• Cancellable
• Independent
Weak Reference
• Just make all references to the Activity weak
• Currently a “well-known” solution
• The refuge of scoundrels:
– Allows the process to continue, even when the value will be discarded
– Doesn't fix references to destroyed processes
• These are the folks who used to lazily initialize their database connections.
Independent
• What happens when firing the AT is a contract with the UI, and must complete?
• Do the simplest possible proxy to the model
• The inverse of the RESTful ContentProvider cache
Service
Time
Activity Component
onCreate() onDestroy() onCreate() onDestroy()
Service Component
BG
onCreate() onDestroy()
Intent Service
Time
IntentService Component
Intent 1 BG Intent 2 Intent 3 Intent n
stopSelf()
onCreate() onDestroy()
Good Use Cases
• Serially executed tasks decoupled from other component lifecycles.
• Off-load UI thread from BroadcastReceiver.
• REST client (ResultReceiver as callback)
IntentService
AsyncQueryHandler
• API Level 1
• Asynchronous operations on a ContentResolver
• Query
• Insert
• Delete
• Update
• Wraps a HandlerThread
How it works AsyncQueryHandler
UI Thread
BG Thread
new AsyncQueryHandler(); 1
startQuery(); startInsert(); startUpdate(); startDelete();
2
onQueryComplete(); onInsertComplete(); onUpdateComplete(); onDeleteComplete();
3
DB operations
Cons
• No cursor management
• No content observation
• No data retention on configuration changes
• Background thread can’t be forced to quit
AsyncQueryHandler
Loader
• API added in Honeycomb
• Available in compatibility package
• Load data in a background thread
• Observes data changes
• Retained on configuration changes
• Connected to the Activity and Fragment lifecycles
Basics Loader
Data Source
Loader
1 Load data in BG 2 Observe data
3 Lifecycle management 4 Retained on configuration change
Data Sources Loader
Any Data Source
Content Provider
Custom Loader
Cursor Loader
How It Works Loader
public class AndroidLoaderActivity extends ListActivity implements LoaderCallbacks<Cursor>{
SimpleCursorAdapter mAdapter;
public void onCreate(Bundle savedInstanceState) {
getLoaderManager().initLoader(0, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(..., CONTENT_URI, ...);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
mAdapter.swapCursor(c);
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.swapCursor(null);
}
}
Used Material
• http://www.infoq.com/presentations/Concurrency-Android • http://developer.android.com/reference/android/os/Proces
s.html • http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-
133-faq.html • http://docs.oracle.com/javase/specs/jls/se7/html/jls-
17.html • https://plus.google.com/u/0/105051985738280261832/po
sts/XAZ4CeVP6DC • https://github.com/keesj/gomo/wiki/AndroidScheduling • http://stackoverflow.com/questions/7931032/android-
process-scheduling • https://www.youtube.com/watch?v=_q12gb7OwsA