T - the type of the local value.public final class Local<T> extends Object
Locals are a mechanism similar to ThreadLocal but for asynchronous computations.
It is not possible to use ThreadLocals with Future because the data it holds become invalid when the computation reaches an asynchronous boundary. The thread returns to its thread pool to execute other computations, and the continuations are performed by the thread that sets the result of the Promise.
Locals are a mechanism similar to ThreadLocal, but it has a more flexible scope. For example, this code sets the UserSession local when a request is processed:
public class UserSession {
public static final Local<UserSession> local= Local.apply();
// UserSession impl
}
public class MyService {
public Future<List<Tweet>> getTweetsEndpoint(Request request) {
UserSession.local.let(
request.getSession(),
() -> tweetRepo.get(request.getUserId()));
}
}
Note that the let method is used to define the local value, execute the function defined by the second parameter, and then set the local to its previous value. It is a convenient method to avoid having to set and clear the value manually:
public class MyService {
public Future<List<Tweet>> getTweetsEndpoint(Request request) {
final Optional<UserSessuib> saved = UserSession.local.get();
UserSession.local.set(Optional.of(request.getSession()));
try {
return tweetRepo.get(request.getUserId());
} finally {
UserSession.local.set(saved);
}
}
}
At any point of the of the request processing, even after asynchronous boundaries, the user session can be accessed. For instance, let’s say that tweetRepo uses a TweetStorage that routes the query to a specific database shard based on the user that is requesting the tweet:
public class TweetStorage {
public Future<RawTweet> getTweet(long tweetId) {
databaseFor(UserSession.local.get().getUserId()).getTweet(tweetId);
}
}
This feature is implemented with a ThreadLocal that is saved at the point of an asynchronous boundary as a Promise field and is restored when the Promise is satisfied, flushing its continuations with the original ThreadLocal contents.
Note: This feature does not have the same behavior as Twitter’s Local. The ThreadLocal state is captured when a Promise is created, whereas Twitter’s implementation captures the state only when a Promise continuation is created (for instance, map is called on a Promise instance). In practice, most Promise creations are followed by a continuation, so the behavior is usually the same.
| Modifier and Type | Method and Description |
|---|---|
static <T> Local<T> |
apply()
Creates a new local value.
|
Optional<T> |
get()
Gets the current value of the local.
|
<U> U |
let(T value,
java.util.function.Supplier<U> s)
Executes the supplier with the provided value and then rolls back to the previous local value.
|
protected static void |
restore(Optional<?>[] saved) |
protected static Optional<?>[] |
save() |
void |
set(Optional<T> opt)
Sets the value of the local.
|
void |
update(T value)
Updates the local with the provided value.
|
protected static final Optional<?>[] EMPTY
public static final <T> Local<T> apply()
Creates a new local value.
T - the type of the local value.protected static final Optional<?>[] save()
protected static final void restore(Optional<?>[] saved)
public final void update(T value)
Updates the local with the provided value.
value - value to setpublic final void set(Optional<T> opt)
Sets the value of the local. It’s similar to update but receives an optional value.
opt - optional value to set.public final <U> U let(T value, java.util.function.Supplier<U> s)
Executes the supplier with the provided value and then rolls back to the previous local value.
value - value to be set.s - supplier to be executed with the provided value.Copyright © 2017. All Rights Reserved.