1## Asynchronous work {#async}
2
3### With return values {#async-return}
4
5#### Kotlin
6
7Traditionally, asynchronous work on Android that results in an output value
8would use a callback; however, better alternatives exist for libraries.
9
10Kotlin libraries should consider
11[coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) and
12`suspend` functions for APIs according to the following rules, but please refer
13to the guidance on [allowable dependencies](#dependencies-coroutines) before
14adding a new dependency on coroutines.
15
16Kotlin suspend fun vs blocking       | Behavior
17------------------------------------ | --------------------------
18blocking function with @WorkerThread | API is blocking
19suspend                              | API is async (e.g. Future)
20
21In general, do not introduce a suspend function entirely to switch threads for
22blocking calls. To do so correctly requires that we allow the developer to
23configure the Dispatcher. As there is already a coroutines-based API for
24changing dispatchers (withContext) that the caller may use to switch threads, it
25is unecessary API overhead to provide a duplicate mechanism. In addition, it
26unecessary limits callers to coroutine contexts.
27
28```kotlin
29// DO expose blocking calls as blocking calls
30@WorkerThread
31fun blockingCall()
32
33// DON'T wrap in suspend functions (only to switch threads)
34suspend fun blockingCallWrappedInSuspend(
35  dispatcher: CoroutineDispatcher = Dispatchers.Default
36) = withContext(dispatcher) { /* ... */ }
37
38// DO expose async calls as suspend funs
39suspend fun asyncCall(): ReturnValue
40
41// DON'T expose async calls as a callback-based API (for the main API)
42fun asyncCall(executor: Executor, callback: (ReturnValue) -> Unit)
43```
44
45#### Java
46
47Java libraries should prefer `ListenableFuture` and the
48[`CallbackToFutureAdapter`](https://developer.android.com/reference/androidx/concurrent/futures/CallbackToFutureAdapter)
49implementation provided by the `androidx.concurrent:concurrent-futures` library.
50Functions and methods that return `ListenableFuture` should be suffixed by,
51`Async` to reserve the shorter, unmodified name for a `suspend` method or
52extension function in Kotlin that returns the value normally in accordance with
53structured concurrency.
54
55Libraries **must not** use `java.util.concurrent.CompletableFuture`, as it has a
56large API surface that permits arbitrary mutation of the future's value and has
57error-prone defaults.
58
59See the [Dependencies](#dependencies) section for more information on using
60Kotlin coroutines and Guava in your library.
61
62### Cancellation
63
64Libraries that expose APIs for performing asynchronous work should support
65cancellation. There are *very few* cases where it is not feasible to support
66cancellation.
67
68Libraries that use `ListenableFuture` must be careful to follow the exact
69specification of
70[`Future.cancel(boolean mayInterruptIfRunning)`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html?is-external=true#cancel-boolean-)
71behavior.
72
73```java {.bad}
74@Override
75public boolean cancel(boolean mayInterruptIfRunning) {
76    // Does not support cancellation.
77    return false;
78}
79```
80
81```java {.bad}
82@Override
83public boolean cancel(boolean mayInterruptIfRunning) {
84    // Aggressively does not support cancellation.
85    throw new UnsupportedOperationException();
86}
87```
88
89```java {.good}
90@Override
91public boolean cancel(boolean mayInterruptIfRunning) {
92    // Pseudocode that ignores threading but follows the spec.
93    if (mCompleted
94            || mCancelled
95            || mRunning && !mayInterruptIfRunning) {
96        return false;
97    }
98    mCancelled = true;
99    return true;
100}
101```
102
103### Avoid `synchronized` methods
104
105Whenever multiple threads are interacting with shared (mutable) references those
106reads and writes must be synchronized in some way. However synchronized blocks
107make your code thread-safe at the expense of concurrent execution. Any time
108execution enters a synchronized block or method any other thread trying to enter
109a synchronized block on the same object has to wait; even if in practice the
110operations are unrelated (e.g. they interact with different fields). This can
111dramatically reduce the benefit of trying to write multi-threaded code in the
112first place.
113
114Locking with synchronized is a heavyweight form of ensuring ordering between
115threads, and there are a number of common APIs and patterns that you can use
116that are more lightweight, depending on your use case:
117
118*   Compute a value once and make it available to all threads
119*   Update Set and Map data structures across threads
120*   Allow a group of threads to process a stream of data concurrently
121*   Provide instances of a non-thread-safe type to multiple threads
122*   Update a value from multiple threads atomically
123*   Maintain granular control of your concurrency invariants
124