Showing posts with label concurrency. Show all posts
Showing posts with label concurrency. Show all posts

Sunday, November 23, 2008

Asynchronous transitions for Active Objects

I've added support for asynchronous transitions in ActiveObjectSupport (see parts 1, 2 and 3 in the series).

The asynchronous versions share the same logic of the synchronous ones. The preconditions are checked in the calling thread, the state change to a transient state is also done in the calling thread (as it was previously shown it's just an update to an atomic reference) and the transition is performed in a background thread, including waiting for pending requests to finish.

Why did I add this feature now? Well, I'll need it for the next iteration of lucis.

Saturday, November 8, 2008

Thread-safe simple lifecycle (part 3)

In parts parts one and two of these mini-series, we started showing how going multi-thread could affect the simplest lifecycle of what we called and active object. In the end, what we have is a set of open questions, including (some of them were presented in previous posts):
  • What happens if you try to start the object and some other thread have previously done so?
  • What happens if several threads try to stop the object at the same time?
  • What happens if you try to stop the object when there are in-flight requests? Do we wait for them to finish? Do we stop and let them crash?
And the answer to all these questions is the same: it depends. It depends on the semantics of each particular object, so we can't provide a solutions suitable for everyone, every time. But this doesn't mean we can't do anything. I've checked in a new solution. Some of the highlights include:
  • The lifecycle interface is gone. As we have shown different problems need different semantics and thus, a different interface. Instead, we have a support class.
  • Though externally the same fixed-set of states is kept (implemented as an enumerated type), internally an infinite set of states is used, so that we can keep track of in-flight requests.
  • No synchronization is used, and state changes are performed using atomic references. Client-provided transition code is guaranteed to be run by just one thread without holding any locks.
  • No standard semantics are enforced. Instead, the support class provides methods so that you can build your own. Eg, if you call a method to start or stop the object while the transition is being performed in another thread an exception is thrown. However you can catch this exception and use the provided methods to wait for the object to reach a permanent exception to implement different semantics.


Tuesday, October 7, 2008

Thread-safe simple lifecycle (part 2)

After last post, there are some issues that remain open:
  • Do clients need to know about transient states? After all, in our multithreaded environment we only want to know if the service provided by the active object is ready to be used or not, regardless of which thread's start command did the trick.
  • What happens if we stop the object while there are in-flight requests that depend on the ON state (such as a resource disposed after a stop command)? Can we provide deterministic behaviors for these cases? Can we provide them minimizing synchronized regions and contention?
Stay tuned.

Sunday, October 5, 2008

Thread-safe simple lifecycle.

The subject today is not rocket science,  but it's been common enough through the years to deserve a post :). The problem is as follows: we have and object with a very simple lifecycle (on and off) and we need (or want) the status-changing methods (start and stop) to be thread-safe.

Of course, we can just make start and stop synchronized but, can we do better? Ok, let's polish our list of desired features:
  • We want a generic solution. We only want to write the transition code (starting up and shutting down) without worrying about thread-safety, getting it for free from the solution.
  • We want to minimize synchronization, and ideally avoid it.
  • If we can't avoid synchronization, we forbid calling alien methods from synchronized regions (to avoid unforeseen problems in the future).
So, I've checked-in a possible solution. It avoids synchronization by adding some transient states and using AtomicReference (the java.util.concurrent.atomic package contains equivalent classes for different types). More specifically, the solution is based on the compareAndSet method, which besides the properties described in the documentation, has the added benefit of being idempotent, a property that really simplifies reasoning in concurrent and distributed systems, at very different levels of abstraction.

Update: Changed svn links to tagged version.