Created
August 12, 2016 01:32
-
-
Save eribeiro/4141df2d02c62d7370101bc4349cd8c4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.HashSet; | |
import java.util.Set; | |
import java.util.concurrent.*; | |
public class MapComputeTest | |
{ | |
public static void main(String[] args) | |
{ | |
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); | |
// our dumb collectionWatches | |
ConcurrentHashMap<String, Set<Integer>> collectionWatches = new ConcurrentHashMap<>(); | |
// our "equivalent" of stateWatchers | |
final Set<Integer> stateWatchers = new HashSet<>(); // non thread-safe | |
// COMMENT THE LINE ABOVE AND UNCOMMENT THE LINE BELOW TO FIX THE ISSUE | |
// no, Collections.synchronizedSet doesn't solve it. :( | |
// final Set<Integer> stateWatchers = ConcurrentHashMap.newKeySet(); // thread-safe fix | |
collectionWatches.put("1", stateWatchers); | |
// pre-populate stateWatchers so that it can have something | |
// to start looping on | |
for (int i = 0; i < 10; i++) | |
stateWatchers.add(i); | |
// IMPORTANT: this thread modifies stateWatchers concurrently, | |
// but only does so after 1s so that we have a chance | |
// of interleaving the operations with the one performed | |
// by the .compute | |
executorService.schedule(() -> { | |
for (int i = 11; i < 20; i++) | |
{ | |
stateWatchers.add(i); | |
} | |
}, 1, TimeUnit.SECONDS); | |
// FORTUNATELY addAll is very fast, so if I want | |
// to get the right interleaving then I need to "cheat": | |
// by overriding the add() method and inserting a little | |
// delay so that Set insertion is not so fast. ;) | |
Set<Integer> watchers = new HashSet<Integer>() | |
{ | |
@Override | |
public boolean add(Integer o) | |
{ | |
try | |
{ | |
TimeUnit.SECONDS.sleep(1); | |
} | |
catch (InterruptedException e) | |
{ | |
e.printStackTrace(); | |
} | |
return super.add(o); | |
} | |
}; | |
System.out.println("PLEASE, be patient. Even when it works, has been made slow ;)"); | |
try | |
{ | |
// the patch solution | |
collectionWatches.compute("1", (k, v) -> { | |
if (v != null) | |
{ | |
watchers.addAll(stateWatchers); | |
} | |
return v; | |
}); | |
// The original code (or almost) with that slow down trick | |
// watchers = new HashSet<Integer>(stateWatchers) | |
// { | |
// @Override | |
// public boolean add(Integer o) | |
// { | |
// try | |
// { | |
// TimeUnit.SECONDS.sleep(1); | |
// } | |
// catch (InterruptedException e) | |
// { | |
// e.printStackTrace(); | |
// } | |
// return super.add(o); | |
// } | |
// }; | |
System.out.println(watchers); | |
} finally { | |
executorService.shutdownNow(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment