package com.github.basking2.sdsai.itrex.util;

import java.util.concurrent.*;

/**
 * A future that will, on calls to {@link #get()}, let the calling thread do the work.
 *
 * This does not prevent double-computation in all situations, but makes the risk of that very small.
 *
 * @param <T> The type returned.
 */
public class WorkStealingFuture<T> implements Future<T> {

    /**
     * The work to perform.
     */
    private final Callable<T> callable;

    /**
     * The future in the {@link ExecutorService} allowing for canceling, etc.
     */
    private Future<T> future;

    /**
     * Set when a worker thread begins computation.
     */
    private volatile boolean isStarted;

    private WorkStealingFuture(final Callable<T> callable) {
        this.callable = callable;
        this.isStarted = false;
        this.future = null;
    }

    public static <T> WorkStealingFuture<T> run(final ExecutorService executorService, final Callable<T> callable) {
        final WorkStealingFuture<T> workStealingFuture = new WorkStealingFuture<>(callable);

        workStealingFuture.future = executorService.submit(() -> {
            if (!workStealingFuture.isStarted) {
                workStealingFuture.isStarted = true;
                return callable.call();
            }
            else {
                return null;
            }
        });

        return workStealingFuture;
    }

    public static <T> WorkStealingFuture<T> execute(final Executor executor, final Callable<T> callable) {
        final WorkStealingFuture<T> workStealingFuture = new WorkStealingFuture<>(callable);

        final FutureTask<T> promise = new FutureTask<>(() -> {
            if (!workStealingFuture.isStarted) {
                workStealingFuture.isStarted = true;
                return callable.call();
            }
            return null;
        });

        workStealingFuture.future = promise;

        executor.execute(promise);

        return workStealingFuture;
    }

    @Override
    public boolean cancel(boolean b) {
        return future.cancel(b);
    }

    @Override
    public boolean isCancelled() {
        return future.isCancelled();
    }

    @Override
    public boolean isDone() {
        return future.isDone();
    }

    @Override
    public T get() throws InterruptedException, ExecutionException {
        if (isStarted) {
            return future.get();
        }
        else {
            isStarted = true;
            if (future.isDone()) {
                return future.get();
            }
            else {
                try {
                    return callable.call();
                } catch (final Throwable e) {
                    throw new ExecutionException("Executing call directly.", e);
                }
            }
        }
    }

    @Override
    public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
        return future.get(l, timeUnit);
    }
}

@@ -170,113 +170,8 @@
 %0A *%0A
- * This does not prevent double-computation in all situations, but makes the risk of that very small.%0A *%0A
  * @
@@ -735,32 +735,482 @@
  = null;%0A    %7D%0A%0A
+    /**%0A     * Lock this object and try to set isStarted to true.%0A     *%0A     * @return True if isStarted was not previously set to true and this function call set it to true, false otherwise.%0A     */%0A    private boolean tryStart() %7B%0A        synchronized (this) %7B%0A            if (isStarted) %7B%0A                return false;%0A            %7D%0A            else %7B%0A                isStarted = true;%0A                return true;%0A            %7D%0A        %7D%0A    %7D%0A%0A
     public stati
@@ -1479,33 +1479,32 @@
             if (
-!
 workStealingFutu
@@ -1510,74 +1510,22 @@
 ure.
-is
+try
 Start
-ed
+()
 ) %7B%0A
-                workStealingFuture.isStarted = true;%0A
     
@@ -1975,9 +1975,8 @@
 if (
-!
 work
@@ -1990,25 +1990,26 @@
 gFuture.
-is
+try
 Start
-ed
+()
 ) %7B%0A    
@@ -2024,43 +2024,30 @@
     
-workStealingFuture.isStarted = true
+return callable.call()
 ;%0A  
@@ -2060,50 +2060,33 @@
     
+%7D%0A
     
-return callable.call();%0A       
+        else %7B%0A
     
- %7D%0A
     
@@ -2098,32 +2098,46 @@
    return null;%0A
+            %7D%0A
         %7D);%0A%0A   
@@ -2625,218 +2625,22 @@
 if (
-isStarted) %7B%0A            return future.get();%0A        %7D%0A        else %7B%0A            isStarted = true;%0A            if (future.isDone()) %7B%0A                return future.get();%0A            %7D%0A            else %7B%0A    
+tryStart()) %7B%0A
     
@@ -2653,20 +2653,16 @@
   try %7B%0A
-    
         
@@ -2705,20 +2705,16 @@
         
-   
- 
 %7D catch 
@@ -2731,28 +2731,24 @@
 owable e) %7B%0A
-    
             
@@ -2812,32 +2812,38 @@
 .%22, e);%0A        
+    %7D%0A
         %7D%0A      
@@ -2836,37 +2836,71 @@
       %7D%0A        
-    %7D
+else %7B%0A            return future.get();
 %0A        %7D%0A    %7D

Use a synchronized block to start computation.