|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Object org.lightwolf.Flow
public final class Flow
An execution context similar to that of a thread, but with more capabilities.
Compared to normal threads
, flows simplifies the
implementation of concurrent algorithms and scalable applications. The
following list summarizes the capabilities of a flow:
suspended
for later
resuming
, without consuming a Java thread meanwhile.Continuation
, fork(int)
,
and returnAndContinue()
.There are some important concepts regarding flows.
Flow-method: A flow-method is a method marked with the
FlowMethod
annotation. Whenever a flow-method is executing, there
will be an associated flow instance, which can be obtained by invoking
current()
(such flow is automatically instantiated as described
below). If a flow-method invokes itself or another flow-method, both methods
use the same flow instance. If a flow-method invokes a normal (non-flow)
method, the flow is kept active and can be queried, but some flow utilities
will disabled until the normal method returns to the invoker flow-method.
Flow-creator: Whenever a flow-method is invoked
by a normal (non-flow) method, it is called the flow-creator method, because
it triggers the creation of a new flow (this is done automatically). The flow
ends when the flow-creator completes normally or by exception. If the
flow-creator calls itself or another flow-method, no new flow is created, as
described above.
Flow-controller: The flow-controller is a
normal (non-flow) method that invokes a flow-method. The flow-controller
receives signals sent by some flow
operations, and must handle those signals accordingly. There are standard
implementations of flow-controllers, such as
According to the above specification, when a flow-method A invokes a
normal method B, and then B invokes a flow-method C, a
nested flow is created. Regarding the nested flow, B will be the
flow-controller and C the flow-creator. If C invokes a flow
utility such as
If a flow A belongs to a
execute(Callable)
and
SimpleFlowManager
. If it is known that a flow-method will never send
signals, the flow-controller can be any ordinary method calling a
flow-method. Many utilities do not send any signal, such as
split(int)
and returnAndContinue()
.
fork(int)
, the effect is applied only to the nested
flow. The outer flow, on which A is running, is not affected by the
fork. When the nested flow ends or is suspended, the outer flow becomes
active again. The number of nesting levels is limited only by memory. Nested
flows are uncommon because usually flow-methods are designed to call other
flow-methods, which does not cause the creation of new flow, as mentioned
above. Nevertheless, nested flows are allowed as an orthogonality feature.
Process
, then every flow B
derived from A will automatically belong to the same process. Derived
flows are result of shallow copies. Many utilities
perform shallow copies, including but not limited to fork(int)
,
returnAndContinue()
and Continuation
.
FlowMethod
,
Process
,
Serialized Form
Field Summary | |
---|---|
static int |
ACTIVE
A constant indicating that the flow is active. |
static int |
ENDED
A constant indicating that the flow is ended. |
static int |
PASSIVE
A constant indicating that the flow is passive. |
static int |
SUSPENDED
A constant indicating that the flow is suspended. |
Method Summary | |
---|---|
Future<?> |
activate()
Equivalent to activate(null) . |
Future<?> |
activate(Object signalResult)
Schedules this flow to resume in another thread. |
Future<?> |
activateThrowing(Throwable exception)
Schedules this flow to resume in another thread, and throws an exception upon resuming. |
Flow |
copy()
Performs a shallow copy on this flow. |
static Flow |
current()
Returns the current flow. |
static void |
end()
Ends the current flow. |
static void |
endFork()
Ends the current fork without waiting for any branch. |
static Object |
execute(Callable<?> callable)
|
static void |
execute(Runnable runnable)
|
static void |
forgetFork()
Forgets the current fork without waiting for any branch. |
static boolean |
forgetProcess()
Removes the current flow from its current process. |
static int |
fork(int n)
Starts a fork on the invoker. |
FlowManager |
getManager()
|
Flow |
getPrevious()
|
Object |
getResult()
|
int |
getState()
This flow's state, which will be ACTIVE , SUSPENDED or
ENDED . |
boolean |
isActive()
|
boolean |
isEnded()
|
boolean |
isSuspended()
|
Object |
join()
|
static void |
joinProcess(Process process)
Adds the current flow to the informed process. |
static void |
leaveProcess()
Removes the current flow from its current process. |
static void |
log(String msg)
|
static void |
merge()
Ends a fork by restoring single-threaded execution. |
static boolean |
merge(long timeout,
TimeUnit unit)
Attempts to end a fork, or give-up after a timeout elapses. |
static Flow |
newFlow()
Creates and returns a new flow. |
static Process |
process()
The process to which this flow belongs. |
Object |
resume()
Equivalent to resume(null) . |
Object |
resume(Object signalResult)
Resumes this flow. |
Object |
resumeThrowing(Throwable exception)
Resumes this flow throwing an exception. |
static void |
returnAndContinue()
Performs return while continuing asynchronously. |
static void |
returnAndContinue(boolean v)
Performs return boolean-value while continuing
asynchronously. |
static void |
returnAndContinue(byte v)
Performs return byte-value while continuing
asynchronously. |
static void |
returnAndContinue(char v)
Performs return char-value while continuing
asynchronously. |
static void |
returnAndContinue(double v)
Performs return double-value while continuing
asynchronously. |
static void |
returnAndContinue(float v)
Performs return float-value while continuing
asynchronously. |
static void |
returnAndContinue(int v)
Causes a method to return an int while continuing
asynchronously. |
static void |
returnAndContinue(long v)
Performs return long-value while continuing
asynchronously. |
static void |
returnAndContinue(Object v)
Performs return reference-value while continuing
asynchronously. |
static void |
returnAndContinue(short v)
Performs return short-value while continuing
asynchronously. |
static Flow |
safeCurrent()
Returns the current flow, or throws an exception if there is no current flow. |
static Object |
signal(FlowSignal signal)
Suspends the flow and sends a signal to the flow-controller. |
static Flow |
snapshot()
|
static int |
split(int n)
Initiates concurrent execution on the invoker. |
Flow |
streamedCopy()
|
static Flow |
submit(Callable<?> callable)
|
static Flow |
submit(Runnable runnable)
|
static Object |
suspend()
Equivalent to suspend(null) . |
static Object |
suspend(Object argument)
Suspends the current flow, allowing the current thread to be released. |
Object |
waitNotRunning()
|
Object |
waitSuspended()
|
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
public static final int ACTIVE
Thread
. When a
flow method calls a non-flow method, the flow
will remain active. A flow will move out from active state when the flow-creator returns or when the flow is
suspended.
getState()
,
Constant Field Valuespublic static final int SUSPENDED
Thread
. A
suspended flow is always stopped at the point of invocation of
signal(FlowSignal)
or higher level methods such as
suspend(Object)
or Continuation.checkpoint()
. This means
it can be resumed with one of the resume()
methods.
getState()
,
Constant Field Valuespublic static final int PASSIVE
SUSPENDED
flow.
getState()
,
Constant Field Valuespublic static final int ENDED
end()
is called. An ended flow cannot be
resumed, but it can be passed for the method
Continuation.placeOnCheckpoint(Flow)
.
getState()
,
Constant Field ValuesMethod Detail |
---|
public static Flow newFlow()
ENDED
state, which is suitable to be passed as argument to methods such as
Continuation.resume(Flow)
.
ENDED
state.public static void execute(Runnable runnable)
public static Object execute(Callable<?> callable)
public static Flow submit(Runnable runnable)
public static Flow submit(Callable<?> callable)
public static Process process()
Process
, or null
if this flow
does not belong to any process.joinProcess(Process)
,
leaveProcess()
public static void joinProcess(Process process)
process
- The process to which the current flow will be added. Must
not be null
.
IllegalStateException
- If the invoker is not a FlowMethod
.
NullPointerException
- If the informed process is a
null
reference.Process
,
leaveProcess()
,
forgetProcess()
public static void leaveProcess()
null
, or
throws an exception if the current flow does
not belong to any process.
IllegalStateException
- If the invoker is not a FlowMethod
,
or if the current flow does not belong to any process.joinProcess(Process)
,
forgetProcess()
public static boolean forgetProcess()
null
, or
does nothing if the current flow does not
belong to any process.
IllegalStateException
- If the invoker is not a FlowMethod
.joinProcess(Process)
,
leaveProcess()
public static Flow snapshot()
public static int split(int n)
This method creates n shallow copies of the
current flow, then executes each copy concurrently and starting from the
invocation point. In other words, this method is invoked once, but
returns 1+n times: 1 time for the invoker, and n times for
new flows. Notice that split(0)
is a no-effect
operation.
The returned value is an int
that identifies the flow to
which the method returned. It will be 0
for the invoker, and
a distinct positive integer for new flows, ranging from 1
to
n.
The following example illustrates this behavior:
void example() { System.out.println("Before doFlow()"); int i = doFlow(); System.out.printf("doFlow(): %d\n", i); } @The above snippet prints the following (under fair scheduling conditions):FlowMethod
int doFlow() { System.out.println("Before performSplit()"); int i = performSplit(); System.out.printf("performSplit(): %d\n", i); return i; } @FlowMethod
int performSplit() { System.out.println("Before split(2)"); int i = Flow.split(2); System.out.printf("Split result: %d\n", i); return i; }
Before doFlow() Before performSplit() Before split(2) Split result: 0 Split result: 1 Split result: 2 performSplit(): 0 performSplit(): 1 performSplit(): 2 doFlow(): 0
Each of the created flow runs on a possibly different thread (the actual thread is defined by the flow manager), and will be independent from all other flows, including the invoker. As defined by the shallow copy behavior, all flows share heap objects referenced by the invoker stack frames at the time of invocation.
If there is an active fork at the time of
invocation, the invoker will remain on such fork, hence methods such as
merge()
and forgetFork()
are still valid for the
invoker. On the other hand, the newly created flows will be outside any
fork, which means that invoking merge()
and
forgetFork()
before an explicit fork on such flows will cause an
exception to be thrown.
n
- The number of flows to create. Must be non-negative.
1
to n
for each new
branch.
IllegalArgumentException
- If n is negative.
IllegalStateException
- If the invoker is not a FlowMethod
.fork(int)
public static int fork(int n)
This method is similar to split(int)
. In addition to create new
flows, it makes the invoker and each of the created flows to run in the
context of a fork. The invoker will stay in the fork until it explicitly
merges or forgets. As a
convention in this documentation, new flows created by this method are
called branches, and the flow that invokes this method is called
the fork-creator.
If this method is invoked during a previous fork, a nested fork is
established. This method changes the behavior of merge()
and
other fork-ending methods, which always applies to the innermost fork.
Because of this, it is recommended to use the structured fork/merge
style, which use try
/finally
blocks as in the
following example:
... // Single-threaded execution.
int branch = Flow.fork(n);
try {
... // Concurrent execution by n threads.
} finally {
Flow.merge()
;
}
... // Single-threaded execution.
The returned value is an int
that identifies the branch to
which the method returned. It will be 0
for the invoker, and
a distinct positive integer for new branches, ranging from 1
to n.
If parameter n is zero, no new flow will be instantiated and the invoker will continue execution in single-threaded mode. Still, the next fork-ending operation will apply to such fork.
n
- The number of branches to create. Must be non-negative.
1
to n
for each
new branch.
IllegalArgumentException
- If n is negative.
IllegalStateException
- If the invoker is not a FlowMethod
.merge(long, TimeUnit)
,
forgetFork()
public static void merge() throws InterruptedException
If the invoker is the fork-creator: This method blocks until each of the corresponding branches ends (see below), or until this thread is interrupted, whichever comes first. If the merge is successful (all branches have ended), the invoker exits the fork, restoring the next outer fork, if any. Otherwise (the thread is interrupted while at least one branch is active), the invoker will stay in the fork. If all other branches have ended before invocation of this method, it will return immediately without checking the thread's interrupt flag.
If the invoker is a branch: This method does not return. It ends
the flow immediately, as if end()
were invoked. Notice that even
finally
blocks will not execute.
This method considers only branches created by the last invocation of
fork(int)
.
A branch will be active (that is, it will not end) until one of the following happens:
end()
.merge()
or
merge(long, TimeUnit)
.forgetFork()
.endFork()
.Whenever this method returns normally, it is guaranteed that the invoker was the fork-creator and no branch will be active.
InterruptedException
- If the current thread was interrupted while
there was at least one active branch.
IllegalStateException
- If the invoker is not a FlowMethod
.fork(int)
,
merge(long, TimeUnit)
,
forgetFork()
public static boolean merge(long timeout, TimeUnit unit) throws InterruptedException
merge()
. Depending on who is
the invoker, the behavior will be different.
If the invoker is the fork-creator: This method blocks until each
of the corresponding branches ends (see merge()
), or until the
given timeout expires, or until this thread is interrupted, whichever
comes first. If the merge is successful (all branches have ended before
the timeout expire), the invoker exits the fork, restoring the next outer
fork, if any, and this method returns true
. If the timeout
expires while at least on branch is active, the invoker will stay in the
fork, and this method returns false
. Otherwise (the thread
is interrupted while at least one branch is active), the invoker will
stay in the fork. If all other branches have ended before invocation of
this method, it will return immediately without checking the thread's
interrupt flag.
If the invoker is a branch: This method does not return. It ends
the flow immediately, as if end()
were invoked. Notice that even
finally
blocks will not execute.
Whenever this method returns normally, it is guaranteed that the invoker will be the fork-creator.
true
if all other branches have ended,
false
if there was at least one active branch when
the timeout elapsed.
InterruptedException
- If the current thread was interrupted during
the wait for branches to end.
IllegalStateException
- If the invoker is not a FlowMethod
.
NullPointerException
- If unit
is null.fork(int)
,
merge()
,
forgetFork()
public static void forgetFork()
If the invoker is the fork-creator, this method exits the fork and
restores the next outer fork, if any, and then immediately returns. If
the invoker is a branch, the flow will continue to run on the same
thread, but "detached" from the fork, as if created by
split(int)
. Therefore the fork-creator will consider this branch
as ended, which means that it might unblock an ongoing call to
merge()
in the fork-creator.
This method does not cause the current flow to end, even if the invoker
is a branch. If you need this, use endFork()
instead.
IllegalStateException
- If the invoker is not a FlowMethod
.fork(int)
,
merge(long, TimeUnit)
,
endFork()
public static void endFork()
If the invoker is the fork-creator, this method exits the fork and
restores the next outer fork, if any, and then immediately returns. If
the invoker is a branch, it will end the flow immediately, as if
end()
were invoked. This means that it might unblock an ongoing
call to merge()
in the fork-creator.
IllegalStateException
- If the invoker is not a FlowMethod
.fork(int)
,
merge(long, TimeUnit)
,
forgetFork()
public static void end()
void example() {
System.out.println("Before doFlow()");
int i = doFlow();
System.out.printf("doFlow(): %d\n", i);
}
@FlowMethod
int doFlow() {
System.out.println("Before end()");
Flow.end();
System.out.println("After end()");
return 5;
}
The above snippet prints the following:
Before doFlow() Before end() doFlow(): 0
This method causes the flow-creator to return a "zero" value corresponding to its return type:
null
.0
.false
.(char) 0
.
If the current flow was created by an utility such as split(int)
or returnAndContinue()
, this method never returns and simply
releases the current thread.
IllegalStateException
- If the invoker is not a FlowMethod
.public static void returnAndContinue()
return
while continuing asynchronously.
This method is used to perform a local split
operation. In the current flow, it works as if return
were
executed. In a newly created flow, the invoker is resumed from the point
of invocation. The new flow starts from the invoker method, and not from
the flow-creator as it would be if
split(int)
were used. The following example illustrates this
behavior:
@FlowMethod
void example() { System.out.println("Before doFlow()"); doFlow(); System.out.println("After doFlow()"); Thread.sleep(50); // Schedule the new flow's thread. System.out.println("Done"); } @FlowMethod
void doFlow() { System.out.println("Before returnAndContinue()"); Flow.returnAndContinue(); System.out.println("After returnAndContinue()"); }
The above example prints the following:
Before doFlow() Before returnAndContinue() After doFlow() After returnAndContinue() Done
Notice that the new flow ends when the method doFlow()
ends.
Calling this method more than once in the same method works, but is
redundant because in the second and subsequent calls, the work doesn't
need to be done in a new flow.
This method must be called only by a void
method. There is
one version of this method for each possible return value.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
void
method.public static void returnAndContinue(boolean v)
return
boolean-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a boolean
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
boolean
method.public static void returnAndContinue(char v)
return
char-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a char
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
char
method.public static void returnAndContinue(byte v)
return
byte-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a byte
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
byte
method.public static void returnAndContinue(short v)
return
short-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a short
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
short
method.public static void returnAndContinue(int v)
int
while continuing
asynchronously.
This method is used to perform a local split
operation. In the current flow, it works as if return v
were
executed. In a newly created flow, the invoker is resumed from the point
of invocation. The new flow starts from the invoker method, and not from
the flow-creator as it would be if
split(int)
were used. The following example illustrates this
behavior:
@The above example prints the following:FlowMethod
void example() { System.out.println("Before doFlow()"); int i = doFlow(); System.out.printf("doFlow(): %d\n", i); Thread.sleep(50); // Schedule the new flow's thread. System.out.println("Done"); } @FlowMethod
int doFlow() { System.out.println("Before returnAndContinue()"); Flow.returnAndContinue(123); System.out.println("After returnAndContinue()"); return 456; }
Before doFlow() Before returnAndContinue() doFlow(): 123 After returnAndContinue() Done
Notice that the new flow ends when the method doFlow()
ends.
Hence the value of the actual return
statement (
456
in the example) is discarded. Calling this method more
than once in the same method works, but is redundant because in the
second and subsequent calls, the work doesn't need to be done in a new
flow.
This method must be called only by an int
method. There is
one version of this method for each possible return value.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not an
int
method.public static void returnAndContinue(long v)
return
long-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a long
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
long
method.public static void returnAndContinue(float v)
return
float-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a float
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
float
method.public static void returnAndContinue(double v)
return
double-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for a double
method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a
double
method.public static void returnAndContinue(Object v)
return
reference-value while continuing
asynchronously. This method is similar to returnAndContinue(int)
, except for that it must be invoked for an reference method.
v
- The value to return.
IllegalStateException
- If the invoker is not a FlowMethod
.
IllegalReturnValueException
- If the invoker is not a reference
method.
ClassCastException
- If the returned object is not assignable to
the invoker's return type.public static Object suspend()
suspend(null)
.
public static Object suspend(Object argument)
SuspendSignal
to the flow-controller, which by
default does
nothing. This can be used to
release the current thread to other tasks.
The informed argument is simply passed to the
constructor of
SuspendSignal
, and can be later obtained, usually in the flow-controller, by invoking
SuspendSignal.getResult()
. The informed argument is usually used
to tell the reason of suspension. That is, its usually a merely
informative value, used for debugging and tracing purposes.
When a flow chooses to suspend itself, it usually must provide means to
be resumed when some event occurs, and not
rely on the flow-controller for this task. For example, if a flow chooses
to suspend itself while waiting for user input, it should store
itself on the user's session storage
before suspending, so that when user input happens, the event
handler can invoke resume(Object)
on the suspended flow.
This method returns the value passed to resume(Object)
, and
might throw an exception if resumeThrowing(Throwable)
were
instead used. This method can return multiple times and/or in different
flows, at the discretion of whoever uses the suspended flow.
This method behaves exactly as the expression
signal(new SuspendSignal(argument))
.
argument
- The argument to be associated with SuspendSignal
.
resume(Object)
.signal(FlowSignal)
,
suspend()
,
SuspendSignal
,
resume()
,
resume(Object)
public static Object signal(FlowSignal signal)
This method first suspends the current flow at the point of invocation. Then it sends the specified signal to the flow-controller, as if the signal were thrown by the flow-creator (see below). After this, the next actions are fully determined by the flow-controller, which typically uses the signal to decide.
This method returns only when the flow-controller invokes a
resume
method (see below) on this flow or on a copy. Notice
that this method may complete on a different flow and it may also
complete more than once, at the discretion of the flow-controller.
Although the signal is an exception, this method doesn't throw the signal on the current flow. The signal is thrown by the subsystem after the flow have been suspended. To the flow-controller, the signal appears to have been thrown by the flow-creator. This mechanism is illustrated in the following snippet:
void example() { // This is the flow-controller. try { doFlow(); System.out.println("doFlow() returned"); } catch (FlowSignal signal) { System.out.println("Caught by the flow-controller"); System.out.println("Calling Flow.resume()"); signal.getFlow().The above snippet prints the following:resume()
; System.out.println("Flow ended"); } } @FlowMethod
void doFlow() { // This is the flow-creator. try { doSignal(); System.out.println("doSignal() returned"); } catch (FlowSignal signal) { System.out.println("Caught by the flow-creator"); } } @FlowMethod
void doSignal() { // This is an ordinary flow method. try { System.out.println("Sending signal"); FlowSignal signal = new MyFlowSignal(); Flow.signal(signal); System.out.println("Returned from signal (resumed)"); } catch (FlowSignal signal) { System.out.println("Caught by doSignal()"); } }
Sending signal Caught by the flow-controller Calling Flow.resume() Returned from signal (resumed) doSignal() returned Flow endedThe flow-controller can, among other actions, create a shallow copy of this flow, serialize this flow and deserialize in another machine instance, ignore the signal and never resume, or wait for some specific condition before resuming. To provide satisfactory usability, the flow-controller must proceed as specified by the received signal object. There are some well-known signal classes such as
DelayedCallSignal
and SuspendSignal
, but developers are
free to create new signals, as long as they provide support for them in
the flow-controller.
The completion of this method depends on the chosen resume
method:
resume()
, this method returns
null
.resume(Object)
, this method
returns the object passed to the resume
method.resumeThrowing(Throwable)
, this
method throws ResumeException
whose
cause is the exception passed to the
resumeThrowing
method.
This method is used to implement utilities such as
suspend(Object)
and ThreadFreeLock
. It is the lowest
level API for implementing features such as releasing a pooled thread
before completion and serializing thread state for long running
processes.
signal
- The signal to be sent to the flow-controller.
resume(Object)
method.
IllegalStateException
- If the invoker is not a FlowMethod
.
NullPointerException
- If signal
is null
.
ResumeException
- If the flow is resuming through
resumeThrowing(Throwable)
.public static Flow current()
null
. The current flow will always be
ACTIVE
.
null
no flow method is running on the current thread.public static Flow safeCurrent()
current()
, except in that it never
returns null
. In the absence of a current flow, it will
throw an exception.
IllegalStateException
- If there is no current flow.public static void log(String msg)
public FlowManager getManager()
public Flow getPrevious()
public int getState()
ACTIVE
, SUSPENDED
or
ENDED
.
waitSuspended()
,
waitNotRunning()
public boolean isActive()
public boolean isSuspended()
public boolean isEnded()
public Object resume()
resume(null)
.
public Object resumeThrowing(Throwable exception)
signal(FlowSignal)
inside this flow to throw a
ResumeException
whose cause is
the informed exception.
In all other aspects, this method behaves as resume(Object)
.
That is, the invoker will block until the flow completes, will be the new
flow-controller, and might need to handle
signals.
exception
- The exception that will be the cause of the
ResumeException
to be throwed.
null
if the
flow-creator is a void
method.
NullPointerException
- If exception
is null.
IllegalStateException
- If this flow is not suspended.signal(FlowSignal)
,
resume(Object)
,
activateThrowing(Throwable)
public Object resume(Object signalResult)
signal(FlowSignal)
inside this flow to return. The flow resumes
execution directly on the current thread, and therefore this method only
returns when the flow finishes. This means that the invoker of this
method will be the new flow-controller, and
might need to handle signals. To resume
this flow on another thread, use activate(Object)
.
The informed parameter is simply returned to the flow as a normal result
of signal(FlowSignal)
.
The completion of this method is defined as follows:
FlowException
having the exception as its
cause.
resume(Object)
will behave as an
ordinary flow-controller.
signalResult
- The value that signal(FlowSignal)
must
return to its invoker.
null
if the
flow-creator is a void
method.
IllegalStateException
- If this flow is not suspended.signal(FlowSignal)
,
resume()
,
resumeThrowing(Throwable)
,
activate()
,
activate(Object)
public Future<?> activate()
activate(null)
.
public Future<?> activateThrowing(Throwable exception)
activate(Object)
, except in that resuming is done with
resumeThrowing(Throwable)
instead of resume(Object)
.
resumeThrowing(Throwable)
,
activate()
,
activate(Object)
public Future<?> activate(Object signalResult)
FlowManager.submit(Flow, Object)
method, which will assign resume
execution to some thread. The thread's run is a simple flow-controller. It can be roughly defined by
this pseudo-code:
public void run() { try { flow.resume(signalResult); } catch (FlowSignal signal) { signal.defaultAction(); // Always call the default action. } catch (Throwable e) { log(e); // Logs the exception. } }The returned
Future
can be use to query execution status. Notice
that if such Future
is done, it
does not necessarily means that the flow finished.
Future.isDone()
will return true
even when the flow
was just suspended.
signalResult
- The argument to be passed to resume(Object)
method. This argument will be returned to the flow by the
signal(FlowSignal)
that causes suspension.
Future
that can be used to query execution status.resume(Object)
,
activate()
,
activateThrowing(Throwable)
public Flow copy()
If this flow is suspended, the returned copy can be
resumed and it will run just after the suspend
invocation, as if it were suspended by itself. This process does not
affect the current flow, which was only the source in a copy operation.
Many copies can be created from a single flow, which allows
implementation of utilities such as split(int)
and
EventPicker
.
The target flow must be either suspended or ended, and hence this method
cannot be used to copy a running flow. To get the state of a running
flow, use Continuation
.
IllegalStateException
- If this flow is not suspended nor ended.public Flow streamedCopy()
public Object join() throws InterruptedException
InterruptedException
public Object waitSuspended() throws InterruptedException
InterruptedException
public Object waitNotRunning() throws InterruptedException
InterruptedException
public Object getResult()
|
||||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |