Overview
Prometheus is a concurrency library for Java 5 and higher and will be released under the MIT license. The main goal of the project is to provide higher level concurrency control abstractions to reduce concurrency control related complexity. Prometheus relies on the java.util.concurrent library that is introduced in Java 5 and tries to make use of this package where possible.
First release
The first release candidate of version 0.1 has been released. No new functionality will be added to the first release, the primary focus will be on improving tests (unit/integration/performance) and documentation.
The following features are planned for the first release:
- AwaitableReference: a synchronization abstraction that makes it easy to pass references from one thread to another or block if no reference is available.
- LendableReference: a synchronization abstraction that extends the AwaitableReference and adds the concept of taking back items. This provides a way to control which references are lend: if a LendableReference is strict, it doesn't allow different references to be lend at any given moment. If a new reference is set, the call blocks until all lend references are returned. The opposite of the strict version is the relaxed LendableReference: it doesn't care if different references are lend at any given moment, so placing a new item can be done without long blocking.
- Repeater: a threadpool structure that is responsible for repeating tasks. An Executor is great for executing a task once, but a Repeater provides a better abstraction for repeatedly executing tasks.
- BlockingExecutor: a threadpool structure like the Executor but provides more control on blocking and timeout behaviour.
- ConditionUtil & LockUtil: contain various functions for Lock and Condition instances.
- UninterruptibleSection: provides a way to do interruptible calls in locations where you can't deal with interrupts.
- Latch: a synchronization abstraction that provides a single shot waiting mechanism. It can be used to wait for a final state change to occur, like the complete shutdown of a Repeater for example.
- JMX: MBeans for various structures so they can be controlled in a serverside environment.
- Test support: a set of classes/interfaces and utilities to test multi-threaded code.
Future features
A lot of functionality has been removed from the first version, to prevent delaying an initial release indefinitely, and moved to a later version. But a lot of nice features (the best ones imho) are planned:
-
Channels: a data exchange abstraction. A BlockingQueue
can be quite troublesome when you are working with producer/consumer
solutions because they have many responsibilities:
- placement of items (put/offer methods)
- storage of items (it extends the Collection interface)
- retrieval of items (take, poll methods)
- the OutputChannel is responsible for placement of items
- the InputChannel is responsible for retrieval of items
-
Processes & Processors: provide a 'framework' for setting up assembly lines ('pipes
and filters'). And can be used to set up applications that need to process large amounts of data
like batch applications. The main goal is to separate 2 aspects:
- the actual processing of messages (in most cases some form of transformation)
- plumbing: connecting processes (either directly or by some form of queueing), threading, exception handling and pattern matching on message type.
- Waitpoint: an abstraction for blocking behaviour. By injecting different waitpoints one is able to customize the blocking behaviour of various components. One of the usages would be a BlockingQueue that is able to throttle the intake of items, or is able to pauze the taking of items. This could be used to make an Executor pause for example.
- Waitsections: extend the concept of Waitpoints. Waitpoints don't have any with, you either in front of a waitpoint, or you have passed it. With a Waitsection there is a period a thread is inside the waitpoint.
- Deadlock safe calls: writing deadlock free code can be very complicated (almost impossible) but deadlocks can be prevented. Deadlock detection is not obligated by the JVM, but another solution is to limit the amount of time for waiting on a resource (like a Lock). But adding timeouts to calls can be quite cumbersome: you don't want to administrate the timeout with every call. That is why I'm going to introduce 'safe' calls: call that use a timeout but don't require you to deal with the administration. A threadlocal is used to store the timeout, this value can be set at the beginning of the callstack, and will decrease each time some sort of locking occurs.
Recommended literature
Concurrency control is a very complex subject and good preparation is advisable. And although this library tries to reduce complexity, I think it is important that you know what you are doing. Two Java books that really helped me a lot, are the following classics: