 <p>I think that your initial idea is pretty good and can be made to work with not too much code. It will require some tinkering in order to decouple "is a <code>Runnable</code> for this value already running" from "execute this <code>Runnable</code>", but here's a rough illustration that doesn't take care about that:</p> <ul> <li>Implement <code>equals()</code> and <code>hashCode()</code> in <code>Process</code>, so that instances can safely be used in unordered sets and maps.</li> <li>Create a <code>ConcurrentMap&lt;Process, Boolean&gt;</code> <ul> <li>You won't be using <code>Collections.newSetFromMap(new ConcurrentHashMap&lt;Process, Boolean&gt;)</code> because you'd want to use the map's <code>putIfAbsent()</code> method.</li> </ul></li> <li>Try to add in it using <code>putIfAbsent()</code> each <code>Process</code> that you will be submitting and bail if the returned value is not <code>null</code>. <ul> <li>A non-<code>null</code> return value means that there's already an equivalent <code>Process</code> in the map (and therefore being processed).</li> <li>The trivial and not very clean solution will be to inject a reference to the map in each <code>Process</code> instance and have <code>putIfAbsent(this, true)</code> as the first thing you do in your <code>run()</code> method.</li> </ul></li> <li>Remove from it each <code>Process</code> that has finished processing. <ul> <li>The trivial and not very clean solution will be inject a reference to the map in each <code>Process</code> instance and have <code>remove(this)</code> as the last thing you do in your <code>run()</code> method.</li> <li>Other solutions can have <code>Process</code> implement <code>Callable</code> and return its unique value as a result, so that it can be removed from the map, or use <code>CompletableFuture</code> and its <code>thenAccept()</code> callback.</li> </ul></li> </ul> <p><a href="http://pastebin.com/kfYr9Sjm" rel="nofollow">Here's</a> a sample that illustrates the trivial and not very clean solution described above (code too long to paste directly here).</p>