This is a short introduction on how to use the various asynchronous I/O primitives or Async's available in Coconut AIO.
There are three different techniques for using them as we will explain in the following three paragraphs.
Futures
Most methods that block return some kind of result. An asynchronous method must return immediately without doing the actual computation. Instead of returning the actual result we return a Future which is a placeholder of the result of an asynchronous computation. Futures were first introduced in Multilisp, a dynamically typed, yet statically scoped version of Lisp that is specially designed for parallel computations.
To use Coconut AIO in "Future mode" you can open a new Async with (Taking an AsyncSocket as an example):
This returns a new Async immediately. By invoking one of its asynchronous methods you can receive a Future:
The following operations are available on the Future that is returned from the asynchronous method.
Method |
Description |
|---|---|
boolean cancel(boolean mayInterruptIfRunning) |
Attempts to cancel the execution of this I/O operation. |
V get() |
Waits if necessary for the I/O operation to complete, and then retrieves its result. |
V get(long timeout, TimeUnit unit) |
Waits if necessary for at most the given time for the I/O operation to complete, and then retrieves its result, if available. |
boolean isCancelled() |
Returns true if this I/O operation was cancelled before it completed normally. |
boolean isDone() |
Returns true if this I/O operation has completed. |
As a general rule a Future is created and returned to a client when it initiates an asynchronous method. When the client wants to receive the result of an asynchronous method call, it can do so by making a rendezvous with the Future, the get() method, which behaves in one of the following two manners.
- The Future has been resolved already. That is, the method calculating the value has finished, and has stored the result in the Future. Asking for the Future's value will immediately return the result.
- The Future has not been resolved. In this case, the current thread is blocked until the Future resolves. The current thread is effectively synchronizing with the thread calculating the value.
Callbacks
A Callback is an argument passed from a parent function to a child function, the Callback argument is itself a third function. By passing a Callback function the parent provides instructions to the child about how to behave when some condition occurs.
In Coconut we use the following interface to specify a Callback:
In this way the user can provide a Callback to an Async detaling how it should behave once the particular I/O operation completed. It is then the responsibility of the Async to call either the completed(E result) method with the result of the I/O operation or in the case of failure the failed(Throwable cause) method indicating the cause of the failure.
To use Coconut AIO in "Callback mode" you can open a new Async with:
An Executor provides a way of decoupling task submission from the mechanisms of how each task will be run, including details of thread use, scheduling etc. Since the threads in the AIO subsystem lives in their own little enviroment the user must specify an Executor that handles the execution of any Callback provided by the user.
If you specify an Executor when opening an Async you can use the Async in the following way:
When the asynchronous methods completes in delegates the execution of the Callback to the Executor that was provided when the Async was opened. The AIO runtime automatically wraps the Callback in a Runnable instance that can be executed by the Executor.
If you for some reason need to have separate Executors depending on which methods you are calling you can choose to open an Async without specifying an specifying an Executor:
and instead provide an Executor as the first parameter when specifying the Callback:
Offerables and Queue
In classical flow network theory, a Source is an origin of events and a Sink is a consumer of events. In Coconut an Offerable is a consumer of events, for example, an event indicating that a AsyncSocket has succesfully connected to a remote host.
In Coconut we use the following interface for an Offerable:
The signature of the offer method is the same as the offer() method in java.util.Queue(Javadoc|Javadoc) interface and any implementation of the offer() method should be non-blocking and only take a short duration.
To use Coconut AIO in "Offerable mode" you can open a new Async with:
As an alternative you can use an instance of java.util.Queue to open an new Async with
Each Async exports a number of predefined events that are passed along to the offer() method whenever something "interesting" happens. For example, here are the events AsyncSocket exports (all of them are defined as inner classes).
Method |
Description |
|---|---|
An event indicating that the asynchronous socket was closed either normally by calling its close() method or due to some failure. |
|
An event indicating that the socket successfully connected to a remote host. |
|
Indicates that the socket failed while doing an I/O operation, for example, while trying to connect to a remote host. |
|
An event indicating that the socket successfully started reading data on the socket. |
|
Indicating that a particular packet was successfully written to the socket. |
