fork download
  1. /* package whatever; // don't place package name! */
  2.  
  3. import java.util.*;
  4. import java.util.concurrent.*;
  5. import java.util.concurrent.locks.*;
  6. import java.lang.*;
  7. import java.io.*;
  8.  
  9. /* Name of the class has to be "Main" only if the class is public. */
  10. class Ideone {
  11. private final ConcurrentHashMap<String, Future<?>> pending = new ConcurrentHashMap<>();
  12. private final ExecutorService executor;
  13. private final long start;
  14.  
  15. Ideone(ExecutorService executor) {
  16. this.executor = executor;
  17. this.start = System.nanoTime();
  18. }
  19.  
  20. void test(String hash) {
  21. System.out.println(Thread.currentThread().getName() + " started at: " + ((System.nanoTime() - start) / 1e9) + "s");
  22.  
  23. Future<?> future =
  24. pending.computeIfAbsent(hash, k -> executor.submit(() -> longRunningMethod()));
  25. try {
  26. future.get(); // Block until LRM has finished.
  27. System.out.println(Thread.currentThread().getName() + " completed after: " + ((System.nanoTime() - start) / 1e9) + "s");
  28. } catch (ExecutionException e) {
  29. throw new RuntimeException(e);
  30. } catch (InterruptedException e) {
  31. Thread.currentThread().interrupt();
  32. throw new RuntimeException(e);
  33. } finally {
  34. pending.values().remove(future);
  35. }
  36. }
  37.  
  38. void longRunningMethod() {
  39. System.out.println("Start: " + Thread.currentThread().getName());
  40. try {
  41. Thread.sleep(500);
  42. } catch (InterruptedException e) {
  43. Thread.currentThread().interrupt();
  44. throw new RuntimeException(e);
  45. }
  46. System.out.println("End: " + Thread.currentThread().getName());
  47. }
  48.  
  49. static void startAndRun(Thread... ts) throws InterruptedException {
  50. for (Thread t : ts) t.start();
  51. for (Thread t : ts) t.join();
  52. }
  53.  
  54. public static void main(String[] args) throws java.lang.Exception {
  55. ExecutorService executor = Executors.newCachedThreadPool();
  56. try {
  57. Ideone instance = new Ideone(executor);
  58.  
  59. Runnable r = () -> instance.test("");
  60.  
  61. // These threads all run concurrently, and basically finish at the same
  62. // time.
  63. startAndRun(new Thread(r), new Thread(r), new Thread(r));
  64. // The LRM needs to be called again for these threads.
  65. startAndRun(new Thread(r), new Thread(r));
  66. } finally {
  67. executor.shutdown();
  68. }
  69. }
  70. }
  71.  
Success #stdin #stdout 0.2s 322112KB
stdin
Standard input is empty
stdout
Thread-0 started at: 0.094508291s
Thread-1 started at: 0.099820226s
Thread-2 started at: 0.101491774s
Start: pool-1-thread-1
End: pool-1-thread-1
Thread-0 completed after: 0.602933698s
Thread-2 completed after: 0.603211042s
Thread-1 completed after: 0.60299587s
Thread-3 started at: 0.604279514s
Start: pool-1-thread-1
Thread-4 started at: 0.604574315s
End: pool-1-thread-1
Thread-3 completed after: 1.104799675s
Thread-4 completed after: 1.10501813s