I ran across this interesting Scala class by Vaclav Pech which makes the data concurrent rather than the code (if I understood the author correctly). The ~
(extraction) and <<
(insertion) operators looked nifty.
Looking to do the same in Java, I see four key requirements:
- Insertion can happen only once.
- Extraction is idempotent (infinitely repeatable, non-modifying).
- Extraction blocks until insertion has completed.
- Insertion and extraction are both atomic.
With these in mind, I write this:
public class DataFlowReference<T> { private final ReentrantLock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); private volatile T item; private volatile boolean set = false; private volatile boolean called = false; public T get() throws InterruptedException { lock.lockInterruptibly(); try { while (true) { if (set) return item; if (!called) { called = true; onFirstGet(); continue; } condition.await(); } } finally { lock.unlock(); } } public void setOnce(final T value) { lock.lock(); try { if (set) return; set = true; item = value; condition.signalAll(); } finally { lock.unlock(); } } protected void onFirstGet() { } // Object @Override public boolean equals(final Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; final DataFlowReference that = (DataFlowReference) o; return set && item.equals(that.item); } @Override public int hashCode() { return set ? item.hashCode() : super.hashCode(); } @Override public String toString() { return "(" + set + ':' + item + ')'; } }
Use of DataFlowReference
follows the examples from Vaclav's page: declare dataflow references, create threads whose runables use setOnce()
and get()
, invoke them all together.
onFirstGet()
supports "just in time" supply of item
and would call setOnce(T)
with a fresh value.
UPDATE: The original version of this class had a horrible, obvious race condition. Caveat plicator.
1 comment:
You have basically implemented a Future with external setting semantics. For something similar, see:
http://labs.atlassian.com/source/browse/CONCURRENT/trunk/src/main/java/com/atlassian/util/concurrent/SettableFuture.java?r=2602
and a related conversation (Offering data to Futures):
http://cs.oswego.edu/pipermail/concurrency-interest/2009-May/thread.html#6161
Post a Comment