@ExperimentalApi(value="https://github.com/grpc/grpc-java/issues/262") public class Context extends Object
Context objects make their state available by being attached to the executing thread using
a ThreadLocal
. The context object bound to a thread is considered current()
.
Context objects are immutable and inherit state from their parent. To add or overwrite the
current state a new context object must be created and then attached to the thread replacing the
previously bound context. For example:
Context withCredential = Context.current().withValue(CRED_KEY, cred); executorService.execute(withCredential.wrap(new Runnable() { public void run() { readUserRecords(userId, CRED_KEY.get()); } }));
Context objects will cascade cancellation from their parent and propagate it to their
children. You can add a Context.CancellationListener
to a context to be notified when it or
one of its ancestors has been cancelled. Cancellation does not release the state stored by
a context and it's perfectly valid to attach()
an already cancelled context to a
thread to make it current. To cancel a context (and its descendants) you first create a
Context.CancellableContext
and when you need to signal cancellation call
Context.CancellableContext.cancel(java.lang.Throwable)
or Context.CancellableContext.detachAndCancel(io.grpc.Context, java.lang.Throwable)
. For example:
CancellableContext withCancellation = Context.current().withCancellation(); try { executorService.execute(withCancellation.wrap(new Runnable() { public void run() { while (waitingForData() && !Context.current().isCancelled()) {} } }); doSomeWork(); } catch (Throwable t) { withCancellation.cancel(t); }
Notes and cautions on use:
Modifier and Type | Class and Description |
---|---|
static class |
Context.CancellableContext
A context which inherits cancellation from its parent but which can also be independently
cancelled and which will propagate cancellation to its descendants.
|
static interface |
Context.CancellationListener
A listener notified on context cancellation.
|
static class |
Context.Key<T>
Key for indexing values stored in a context.
|
Modifier and Type | Field and Description |
---|---|
static Context |
ROOT
The logical root context which is
current() if no other context is bound. |
Modifier and Type | Method and Description |
---|---|
void |
addListener(Context.CancellationListener cancellationListener,
Executor executor)
Add a listener that will be notified when the context becomes cancelled.
|
Context |
attach()
Attach this context to the thread and make it
current() , the previously current context
is returned. |
Throwable |
cause()
If a context
isCancelled() then return the cause of the cancellation or
null if context was cancelled without a cause. |
static Context |
current()
Return the context associated with the current thread, will never return
null as
the ROOT context is implicitly associated with all threads. |
void |
detach(Context toAttach)
Detach the current context from the thread and attach the provided replacement.
|
Context.CancellableContext |
fork()
Create a new context which copies the values of this context but does not propagate its
cancellation and is its own independent root for cancellation.
|
boolean |
isCancelled()
Is this context cancelled.
|
static <T> Context.Key<T> |
key(String name)
Create a
Context.Key with the given name. |
static <T> Context.Key<T> |
keyWithDefault(String name,
T defaultValue)
Create a
Context.Key with the given name and default value. |
static Executor |
propagate(Executor e)
Create an executor that propagates the
current() context when Executor.execute(java.lang.Runnable)
is called to the current() context of the Runnable scheduled. |
void |
removeListener(Context.CancellationListener cancellationListener)
Remove a
Context.CancellationListener . |
Context.CancellableContext |
withCancellation()
Create a new context which is independently cancellable and also cascades cancellation from
its parent.
|
Context.CancellableContext |
withDeadlineAfter(long duration,
TimeUnit unit)
Create a new context which will cancel itself after the given
duration from now. |
Context.CancellableContext |
withDeadlineNanoTime(long deadlineNanoTime)
Create a new context which will cancel itself after an absolute deadline expressed as
nanoseconds in the
System.nanoTime() clock. |
<V> Context |
withValue(Context.Key<V> k1,
V v1)
Create a new context with the given key value set.
|
<V1,V2> Context |
withValues(Context.Key<V1> k1,
V1 v1,
Context.Key<V2> k2,
V2 v2)
Create a new context with the given key value set.
|
<V1,V2,V3> Context |
withValues(Context.Key<V1> k1,
V1 v1,
Context.Key<V2> k2,
V2 v2,
Context.Key<V3> k3,
V3 v3)
Create a new context with the given key value set.
|
<C> Callable<C> |
wrap(Callable<C> c)
|
Executor |
wrap(Executor e)
|
Runnable |
wrap(Runnable r)
|
public static <T> Context.Key<T> key(String name)
Context.Key
with the given name.public static <T> Context.Key<T> keyWithDefault(String name, T defaultValue)
Context.Key
with the given name and default value.public static Context current()
null
as
the ROOT
context is implicitly associated with all threads.
Will never return Context.CancellableContext
even if one is attached, instead a
Context
is returned with the same properties and lifetime. This is to avoid
code stealing the ability to cancel arbitrarily.
public Context.CancellableContext withCancellation()
Context.CancellableContext.cancel(Throwable)
or Context.CancellableContext.detachAndCancel(Context, Throwable)
are called to notify
listeners and release the resources associated with them.
Sample usage:
Context.CancellableContext withCancellation = Context.current().withCancellation(); try { executorService.execute(withCancellation.wrap(new Runnable() { public void run() { Context current = Context.current(); while (!current.isCancelled()) { keepWorking(); } } }); doSomethingRelatedWork(); } catch (Throwable t) { withCancellation.cancel(t); }
public Context.CancellableContext withDeadlineNanoTime(long deadlineNanoTime)
System.nanoTime()
clock. The returned context will cascade
cancellation of its parent. Callers may explicitly cancel the returned context prior to
the deadline just as for withCancellation()
,
It is recommended that callers only use this method when propagating a derivative of
a received existing deadline. When establishing a new deadline, withDeadlineAfter(long, java.util.concurrent.TimeUnit)
is the better mechanism.
public Context.CancellableContext withDeadlineAfter(long duration, TimeUnit unit)
duration
from now.
The returned context will cascade cancellation of its parent. Callers may explicitly cancel
the returned context prior to the deadline just as for withCancellation()
,
Sample usage:
Context.CancellableContext withDeadline = Context.current().withDeadlineAfter(5, TimeUnit.SECONDS); executorService.execute(withDeadline.wrap(new Runnable() { public void run() { Context current = Context.current(); while (!current.isCancelled()) { keepWorking(); } } });
public <V> Context withValue(Context.Key<V> k1, V v1)
Context withCredential = Context.current().withValue(CRED_KEY, cred); executorService.execute(withCredential.wrap(new Runnable() { public void run() { readUserRecords(userId, CRED_KEY.get()); } }));
public <V1,V2> Context withValues(Context.Key<V1> k1, V1 v1, Context.Key<V2> k2, V2 v2)
public <V1,V2,V3> Context withValues(Context.Key<V1> k1, V1 v1, Context.Key<V2> k2, V2 v2, Context.Key<V3> k3, V3 v3)
public Context.CancellableContext fork()
public Context attach()
current()
, the previously current context
is returned. It is allowed to attach contexts where isCancelled()
is true
.public void detach(Context toAttach)
current()
a SEVERE message will be logged but the context to attach
will still be bound.public boolean isCancelled()
@Nullable public Throwable cause()
isCancelled()
then return the cause of the cancellation or
null
if context was cancelled without a cause. If the context is not yet cancelled
will always return null
.
The cause is provided for informational purposes only and implementations should generally assume that it has already been handled and logged properly.
public void addListener(Context.CancellationListener cancellationListener, Executor executor)
public void removeListener(Context.CancellationListener cancellationListener)
Context.CancellationListener
.public Executor wrap(Executor e)
Executor
so that it executes with this context as the current()
context.
It is generally expected that propagate(Executor)
would be used more commonly than
this method.propagate(Executor)
public static Executor propagate(Executor e)
current()
context when Executor.execute(java.lang.Runnable)
is called to the current()
context of the Runnable
scheduled. Note that this
is a static method.wrap(Executor)