diff --git a/CHANGES.txt b/CHANGES.txt index 528ed1ce..c3c91f1e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,9 +3,11 @@ 1, Improve Pair/Triple/Tuple... -2, Add firstResult/firstSuccessResult/lastResult/lastSuccessResult to AsyncExecutor. +2, Add firstResult/firstSuccessResult/lastResult/lastSuccessResult/parallelGet to CompletableFuture. -3, Improvements and bug fix. +3, Refactoring CompletableFuture/AsyncExecutor to keep consistent with CompletableFuture in JDK 8. + +4, Improvements and bug fix. ========Changes in 0.9.52========================================================================= diff --git a/lib/abacus-util-0.9.53.jar b/lib/abacus-util-0.9.53.jar index 59cf2e34..1c6caba8 100644 Binary files a/lib/abacus-util-0.9.53.jar and b/lib/abacus-util-0.9.53.jar differ diff --git a/lib/abacus-util-all-0.9.53.jar b/lib/abacus-util-all-0.9.53.jar index b1fc62ab..dc25d300 100644 Binary files a/lib/abacus-util-all-0.9.53.jar and b/lib/abacus-util-all-0.9.53.jar differ diff --git a/src/com/landawn/abacus/android/util/AsyncExecutor.java b/src/com/landawn/abacus/android/util/AsyncExecutor.java index f0f7f949..a0d4644c 100644 --- a/src/com/landawn/abacus/android/util/AsyncExecutor.java +++ b/src/com/landawn/abacus/android/util/AsyncExecutor.java @@ -16,23 +16,11 @@ package com.landawn.abacus.android.util; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.Executor; +import java.util.concurrent.FutureTask; import com.landawn.abacus.annotation.Beta; -import com.landawn.abacus.logging.Logger; -import com.landawn.abacus.logging.LoggerFactory; -import com.landawn.abacus.util.Callback; -import com.landawn.abacus.util.Holder; -import com.landawn.abacus.util.N; -import com.landawn.abacus.util.Optional; -import com.landawn.abacus.util.OptionalNullable; -import com.landawn.abacus.util.Pair; import com.landawn.abacus.util.Retry; import com.landawn.abacus.util.Retry.Retry0; import com.landawn.abacus.util.function.BiFunction; @@ -44,7 +32,7 @@ /** *
- * AsyncExecutor.executeInParallel(() -> { // download image })
+ * AsyncExecutor.executeWithThreadPool(() -> { // download image })
     .executeOnUiThread((e, image) -> {// refresh UI })
     .execute((e, image) -> {// convert image to bitmap format})
     .callbackOnUiThread((e, bitmap) -> {// update UI});
@@ -55,8 +43,10 @@
  * @author Haiyang Li
  */
 public class AsyncExecutor {
-    private static final Logger logger = LoggerFactory.getLogger(Asyn.class);
-    private static final Handler HANDLER = new Handler(Looper.getMainLooper());
+
+    static final UIExecutor UI_EXECUTOR = new UIExecutor();
+    static final Executor SERIAL_EXECUTOR = AsyncTask.SERIAL_EXECUTOR;
+    static final Executor THREAD_POOL_EXECUTOR = AsyncTask.THREAD_POOL_EXECUTOR;
 
     private AsyncExecutor() {
         // Singleton
@@ -69,7 +59,7 @@ private AsyncExecutor() {
      * @return
      */
     public static CompletableFuture execute(final Runnable action) {
-        return execute(new CompletableFuture(action, null));
+        return execute(new FutureTask(action, null), SERIAL_EXECUTOR);
     }
 
     public static CompletableFuture execute(final Runnable action, final int retryTimes, final long retryInterval,
@@ -82,17 +72,6 @@ public void run() {
         });
     }
 
-    @Beta
-    static List> execute(final List actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Runnable cmd : actions) {
-            results.add(execute(cmd));
-        }
-
-        return results;
-    }
-
     /**
      * The action will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
      * 
@@ -100,7 +79,7 @@ static List> execute(final List acti
      * @return
      */
     public static  CompletableFuture execute(final Callable action) {
-        return execute(new CompletableFuture<>(action));
+        return execute(new FutureTask<>(action), SERIAL_EXECUTOR);
     }
 
     public static  CompletableFuture execute(final Callable action, final int retryTimes, final long retryInterval,
@@ -114,42 +93,19 @@ public T call() throws Exception {
         });
     }
 
-    /**
-     * The actions will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  List> execute(final Collection> actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Callable cmd : actions) {
-            results.add(execute(cmd));
-        }
-
-        return results;
-    }
-
-    private static  CompletableFuture execute(final CompletableFuture callableFuture) {
-        AsyncTask.SERIAL_EXECUTOR.execute(callableFuture);
-
-        return callableFuture;
-    }
-
     /**
      * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
      * 
      * @param action
      * @return
      */
-    public static CompletableFuture executeInParallel(final Runnable action) {
-        return executeInParallel(new CompletableFuture(action, null));
+    public static CompletableFuture executeWithThreadPool(final Runnable action) {
+        return execute(new FutureTask(action, null), THREAD_POOL_EXECUTOR);
     }
 
-    public static CompletableFuture executeInParallel(final Runnable action, final int retryTimes, final long retryInterval,
+    public static CompletableFuture executeWithThreadPool(final Runnable action, final int retryTimes, final long retryInterval,
             final Function retryCondition) {
-        return executeInParallel(new Runnable() {
+        return executeWithThreadPool(new Runnable() {
             @Override
             public void run() {
                 Retry.of(retryTimes, retryInterval, retryCondition).run(action);
@@ -157,36 +113,19 @@ public void run() {
         });
     }
 
-    /**
-     * The actions will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static List> executeInParallel(final List actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Runnable cmd : actions) {
-            results.add(executeInParallel(cmd));
-        }
-
-        return results;
-    }
-
     /**
      * The action will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
      * 
      * @param action
      * @return
      */
-    public static  CompletableFuture executeInParallel(final Callable action) {
-        return executeInParallel(new CompletableFuture<>(action));
+    public static  CompletableFuture executeWithThreadPool(final Callable action) {
+        return execute(new FutureTask<>(action), THREAD_POOL_EXECUTOR);
     }
 
-    public static  CompletableFuture executeInParallel(final Callable action, final int retryTimes, final long retryInterval,
+    public static  CompletableFuture executeWithThreadPool(final Callable action, final int retryTimes, final long retryInterval,
             final BiFunction retryCondition) {
-        return executeInParallel(new Callable() {
+        return executeWithThreadPool(new Callable() {
             @Override
             public T call() throws Exception {
                 final Retry0 retry = Retry0.of(retryTimes, retryInterval, retryCondition);
@@ -195,29 +134,6 @@ public T call() throws Exception {
         });
     }
 
-    /**
-     * The actions will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  List> executeInParallel(final Collection> actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Callable cmd : actions) {
-            results.add(executeInParallel(cmd));
-        }
-
-        return results;
-    }
-
-    private static  CompletableFuture executeInParallel(final CompletableFuture callableFuture) {
-        AsyncTask.THREAD_POOL_EXECUTOR.execute(callableFuture);
-
-        return callableFuture;
-    }
-
     /**
      * The action will be asynchronously executed in UI thread.
      * 
@@ -225,7 +141,7 @@ private static  CompletableFuture executeInParallel(final CompletableFutur
      * @return
      */
     public static CompletableFuture executeOnUiThread(final Runnable action) {
-        return executeOnUiThread(new CompletableFuture(action, null), 0);
+        return executeOnUiThread(action, 0);
     }
 
     /**
@@ -236,7 +152,7 @@ public static CompletableFuture executeOnUiThread(final Runnable action) {
      * @return
      */
     public static CompletableFuture executeOnUiThread(final Runnable action, final long delay) {
-        return executeOnUiThread(new CompletableFuture(action, null), delay);
+        return execute(new FutureTask(action, null), UI_EXECUTOR, delay);
     }
 
     public static CompletableFuture executeOnUiThread(final Runnable action, final int retryTimes, final long retryInterval,
@@ -249,41 +165,6 @@ public void run() {
         });
     }
 
-    /**
-     * The actions will be asynchronously executed in UI thread.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static List> executeOnUiThread(final List actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Runnable cmd : actions) {
-            results.add(executeOnUiThread(cmd));
-        }
-
-        return results;
-    }
-
-    /**
-     * The actions will be asynchronously executed in UI thread.
-     * 
-     * @param actions
-     * @param delay
-     * @return
-     */
-    @Beta
-    static List> executeOnUiThread(final List actions, final long delay) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Runnable cmd : actions) {
-            results.add(executeOnUiThread(cmd, delay));
-        }
-
-        return results;
-    }
-
     /**
      * The action will be asynchronously executed in UI thread.
      * 
@@ -291,7 +172,7 @@ static List> executeOnUiThread(final List CompletableFuture executeOnUiThread(final Callable action) {
-        return executeOnUiThread(new CompletableFuture<>(action), 0);
+        return executeOnUiThread(action, 0);
     }
 
     /**
@@ -302,7 +183,7 @@ public static  CompletableFuture executeOnUiThread(final Callable actio
      * @return
      */
     public static  CompletableFuture executeOnUiThread(final Callable action, final long delay) {
-        return executeOnUiThread(new CompletableFuture<>(action), delay);
+        return execute(new FutureTask<>(action), UI_EXECUTOR, delay);
     }
 
     public static  CompletableFuture executeOnUiThread(final Callable action, final int retryTimes, final long retryInterval,
@@ -316,633 +197,33 @@ public T call() throws Exception {
         });
     }
 
-    /**
-     * The actions will be asynchronously executed in UI thread.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  List> executeOnUiThread(final Collection> actions) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Callable cmd : actions) {
-            results.add(executeOnUiThread(cmd));
-        }
-
-        return results;
-    }
-
-    /**
-     * The actions will be asynchronously executed in UI thread.
-     * 
-     * @param actions
-     * @param delay
-     * @return
-     */
-    @Beta
-    static  List> executeOnUiThread(final Collection> actions, final long delay) {
-        final List> results = new ArrayList<>(actions.size());
-
-        for (Callable cmd : actions) {
-            results.add(executeOnUiThread(cmd, delay));
-        }
-
-        return results;
-    }
-
-    private static  CompletableFuture executeOnUiThread(final CompletableFuture callableFuture, final long delay) {
-        if (delay > 0) {
-            HANDLER.postDelayed(callableFuture, delay);
-        } else {
-            HANDLER.post(callableFuture);
-        }
-
-        return callableFuture;
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param a
-     * @return
-     */
-    public static  Optional> firstResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @return
-     */
-    public static  Optional> firstResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  Optional> firstResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    return Optional.empty();
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param a
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param c
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    return OptionalNullable.empty();
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param a
-     * @return
-     */
-    public static  Optional> lastResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
+    private static  CompletableFuture execute(final FutureTask futureTask, final Executor executor) {
+        executor.execute(futureTask);
 
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
+        return new CompletableFuture<>(futureTask, executor);
     }
 
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @return
-     */
-    public static  Optional> lastResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
+    private static  CompletableFuture execute(final FutureTask futureTask, final UIExecutor executor, final long delay) {
+        executor.execute(futureTask, delay);
 
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
+        return new CompletableFuture<>(futureTask, executor);
     }
 
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  Optional> lastResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
+    static final class UIExecutor implements Executor {
+        private static final Handler HANDLER = new Handler(Looper.getMainLooper());
 
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
+        @Override
+        public void execute(Runnable command) {
+            HANDLER.post(command);
         }
 
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    break;
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
+        public void execute(Runnable command, final long delay) {
+            if (delay > 0) {
+                HANDLER.postDelayed(command, delay);
+            } else {
+                HANDLER.post(command);
             }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
         }
-
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param a
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param c
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    break;
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    public static  List> concat(final CompletableFuture... a) {
-        final List> queue = new ArrayList<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).get(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.add(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
-
-    /**
-     * 
-     * @param c
-     * @return
-     */
-    public static  List> concat(final Collection> c) {
-        final List> queue = new ArrayList<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).get(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.add(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
-
-    public static  BlockingQueue> parallelConcat(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
-
-    /**
-     * 
-     * @param c
-     * @return
-     */
-    public static  BlockingQueue> parallelConcat(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
     }
 
     /**
diff --git a/src/com/landawn/abacus/android/util/CompletableFuture.java b/src/com/landawn/abacus/android/util/CompletableFuture.java
index 45ab5ff2..dbddb221 100644
--- a/src/com/landawn/abacus/android/util/CompletableFuture.java
+++ b/src/com/landawn/abacus/android/util/CompletableFuture.java
@@ -14,66 +14,182 @@
 
 package com.landawn.abacus.android.util;
 
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
-import java.util.concurrent.RunnableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
-import com.landawn.abacus.util.Callback;
-import com.landawn.abacus.util.Callback2;
+import com.landawn.abacus.android.util.AsyncExecutor.UIExecutor;
+import com.landawn.abacus.logging.Logger;
+import com.landawn.abacus.logging.LoggerFactory;
+import com.landawn.abacus.util.MutableBoolean;
 import com.landawn.abacus.util.N;
+import com.landawn.abacus.util.Optional;
+import com.landawn.abacus.util.OptionalNullable;
 import com.landawn.abacus.util.Pair;
-import com.landawn.abacus.util.ThreadMode;
+import com.landawn.abacus.util.Tuple;
+import com.landawn.abacus.util.Tuple.Tuple4;
+import com.landawn.abacus.util.function.BiConsumer;
+import com.landawn.abacus.util.function.BiFunction;
+import com.landawn.abacus.util.function.Consumer;
+import com.landawn.abacus.util.function.Function;
 
 /**
+ * The action in all *run* methods will be executed by the specified or default Executor.
+ * The action in other methods will be executed in the thread where the get() or get(timeout, unit) method is called.
+ * 
  * 
  * @since 0.8
  * 
  * @author Haiyang Li
  */
-public class CompletableFuture implements RunnableFuture {
-    private final FutureTask futureTask;
-    private volatile Callback callback;
-    private volatile ThreadMode threadMode;
-    private volatile boolean actionExecuted = false;
+public class CompletableFuture implements Future {
+    private static final Logger logger = LoggerFactory.getLogger(CompletableFuture.class);
+
+    private static final Consumer EMPTY_CONSUMER = new Consumer() {
+        @Override
+        public void accept(Object t) {
+            // Do nothing.                
+        }
+    };
+
+    @SuppressWarnings("rawtypes")
+    private static final Function IDENTITY_FUNCTION = new Function() {
+        @Override
+        public Object apply(Object t) {
+            return t;
+        }
+    };
+
+    private final Future future;
+    private final Executor asyncExecutor;
+    private final long delay;
+
+    CompletableFuture(final Future future, final Executor asyncExecutor) {
+        this(future, asyncExecutor, 0);
+    }
+
+    CompletableFuture(final Future future, final Executor asyncExecutor, final long delay) {
+        this.future = future;
+        this.asyncExecutor = asyncExecutor;
+        this.delay = delay;
+    }
+
+    public static CompletableFuture run(final Runnable action) {
+        return run(action, AsyncExecutor.SERIAL_EXECUTOR);
+    }
+
+    public static  CompletableFuture run(final Callable action) {
+        return run(action, AsyncExecutor.SERIAL_EXECUTOR);
+    }
 
-    CompletableFuture(Callable callable) {
-        this.futureTask = new FutureTask<>(callable);
+    public static CompletableFuture runWithUIExecutor(final Runnable action) {
+        return run(action, AsyncExecutor.UI_EXECUTOR);
     }
 
-    CompletableFuture(Runnable runnable, T result) {
-        this.futureTask = new FutureTask<>(runnable, result);
+    public static  CompletableFuture runWithUIExecutor(final Callable action) {
+        return run(action, AsyncExecutor.UI_EXECUTOR);
+    }
+
+    //    public static CompletableFuture runWithSerialExecutor(final Runnable action) {
+    //        return run(action, AsyncExecutor.SERIAL_EXECUTOR);
+    //    }
+    //
+    //    public static  CompletableFuture runWithSerialExecutor(final Callable action) {
+    //        return run(action, AsyncExecutor.SERIAL_EXECUTOR);
+    //    }
+
+    public static CompletableFuture runWithTPExecutor(final Runnable action) {
+        return run(action, AsyncExecutor.THREAD_POOL_EXECUTOR);
+    }
+
+    public static  CompletableFuture runWithTPExecutor(final Callable action) {
+        return run(action, AsyncExecutor.THREAD_POOL_EXECUTOR);
+    }
+
+    public static CompletableFuture run(final Runnable action, final Executor executor) {
+        final FutureTask futureTask = new FutureTask<>(action, null);
+
+        executor.execute(futureTask);
+
+        return new CompletableFuture<>(futureTask, executor);
+    }
+
+    public static  CompletableFuture run(final Callable action, final Executor executor) {
+        final FutureTask futureTask = new FutureTask<>(action);
+
+        executor.execute(futureTask);
+
+        return new CompletableFuture<>(futureTask, executor);
     }
 
     /**
      * 
      * @param result
-     * @return a {@code CompletableFuture} which is already completed.
+     * @param asyncExecutor
+     * @return a CompletableFuture which is already done by passing the result to it directly.
      */
-    public static  CompletableFuture completed(T result) {
-        return new CompletedFuture<>(result);
+    public static  CompletableFuture completed(final T result) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return false;
+            }
+
+            @Override
+            public boolean isCancelled() {
+                return false;
+            }
+
+            @Override
+            public boolean isDone() {
+                return true;
+            }
+
+            @Override
+            public T get() {
+                return result;
+            }
+
+            @Override
+            public T get(final long timeout, final TimeUnit unit) {
+                return result;
+            }
+        }, AsyncExecutor.SERIAL_EXECUTOR);
     }
 
     @Override
     public boolean cancel(boolean mayInterruptIfRunning) {
-        return futureTask.cancel(mayInterruptIfRunning);
+        return future.cancel(mayInterruptIfRunning);
     }
 
     @Override
     public boolean isCancelled() {
-        return futureTask.isCancelled();
+        return future.isCancelled();
     }
 
     @Override
     public boolean isDone() {
-        return futureTask.isDone();
+        return future.isDone();
     }
 
     @Override
     public T get() throws InterruptedException, ExecutionException {
-        return futureTask.get();
+        return future.get();
+    }
+
+    @Override
+    public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+        return future.get(timeout, unit);
     }
 
     public Pair get2() {
@@ -84,704 +200,1255 @@ public Pair get2() {
         }
     }
 
-    @Override
-    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
-        return futureTask.get(timeout, unit);
-    }
-
-    //    public T get2() {
-    //        try {
-    //            return futureTask.get();
-    //        } catch (InterruptedException | ExecutionException e) {
-    //            throw N.toRuntimeException(e);
-    //        }
-    //    }
-    //
-    //    public T get2(long timeout, TimeUnit unit) {
-    //        try {
-    //            return futureTask.get(timeout, unit);
-    //        } catch (InterruptedException | ExecutionException | TimeoutException e) {
-    //            throw N.toRuntimeException(e);
-    //        }
-    //    }
-
-    public T get(final Callback.Action action) {
-        try {
-            final T result = get();
-            action.on(result);
-            return result;
-        } catch (InterruptedException | ExecutionException e) {
-            throw N.toRuntimeException(e);
-        }
-    }
-
-    public T get(long timeout, TimeUnit unit, final Callback.Action action) {
-        try {
-            final T result = get(timeout, unit);
-            action.on(result);
-            return result;
-        } catch (InterruptedException | ExecutionException | TimeoutException e) {
-            throw N.toRuntimeException(e);
-        }
-    }
-
-    public T get(final Callback callback) {
-        T result = null;
-        Throwable throwable = null;
-
+    public Pair get2(final long timeout, final TimeUnit unit) {
         try {
-            result = get();
+            return Pair.of(get(timeout, unit), null);
         } catch (Throwable e) {
-            throwable = e;
+            return Pair.of(null, e);
         }
-
-        callback.on(throwable, result);
-
-        return result;
     }
 
-    public T get(long timeout, TimeUnit unit, final Callback callback) {
-        T result = null;
-        Throwable throwable = null;
-
+    public T getNow(T defaultValue) {
         try {
-            result = get(timeout, unit);
-        } catch (Throwable e) {
-            throwable = e;
+            return isDone() ? get() : defaultValue;
+        } catch (InterruptedException | ExecutionException e) {
+            throw N.toRuntimeException(e);
         }
-
-        callback.on(throwable, result);
-
-        return result;
     }
 
-    public  R get(final Callback2.Action action) {
+    public  U get(final Function action) {
         try {
-            return action.on(get());
+            return action.apply(get());
         } catch (InterruptedException | ExecutionException e) {
             throw N.toRuntimeException(e);
         }
     }
 
-    public  R get(long timeout, TimeUnit unit, final Callback2.Action action) {
+    public  U get(final long timeout, final TimeUnit unit, final Function action) {
         try {
-            return action.on(get(timeout, unit));
+            return action.apply(get(timeout, unit));
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             throw N.toRuntimeException(e);
         }
     }
 
-    public  R get(final Callback2 callback) {
-        T result = null;
-        Throwable throwable = null;
-
+    public  U get(final BiFunction action) {
         try {
-            result = get();
+            return action.apply(get(), null);
         } catch (Throwable e) {
-            throwable = e;
+            return action.apply(null, e);
         }
-
-        return callback.on(throwable, result);
     }
 
-    public  R get(long timeout, TimeUnit unit, final Callback2 callback) {
-        T result = null;
-        Throwable throwable = null;
-
+    public  U get(final long timeout, final TimeUnit unit, final BiFunction action) {
         try {
-            result = get(timeout, unit);
+            return action.apply(get(timeout, unit), null);
         } catch (Throwable e) {
-            throwable = e;
+            return action.apply(null, e);
         }
-
-        return callback.on(throwable, result);
     }
 
-    @Override
-    public void run() {
-        try {
-            futureTask.run();
-        } finally {
-            if (this.callback != null && actionExecuted == false) {
-                synchronized (this.callback) {
-                    if (actionExecuted == false) {
-                        actionExecuted = true;
-
-                        T result = null;
-                        Throwable throwable = null;
-
-                        try {
-                            result = get();
-                        } catch (Throwable e) {
-                            throwable = e;
-                        }
+    public  CompletableFuture thenApply(final Function action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning);
+            }
 
-                        callback(throwable, result);
-                    }
-                }
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled();
             }
-        }
-    }
 
-    /**
-     * The callback will be executed in target future task thread or current thread if task has been completed before this callback is set.
-     * 
-     * @param action
-     */
-    public void callback(final Callback.Action action) {
-        callback(action, ThreadMode.DEFAULT);
-    }
+            @Override
+            public boolean isDone() {
+                return future.isDone();
+            }
 
-    /**
-     * The callback will be executed in target future task thread or current thread if task has been completed before this callback is set.
-     * 
-     * @param callback
-     */
-    public void callback(final Callback callback) {
-        callback(callback, ThreadMode.DEFAULT);
-    }
+            @Override
+            public U get() throws InterruptedException, ExecutionException {
+                return action.apply(future.get());
+            }
 
-    /**
-     * The callback will be executed in background thread which could be the future task thread or current thread if it's background thread, otherwise it will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR}.
-     * 
-     * @param action
-     */
-    public void callbackInBackground(final Callback.Action action) {
-        callback(action, ThreadMode.SERIAL_EXECUTOR);
+            @Override
+            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                return action.apply(future.get(timeout, unit));
+            }
+        }, asyncExecutor);
     }
 
-    /**
-     * The callback will be executed in background thread which could be the future task thread or current thread if it's background thread, otherwise it will be asynchronously executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR}.
-     * 
-     * @param callback
-     */
-    public void callbackInBackground(final Callback callback) {
-        callback(callback, ThreadMode.SERIAL_EXECUTOR);
-    }
+    public  CompletableFuture thenApply(final BiFunction action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning);
+            }
 
-    /**
-     * The callback will be executed in background thread which could be the future task thread or current thread if it's background thread, otherwise it will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR}.
-     * 
-     * @param action
-     */
-    public void callbackInParallel(final Callback.Action action) {
-        callback(action, ThreadMode.THREAD_POOL_EXECUTOR);
-    }
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled();
+            }
 
-    /**
-     * The callback will be executed in background thread which could be the future task thread or current thread if it's background thread, otherwise it will be asynchronously executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR}.
-     * 
-     * @param callback
-     */
-    public void callbackInParallel(final Callback callback) {
-        callback(callback, ThreadMode.THREAD_POOL_EXECUTOR);
-    }
+            @Override
+            public boolean isDone() {
+                return future.isDone();
+            }
 
-    /**
-     * The callback will be executed in UI thread which could be the future task thread or current thread if it's UI thread, otherwise it will be asynchronously executed in UI thread.
-     * 
-     * @param action
-     */
-    public void callbackOnUiThread(final Callback.Action action) {
-        callback(action, ThreadMode.UI_THREAD);
-    }
+            @Override
+            public U get() throws InterruptedException, ExecutionException {
+                final Pair result = get2();
 
-    /**
-     * The callback will be executed in UI thread which could be the future task thread or current thread if it's UI thread, otherwise it will be asynchronously executed in UI thread.
-     * 
-     * @param callback
-     */
-    public void callbackOnUiThread(final Callback callback) {
-        callback(callback, ThreadMode.UI_THREAD);
-    }
+                return action.apply(result.left, result.right);
+            }
 
-    private void callback(final Callback.Action action, final ThreadMode threadMode) {
-        callback(new Callback() {
             @Override
-            public void on(Throwable e, T result) {
-                if (e != null) {
-                    throw N.toRuntimeException(e);
-                }
+            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                final Pair result = get2(timeout, unit);
 
-                action.on(result);
+                return action.apply(result.left, result.right);
             }
-        }, threadMode);
+        }, asyncExecutor);
     }
 
-    private void callback(final Callback callback, final ThreadMode threadMode) {
-        this.threadMode = threadMode;
-        this.callback = callback;
+    public  CompletableFuture thenAccept(final Consumer action) {
+        return thenApply(new Function() {
+            @Override
+            public Void apply(T t) {
+                action.accept(t);
+                return null;
+            }
+        });
+    }
 
-        synchronized (this) {
-            if (isDone() && isCancelled() == false && actionExecuted == false) {
-                actionExecuted = true;
+    public  CompletableFuture thenAccept(final BiConsumer action) {
+        return thenApply(new BiFunction() {
+            @Override
+            public Void apply(T t, Throwable e) {
+                action.accept(t, e);
+                return null;
+            }
+        });
+    }
 
-                T result = null;
-                Throwable throwable = null;
+    public  CompletableFuture thenCombine(final CompletableFuture other, final BiFunction action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning) && other.future.cancel(mayInterruptIfRunning);
+            }
 
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
-                }
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled() || other.future.isCancelled();
+            }
 
-                callback(throwable, result);
+            @Override
+            public boolean isDone() {
+                return future.isDone() && other.future.isDone();
             }
-        }
-    }
 
-    private void callback(final Throwable throwable, final T result) {
-        if (this.isCancelled()) {
-            return;
-        }
+            @Override
+            public R get() throws InterruptedException, ExecutionException {
+                return action.apply(future.get(), other.future.get());
+            }
 
-        switch (threadMode) {
-            case DEFAULT:
-                callback.on(throwable, result);
+            @Override
+            public R get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                final long timeoutInMillis = unit.toMillis(timeout);
+                final long now = N.currentMillis();
+                final long endTime = timeoutInMillis > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + timeoutInMillis;
 
-                break;
+                final T result = future.get(timeout, unit);
+                final U otherResult = other.future.get(N.max(0, endTime - N.currentMillis()), TimeUnit.MILLISECONDS);
 
-            case SERIAL_EXECUTOR:
-                if (Util.isUiThread()) {
-                    AsyncExecutor.execute(new Runnable() {
-                        @Override
-                        public void run() {
-                            callback.on(throwable, result);
-                        }
-                    });
-                } else {
-                    callback.on(throwable, result);
-                }
+                return action.apply(result, otherResult);
+            }
+        }, asyncExecutor);
+    }
 
-                break;
+    public  CompletableFuture thenCombine(final CompletableFuture other, final Function, R> action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning) && other.future.cancel(mayInterruptIfRunning);
+            }
 
-            case THREAD_POOL_EXECUTOR:
-                if (Util.isUiThread()) {
-                    AsyncExecutor.executeInParallel(new Runnable() {
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled() || other.future.isCancelled();
+            }
 
-                        @Override
-                        public void run() {
-                            callback.on(throwable, result);
-                        }
-                    });
-                } else {
-                    callback.on(throwable, result);
-                }
+            @Override
+            public boolean isDone() {
+                return future.isDone() && other.future.isDone();
+            }
 
-                break;
+            @Override
+            public R get() throws InterruptedException, ExecutionException {
+                final Pair result = get2();
+                final Pair result2 = other.get2();
 
-            case UI_THREAD:
-                if (Util.isUiThread()) {
-                    callback.on(throwable, result);
-                } else {
-                    AsyncExecutor.executeOnUiThread(new Runnable() {
-                        @Override
-                        public void run() {
-                            callback.on(throwable, result);
-                        }
-                    });
-                }
+                return action.apply(Tuple.of(result.left, result.right, (U) result2.left, result.right));
+            }
 
-                break;
+            @Override
+            public R get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                final long timeoutInMillis = unit.toMillis(timeout);
+                final long now = N.currentMillis();
+                final long endTime = timeoutInMillis > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + timeoutInMillis;
 
-            default:
-                throw new RuntimeException("Unsupported thread mode");
+                final Pair result = CompletableFuture.this.get2(timeout, unit);
+                final Pair result2 = other.get2(N.max(0, endTime - N.currentMillis()), TimeUnit.MILLISECONDS);
 
-        }
+                return action.apply(Tuple.of(result.left, result.right, (U) result2.left, result.right));
+            }
+        }, asyncExecutor);
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background thread.
-     * 
-     * @param action
-     * @return
-     */
-    public CompletableFuture execute(final Callback.Action action) {
-        return AsyncExecutor.execute(new Runnable() {
+    public  CompletableFuture thenAcceptBoth(final CompletableFuture other, final BiConsumer action) {
+        return thenCombine(other, new BiFunction() {
             @Override
-            public void run() {
-                try {
-                    action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
+            public Void apply(T t, U u) {
+                action.accept(t, u);
+                return null;
             }
         });
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background thread.
-     * 
-     * @param callback
-     * @return
-     */
-    public CompletableFuture execute(final Callback callback) {
-        return AsyncExecutor.execute(new Runnable() {
+    public  CompletableFuture thenAcceptBoth(final CompletableFuture other, final Consumer> action) {
+        return thenCombine(other, new Function, Void>() {
             @Override
-            public void run() {
-                T result = null;
-                Throwable throwable = null;
-
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
-                }
-
-                callback.on(throwable, result);
+            public Void apply(Tuple4 t) {
+                action.accept(t);
+                return null;
             }
         });
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background thread.
-     * 
-     * @param action
-     * @return
-     */
-    public CompletableFuture executeInParallel(final Callback.Action action) {
-        return AsyncExecutor.executeInParallel(new Runnable() {
+    public CompletableFuture thenRun(final Runnable action) {
+        return execute(new Callable() {
             @Override
-            public void run() {
-                try {
-                    action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
+            public Void call() throws Exception {
+                get();
+                action.run();
+                return null;
             }
         });
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background thread.
-     * 
-     * @param callback
-     * @return
-     */
-    public CompletableFuture executeInParallel(final Callback callback) {
-        return AsyncExecutor.executeInParallel(new Runnable() {
+    public  CompletableFuture thenRun(final Callable action) {
+        return execute(new Callable() {
             @Override
-            public void run() {
-                T result = null;
-                Throwable throwable = null;
-
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
-                }
+            public U call() throws Exception {
+                get();
 
-                callback.on(throwable, result);
+                return action.call();
             }
         });
     }
 
-    /**
-     * The callback will be executed in main(UI) thread.
-     * 
-     * @param action
-     * @return
-     */
-    public CompletableFuture executeOnUiThread(final Callback.Action action) {
-        return AsyncExecutor.executeOnUiThread(new Runnable() {
+    public CompletableFuture thenRun(final Consumer action) {
+        return execute(new Callable() {
             @Override
-            public void run() {
-                try {
-                    action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
+            public Void call() throws Exception {
+                action.accept(get());
+                return null;
             }
         });
     }
 
-    /**
-     * The callback will be executed in main(UI) thread.
-     * 
-     * @param callback
-     * @return
-     */
-    public CompletableFuture executeOnUiThread(final Callback callback) {
-        return AsyncExecutor.executeOnUiThread(new Runnable() {
+    public CompletableFuture thenRun(final BiConsumer action) {
+        return execute(new Runnable() {
             @Override
             public void run() {
-                T result = null;
-                Throwable throwable = null;
-
                 try {
-                    result = get();
+                    action.accept(get(), null);
                 } catch (Throwable e) {
-                    throwable = e;
+                    action.accept(null, e);
                 }
-
-                callback.on(throwable, result);
             }
         });
     }
 
-    /**
-     * The callback will be executed in main(UI) thread.
-     * 
-     * @param action
-     * @param delay
-     * @return
-     */
-    public CompletableFuture executeOnUiThread(final Callback.Action action, final long delay) {
-        return AsyncExecutor.executeOnUiThread(new Runnable() {
+    public  CompletableFuture thenRun(final Function action) {
+        return execute(new Callable() {
             @Override
-            public void run() {
-                try {
-                    action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
+            public R call() throws Exception {
+                return action.apply(get());
             }
-        }, delay);
+        });
     }
 
-    /**
-     * The callback will be executed in main(UI) thread.
-     * 
-     * @param callback
-     * @param delay
-     * @return
-     */
-    public CompletableFuture executeOnUiThread(final Callback callback, final long delay) {
-        return AsyncExecutor.executeOnUiThread(new Runnable() {
+    public  CompletableFuture thenRun(final BiFunction action) {
+        return execute(new Callable() {
             @Override
-            public void run() {
-                T result = null;
-                Throwable throwable = null;
-
+            public R call() throws Exception {
                 try {
-                    result = get();
+                    return action.apply(get(), null);
                 } catch (Throwable e) {
-                    throwable = e;
+                    return action.apply(null, e);
                 }
-
-                callback.on(throwable, result);
             }
-        }, delay);
+        });
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background thread.
-     * 
-     * @param action
-     * @return
-     */
-    public  CompletableFuture execute(final Callback2.Action action) {
-        return AsyncExecutor.execute(new Callable() {
-            @Override
-            public R call() {
-                try {
-                    return action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
-            }
-        });
+    public CompletableFuture thenRunWithUIExecutor(final Runnable action) {
+        return withUIExecutor().thenRun(action);
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#SERIAL_EXECUTOR} in background thread.
-     * 
-     * @param callback
-     * @return
-     */
-    public  CompletableFuture execute(final Callback2 callback) {
-        return AsyncExecutor.execute(new Callable() {
+    public  CompletableFuture thenRunWithUIExecutor(final Callable action) {
+        return withUIExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithUIExecutor(final Consumer action) {
+        return withUIExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithUIExecutor(final BiConsumer action) {
+        return withUIExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithUIExecutor(final Function action) {
+        return withUIExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithUIExecutor(final BiFunction action) {
+        return withUIExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithSerialExecutor(final Runnable action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithSerialExecutor(final Callable action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithSerialExecutor(final Consumer action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithSerialExecutor(final BiConsumer action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithSerialExecutor(final Function action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithSerialExecutor(final BiFunction action) {
+        return withSerialExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithTPExecutor(final Runnable action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithTPExecutor(final Callable action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithTPExecutor(final Consumer action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public CompletableFuture thenRunWithTPExecutor(final BiConsumer action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithTPExecutor(final Function action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public  CompletableFuture thenRunWithTPExecutor(final BiFunction action) {
+        return withTPExecutor().thenRun(action);
+    }
+
+    public CompletableFuture runAfterBoth(final CompletableFuture other, final Runnable action) {
+        return execute(new Callable() {
             @Override
-            public R call() {
-                T result = null;
-                Throwable throwable = null;
+            public Void call() throws Exception {
+                get();
+                other.get();
+                action.run();
+                return null;
+            }
+        });
+    }
 
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
+    public  CompletableFuture runAfterBoth(final CompletableFuture other, final Callable action) {
+        return execute(new Callable() {
+            @Override
+            public U call() throws Exception {
+                get();
+                other.get();
+                return action.call();
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterBoth(final CompletableFuture other, final BiConsumer action) {
+        return execute(new Callable() {
+            @Override
+            public Void call() throws Exception {
+                action.accept(get(), other.get());
+                return null;
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterBoth(final CompletableFuture other, final Consumer> action) {
+        return execute(new Runnable() {
+            @Override
+            public void run() {
+                final Pair result = get2();
+                final Pair result2 = other.get2();
+
+                action.accept(Tuple.of(result.left, result.right, result2.left, result.right));
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterBoth(final CompletableFuture other, final BiFunction action) {
+        return execute(new Callable() {
+            @Override
+            public R call() throws Exception {
+                return action.apply(get(), other.get());
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterBoth(final CompletableFuture other, final Function, R> action) {
+        return execute(new Callable() {
+            @Override
+            public R call() throws Exception {
+                final Pair result = get2();
+                final Pair result2 = other.get2();
+
+                return action.apply(Tuple.of(result.left, result.right, result2.left, result.right));
+            }
+        });
+    }
+
+    public CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other, final Runnable action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other, final Callable action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other, final BiConsumer action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other, final Consumer> action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other, final BiFunction action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterBoth(final CompletableFuture other,
+            final Function, R> action) {
+        return withUIExecutor().runAfterBoth(other, action);
+    }
+
+    public CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other, final Runnable action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other, final Callable action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other, final BiConsumer action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other,
+            final Consumer> action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other, final BiFunction action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterBoth(final CompletableFuture other,
+            final Function, R> action) {
+        return withSerialExecutor().runAfterBoth(other, action);
+    }
+
+    public CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other, final Runnable action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other, final Callable action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other, final BiConsumer action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other, final Consumer> action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other, final BiFunction action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterBoth(final CompletableFuture other,
+            final Function, R> action) {
+        return withTPExecutor().runAfterBoth(other, action);
+    }
+
+    public CompletableFuture runAfterEither(final CompletableFuture other, final Runnable action) {
+        return execute(new Callable() {
+            @Override
+            public Void call() throws Exception {
+                ((CompletableFuture) CompletableFuture.this).acceptEither((other), EMPTY_CONSUMER).get();
+                action.run();
+                return null;
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterEither(final CompletableFuture other, final Callable action) {
+        return execute(new Callable() {
+            @Override
+            public U call() throws Exception {
+                ((CompletableFuture) CompletableFuture.this).acceptEither((other), EMPTY_CONSUMER).get();
+
+                return action.call();
+            }
+        });
+    }
+
+    public CompletableFuture runAfterEither(final CompletableFuture other, final Consumer action) {
+        return execute(new Callable() {
+            @Override
+            public Void call() throws Exception {
+                final T result = applyToEither(other, (Function) IDENTITY_FUNCTION).get();
+                action.accept(result);
+                return null;
+            }
+        });
+    }
+
+    public CompletableFuture runAfterEither(final CompletableFuture other, final BiConsumer action) {
+        return execute(new Runnable() {
+            @Override
+            public void run() {
+                final Pair result = applyToEither(other, (Function) IDENTITY_FUNCTION).get2();
+
+                action.accept(result.left, result.right);
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterEither(final CompletableFuture other, final Function action) {
+        return execute(new Callable() {
+            @Override
+            public R call() throws Exception {
+                final T result = applyToEither(other, (Function) IDENTITY_FUNCTION).get();
+
+                return action.apply(result);
+            }
+        });
+    }
+
+    public  CompletableFuture runAfterEither(final CompletableFuture other, final BiFunction action) {
+        return execute(new Callable() {
+            @Override
+            public R call() throws Exception {
+                final Pair result = applyToEither(other, (Function) IDENTITY_FUNCTION).get2();
+
+                return action.apply(result.left, result.right);
+            }
+        });
+    }
+
+    public CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other, final Runnable action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other, final Callable action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other, final Consumer action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other, final BiConsumer action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other, final Function action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithUIExecutorAfterEither(final CompletableFuture other,
+            final BiFunction action) {
+        return withUIExecutor().runAfterEither(other, action);
+    }
+
+    public CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other, final Runnable action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other, final Callable action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other, final Consumer action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other,
+            final BiConsumer action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other, final Function action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithSerialExecutorAfterEither(final CompletableFuture other,
+            final BiFunction action) {
+        return withSerialExecutor().runAfterEither(other, action);
+    }
+
+    public CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other, final Runnable action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other, final Callable action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other, final Consumer action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other, final BiConsumer action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other, final Function action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture runWithTPExecutorAfterEither(final CompletableFuture other,
+            final BiFunction action) {
+        return withTPExecutor().runAfterEither(other, action);
+    }
+
+    public  CompletableFuture applyToEither(final CompletableFuture other, final Function action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning) && other.future.cancel(mayInterruptIfRunning);
+            }
+
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled() && other.future.isCancelled();
+            }
+
+            @Override
+            public boolean isDone() {
+                return future.isDone() || other.future.isDone();
+            }
+
+            @Override
+            public U get() throws InterruptedException, ExecutionException {
+                final OptionalNullable anySuccessResultOf = anySuccessResultOf(CompletableFuture.this, other);
+
+                if (anySuccessResultOf.isPresent()) {
+                    return action.apply(anySuccessResultOf.get());
                 }
 
-                return callback.on(throwable, result);
+                return action.apply(CompletableFuture.this.get());
+            }
+
+            @Override
+            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                final OptionalNullable anySuccessResultOf = anySuccessResultOf(Arrays.asList(CompletableFuture.this, other), unit.toMillis(timeout));
+
+                if (anySuccessResultOf.isPresent()) {
+                    return action.apply(anySuccessResultOf.get());
+                }
+
+                return action.apply(CompletableFuture.this.get());
+            }
+        }, asyncExecutor);
+    }
+
+    public CompletableFuture acceptEither(final CompletableFuture other, final Consumer action) {
+        return applyToEither(other, new Function() {
+            @Override
+            public Void apply(T t) {
+                action.accept(t);
+                return null;
             }
         });
     }
 
-    /**
-     * The callback will be executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background thread.
-     * 
-     * @param action
-     * @return
-     */
-    public  CompletableFuture executeInParallel(final Callback2.Action action) {
-        return AsyncExecutor.executeInParallel(new Callable() {
+    public CompletableFuture exceptionally(final Function action) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning);
+            }
+
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled();
+            }
+
+            @Override
+            public boolean isDone() {
+                return future.isDone();
+            }
+
             @Override
-            public R call() {
+            public T get() throws InterruptedException, ExecutionException {
                 try {
-                    return action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
+                    return future.get();
+                } catch (Throwable e) {
+                    return action.apply(e);
                 }
             }
-        });
+
+            @Override
+            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                try {
+                    return future.get(timeout, unit);
+                } catch (Throwable e) {
+                    return action.apply(e);
+                }
+            }
+        }, asyncExecutor);
+    }
+
+    //    public CompletableFuture whenComplete(final BiConsumer action) {
+    //        return new CompletableFuture<>(new Future() {
+    //            @Override
+    //            public boolean cancel(boolean mayInterruptIfRunning) {
+    //                return future.cancel(mayInterruptIfRunning);
+    //            }
+    //
+    //            @Override
+    //            public boolean isCancelled() {
+    //                return future.isCancelled();
+    //            }
+    //
+    //            @Override
+    //            public boolean isDone() {
+    //                return future.isDone();
+    //            }
+    //
+    //            @Override
+    //            public T get() throws InterruptedException, ExecutionException {
+    //                final Pair result = get2();
+    //
+    //                if (result.right != null) {
+    //                    try {
+    //                        action.accept(result.left, result.right);
+    //                    } catch (Throwable e) {
+    //                        // ignore.
+    //                    }
+    //
+    //                    if (result.right instanceof InterruptedException) {
+    //                        throw ((InterruptedException) result.right);
+    //                    } else if (result.right instanceof ExecutionException) {
+    //                        throw ((ExecutionException) result.right);
+    //                    } else {
+    //                        throw N.toRuntimeException(result.right);
+    //                    }
+    //                } else {
+    //                    action.accept(result.left, result.right);
+    //                    return result.left;
+    //                }
+    //            }
+    //
+    //            @Override
+    //            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+    //                final Pair result = get2(timeout, unit);
+    //
+    //                if (result.right != null) {
+    //                    try {
+    //                        action.accept(result.left, result.right);
+    //                    } catch (Throwable e) {
+    //                        // ignore.
+    //                    }
+    //
+    //                    if (result.right instanceof InterruptedException) {
+    //                        throw ((InterruptedException) result.right);
+    //                    } else if (result.right instanceof ExecutionException) {
+    //                        throw ((ExecutionException) result.right);
+    //                    } else {
+    //                        throw N.toRuntimeException(result.right);
+    //                    }
+    //                } else {
+    //                    action.accept(result.left, result.right);
+    //                    return result.left;
+    //                }
+    //            }
+    //        }, asyncExecutor);
+    //    }
+    //
+    //    public  CompletableFuture handle(final BiFunction action) {
+    //        return new CompletableFuture<>(new Future() {
+    //            @Override
+    //            public boolean cancel(boolean mayInterruptIfRunning) {
+    //                return future.cancel(mayInterruptIfRunning);
+    //            }
+    //
+    //            @Override
+    //            public boolean isCancelled() {
+    //                return future.isCancelled();
+    //            }
+    //
+    //            @Override
+    //            public boolean isDone() {
+    //                return future.isDone();
+    //            }
+    //
+    //            @Override
+    //            public U get() throws InterruptedException, ExecutionException {
+    //                try {
+    //                    final T result = future.get();
+    //                    return action.apply(result, null);
+    //                } catch (Throwable e) {
+    //                    return action.apply(null, e);
+    //                }
+    //            }
+    //
+    //            @Override
+    //            public U get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+    //                try {
+    //                    final T result = future.get(timeout, unit);
+    //                    return action.apply(result, null);
+    //                } catch (Throwable e) {
+    //                    return action.apply(null, e);
+    //                }
+    //            }
+    //        }, asyncExecutor);
+    //    }
+
+    private CompletableFuture execute(final Runnable command) {
+        return execute(new FutureTask(command, null));
+    }
+
+    private  CompletableFuture execute(final Callable command) {
+        return execute(new FutureTask<>(command));
+    }
+
+    private  CompletableFuture execute(final FutureTask futureTask) {
+        if (delay > 0) {
+            if (asyncExecutor instanceof UIExecutor) {
+                ((UIExecutor) asyncExecutor).execute(futureTask, delay);
+            } else {
+                N.sleep(delay);
+                asyncExecutor.execute(futureTask);
+            }
+        } else {
+            asyncExecutor.execute(futureTask);
+        }
+
+        return new CompletableFuture<>(futureTask, asyncExecutor);
+    }
+
+    public CompletableFuture withUIExecutor() {
+        return with(AsyncExecutor.UI_EXECUTOR);
+    }
+
+    public CompletableFuture withUIExecutor(final long delay) {
+        return with(AsyncExecutor.UI_EXECUTOR, delay);
+    }
+
+    public CompletableFuture withSerialExecutor() {
+        return with(AsyncExecutor.SERIAL_EXECUTOR);
     }
 
     /**
-     * The callback will be executed with {@code android.io.AsyncTask#THREAD_POOL_EXECUTOR} in background thread.
-     * 
-     * @param callback
+     * With Thread Pool Executor.
      * @return
      */
-    public  CompletableFuture executeInParallel(final Callback2 callback) {
-        return AsyncExecutor.executeInParallel(new Callable() {
+    public CompletableFuture withTPExecutor() {
+        return with(AsyncExecutor.THREAD_POOL_EXECUTOR);
+    }
+
+    public CompletableFuture with(Executor executor) {
+        return with(executor, 0);
+    }
+
+    private CompletableFuture with(final Executor executor, final long delay) {
+        return new CompletableFuture<>(new Future() {
             @Override
-            public R call() {
-                T result = null;
-                Throwable throwable = null;
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                return future.cancel(mayInterruptIfRunning);
+            }
 
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
+            @Override
+            public boolean isCancelled() {
+                return future.isCancelled();
+            }
+
+            @Override
+            public boolean isDone() {
+                return future.isDone();
+            }
+
+            @Override
+            public T get() throws InterruptedException, ExecutionException {
+                return future.get();
+            }
+
+            @Override
+            public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                return future.get(timeout, unit);
+            }
+        }, executor, delay);
+    }
+
+    public static CompletableFuture allOf(final CompletableFuture... cfs) {
+        return allOf(N.asList(cfs));
+    }
+
+    public static CompletableFuture allOf(final Collection> cfs) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                for (CompletableFuture future : cfs) {
+                    if (future.cancel(mayInterruptIfRunning) == false) {
+                        return false;
+                    }
                 }
 
-                return callback.on(throwable, result);
+                return true;
             }
-        });
+
+            @Override
+            public boolean isCancelled() {
+                for (CompletableFuture future : cfs) {
+                    if (future.isCancelled()) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            @Override
+            public boolean isDone() {
+                for (CompletableFuture future : cfs) {
+                    if (future.isDone() == false) {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            @Override
+            public Void get() throws InterruptedException, ExecutionException {
+                for (CompletableFuture future : cfs) {
+                    future.get();
+                }
+
+                return null;
+            }
+
+            @Override
+            public Void get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                final long timeoutInMillis = unit.toMillis(timeout);
+                final long now = N.currentMillis();
+                final long endTime = timeoutInMillis > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + timeoutInMillis;
+
+                for (CompletableFuture future : cfs) {
+                    future.get(N.max(0, endTime - N.currentMillis()), TimeUnit.MILLISECONDS);
+                }
+
+                return null;
+            }
+        }, ((CompletableFuture) cfs.iterator().next()).asyncExecutor);
+    }
+
+    public static CompletableFuture anyOf(final CompletableFuture... cfs) {
+        return anyOf(N.asList(cfs));
+    }
+
+    public static CompletableFuture anyOf(final Collection> cfs) {
+        return new CompletableFuture<>(new Future() {
+            @Override
+            public boolean cancel(boolean mayInterruptIfRunning) {
+                for (CompletableFuture future : cfs) {
+                    if (future.cancel(mayInterruptIfRunning) == false) {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            @Override
+            public boolean isCancelled() {
+                for (CompletableFuture future : cfs) {
+                    if (future.isCancelled() == false) {
+                        return false;
+                    }
+                }
+
+                return true;
+            }
+
+            @Override
+            public boolean isDone() {
+                for (CompletableFuture future : cfs) {
+                    if (future.isDone()) {
+                        return true;
+                    }
+                }
+
+                return false;
+            }
+
+            @Override
+            public Object get() throws InterruptedException, ExecutionException {
+                return get(anyResultOf(cfs));
+            }
+
+            @Override
+            public Object get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+                return get(anyResultOf(cfs, unit.toMillis(timeout)));
+            }
+
+            private Object get(final Optional> op) throws InterruptedException, ExecutionException {
+                if (op.isPresent()) {
+                    if (op.get().right != null) {
+                        if (op.get().right instanceof InterruptedException) {
+                            throw ((InterruptedException) op.get().right);
+                        } else if (op.get().right instanceof ExecutionException) {
+                            throw ((ExecutionException) op.get().right);
+                        } else {
+                            throw N.toRuntimeException(op.get().right);
+                        }
+                    }
+
+                    return op.get().left;
+                } else {
+                    throw new InterruptedException("Failed to get result");
+                }
+            }
+        }, ((CompletableFuture) cfs.iterator().next()).asyncExecutor);
     }
 
     /**
-     * The callback will be executed in main(UI) thread.
+     * Returns the first result, which could be an exception.
      * 
-     * @param action
+     * @param a
      * @return
      */
-    public  CompletableFuture executeOnUiThread(final Callback2.Action action) {
-        return AsyncExecutor.executeOnUiThread(new Callable() {
-            @Override
-            public R call() {
-                try {
-                    return action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
+    public static  Optional> anyResultOf(final CompletableFuture... a) {
+        return anyResultOf(Arrays.asList(a));
+    }
+
+    /**
+     * Returns the first result, which could be an exception.
+     * 
+     * @param c
+     * @return
+     */
+    public static  Optional> anyResultOf(final Collection> c) {
+        final MutableBoolean stopSign = MutableBoolean.of(false);
+        final BlockingQueue> queue = allResultOf(c, stopSign);
+
+        try {
+            Pair result = null;
+
+            for (int i = 0, len = c.size(); i < len; i++) {
+                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
+
+                if (result != null) {
+                    stopSign.setTrue();
+                    return Optional.of(result);
                 }
             }
-        });
+        } catch (InterruptedException e) {
+            // throw N.toRuntimeException(e);
+            logger.error("Thread is interrupted while retriving result from queue", e);
+            stopSign.setTrue();
+            return Optional.empty();
+        }
+
+        stopSign.setTrue();
+        return Optional.empty();
     }
 
     /**
-     * The callback will be executed in main(UI) thread.
+     * Returns the first result, which could be an exception.
      * 
-     * @param callback
+     * @param c
+     * @param maxTimeout
      * @return
      */
-    public  CompletableFuture executeOnUiThread(final Callback2 callback) {
-        return AsyncExecutor.executeOnUiThread(new Callable() {
-            @Override
-            public R call() {
-                T result = null;
-                Throwable throwable = null;
+    public static  Optional> anyResultOf(final Collection> c, final long maxTimeout) {
+        final MutableBoolean stopSign = MutableBoolean.of(false);
+        final BlockingQueue> queue = allResultOf(c, stopSign);
+        final long now = N.currentMillis();
+        final long endTime = maxTimeout > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + maxTimeout;
 
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
+        try {
+            Pair result = null;
+
+            for (int i = 0, len = c.size(); i < len; i++) {
+                long timeout = endTime - N.currentMillis();
+
+                if (timeout <= 0) {
+                    stopSign.setTrue();
+                    return Optional.empty();
                 }
 
-                return callback.on(throwable, result);
+                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
+
+                if (result != null) {
+                    stopSign.setTrue();
+                    return Optional.of(result);
+                }
             }
-        });
+        } catch (InterruptedException e) {
+            // throw N.toRuntimeException(e);
+            logger.error("Thread is interrupted while retriving result from queue", e);
+            stopSign.setTrue();
+            return Optional.empty();
+        }
+
+        stopSign.setTrue();
+        return Optional.empty();
     }
 
     /**
-     * The callback will be executed in main(UI) thread.
+     * Returns the first non-exception result or empty if fail to get result for all futures.
      * 
-     * @param action
-     * @param delay
+     * @param a
      * @return
      */
-    public  CompletableFuture executeOnUiThread(final Callback2.Action action, final long delay) {
-        return AsyncExecutor.executeOnUiThread(new Callable() {
-            @Override
-            public R call() {
-                try {
-                    return action.on(get());
-                } catch (InterruptedException | ExecutionException e) {
-                    throw N.toRuntimeException(e);
-                }
-            }
-        }, delay);
+    public static  OptionalNullable anySuccessResultOf(final CompletableFuture... a) {
+        return anySuccessResultOf(Arrays.asList(a));
     }
 
     /**
-     * The callback will be executed in main(UI) thread.
+     * Returns the first non-exception result or empty if fail to get result for all futures.
      * 
-     * @param callback
-     * @param delay
+     * @param c
      * @return
      */
-    public  CompletableFuture executeOnUiThread(final Callback2 callback, final long delay) {
-        return AsyncExecutor.executeOnUiThread(new Callable() {
-            @Override
-            public R call() {
-                T result = null;
-                Throwable throwable = null;
+    public static  OptionalNullable anySuccessResultOf(final Collection> c) {
+        final MutableBoolean stopSign = MutableBoolean.of(false);
+        final BlockingQueue> queue = allResultOf(c, stopSign);
 
-                try {
-                    result = get();
-                } catch (Throwable e) {
-                    throwable = e;
-                }
+        try {
+            Pair result = null;
+
+            for (int i = 0, len = c.size(); i < len; i++) {
+                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
 
-                return callback.on(throwable, result);
+                if (result != null && result.right == null) {
+                    stopSign.setTrue();
+                    return OptionalNullable.of(result.left);
+                }
             }
-        }, delay);
+        } catch (InterruptedException e) {
+            // throw N.toRuntimeException(e);
+            logger.error("Thread is interrupted while retriving result from queue", e);
+            stopSign.setTrue();
+            return OptionalNullable.empty();
+        }
+
+        stopSign.setTrue();
+        return OptionalNullable.empty();
     }
 
-    static class CompletedFuture extends CompletableFuture {
-        private static final Runnable EMPTY_CALLABLE = new Runnable() {
-            @Override
-            public void run() {
-                // do nothing
-            }
-        };
+    /**
+     * Returns the first result, which could be an exception.
+     * 
+     * @param c
+     * @param maxTimeout
+     * @return
+     */
+    public static  OptionalNullable anySuccessResultOf(final Collection> c, final long maxTimeout) {
+        final MutableBoolean stopSign = MutableBoolean.of(false);
+        final BlockingQueue> queue = allResultOf(c, stopSign);
+        final long now = N.currentMillis();
+        final long endTime = maxTimeout > Long.MAX_VALUE - now ? Long.MAX_VALUE : now + maxTimeout;
 
-        private final T result;
+        try {
+            Pair result = null;
 
-        CompletedFuture(T result) {
-            super(EMPTY_CALLABLE, null);
+            for (int i = 0, len = c.size(); i < len; i++) {
+                long timeout = endTime - N.currentMillis();
 
-            this.result = result;
-        }
+                if (timeout <= 0) {
+                    stopSign.setTrue();
+                    return OptionalNullable.empty();
+                }
 
-        @Override
-        public boolean cancel(boolean mayInterruptIfRunning) {
-            return false;
-        }
+                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
 
-        @Override
-        public boolean isCancelled() {
-            return false;
+                if (result != null && result.right == null) {
+                    stopSign.setTrue();
+                    return OptionalNullable.of(result.left);
+                }
+            }
+        } catch (InterruptedException e) {
+            // throw N.toRuntimeException(e);
+            logger.error("Thread is interrupted while retriving result from queue", e);
+            stopSign.setTrue();
+            return OptionalNullable.empty();
         }
 
-        @Override
-        public boolean isDone() {
-            return true;
-        }
+        stopSign.setTrue();
+        return OptionalNullable.empty();
+    }
 
-        @Override
-        public T get() {
-            return result;
-        }
+    public static  BlockingQueue> allResultOf(final CompletableFuture... a) {
+        return allResultOf(Arrays.asList(a));
+    }
 
-        @Override
-        public T get(long timeout, TimeUnit unit) {
-            return result;
-        }
+    /**
+     * 
+     * @param c
+     * @return
+     */
+    public static  BlockingQueue> allResultOf(final Collection> c) {
+        return allResultOf(c, null);
+    }
 
-        @Override
-        public void run() {
-            // do nothing. it's already done.
+    private static  BlockingQueue> allResultOf(final Collection> c,
+            final MutableBoolean stopSign) {
+        final ExecutorService executor = Executors.newFixedThreadPool(c.size());
+        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
+
+        for (CompletableFuture e : c) {
+            final CompletableFuture futuer = (CompletableFuture) e;
+
+            executor.execute(new Runnable() {
+                @Override
+                public void run() {
+                    if (stopSign == null || stopSign.value() == false) {
+                        queue.offer(futuer.get2());
+                    }
+                }
+            });
         }
+
+        return queue;
     }
 }
diff --git a/src/com/landawn/abacus/android/util/Util.java b/src/com/landawn/abacus/android/util/Util.java
index 07d565da..6917b35c 100644
--- a/src/com/landawn/abacus/android/util/Util.java
+++ b/src/com/landawn/abacus/android/util/Util.java
@@ -19,11 +19,9 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.Callable;
 
 import com.landawn.abacus.DataSet;
 import com.landawn.abacus.android.util.SQLiteExecutor.Type;
-import com.landawn.abacus.annotation.Beta;
 import com.landawn.abacus.logging.Logger;
 import com.landawn.abacus.logging.LoggerFactory;
 import com.landawn.abacus.util.Array;
@@ -695,381 +693,6 @@ public static boolean isUiThread(Thread thread) {
         return thread == Looper.getMainLooper().getThread();
     }
 
-    /**
-     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param action
-     */
-    public static CompletableFuture runInBackground(final Runnable action) {
-        if (isUiThread()) {
-            return AsyncExecutor.execute(action);
-        } else {
-            action.run();
-            return CompletableFuture.completed(null);
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param actions
-     */
-    @Beta
-    static void runInBackground(final List actions) {
-        for (Runnable action : actions) {
-            runInBackground(action);
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param action
-     * @return
-     */
-    public static  CompletableFuture runInBackground(final Callable action) {
-        if (isUiThread()) {
-            return AsyncExecutor.execute(action);
-        } else {
-            try {
-                return CompletableFuture.completed(action.call());
-            } catch (Exception e) {
-                throw N.toRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  void runInBackground(final Collection> actions) {
-        for (Callable action : actions) {
-            runInBackground(action);
-        }
-    }
-
-    /**
-     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param action
-     */
-    public static CompletableFuture runInParallel(final Runnable action) {
-        if (isUiThread()) {
-            return AsyncExecutor.executeInParallel(action);
-        } else {
-            action.run();
-            return CompletableFuture.completed(null);
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param actions
-     */
-    @Beta
-    static void runInParallel(final List actions) {
-        for (Runnable action : actions) {
-            runInParallel(action);
-        }
-    }
-
-    /**
-     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param action
-     * @return
-     */
-    public static  CompletableFuture runInParallel(final Callable action) {
-        if (isUiThread()) {
-            return AsyncExecutor.executeInParallel(action);
-        } else {
-            try {
-                return CompletableFuture.completed(action.call());
-            } catch (Exception e) {
-                throw N.toRuntimeException(e);
-            }
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} if current thread is UI thread.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  void runInParallel(final Collection> actions) {
-        for (Callable action : actions) {
-            runInParallel(action);
-        }
-    }
-
-    /**
-     * Execute the action right now if current thread is UI thread or execute it asynchronously if current thread is a background thread.
-     * 
-     * @param action
-     */
-    public static CompletableFuture runOnUiThread(final Runnable action) {
-        if (isUiThread()) {
-            action.run();
-            return CompletableFuture.completed(null);
-        } else {
-            return AsyncExecutor.executeOnUiThread(action);
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is UI thread or execute them asynchronously if current thread is a background thread.
-     * 
-     * @param actions
-     */
-    @Beta
-    static void runOnUiThread(final List actions) {
-        for (Runnable action : actions) {
-            runOnUiThread(action);
-        }
-    }
-
-    /**
-     * Execute the action right now if current thread is UI thread or execute it asynchronously if current thread is a background thread.
-     * 
-     * @param action
-     * @return
-     */
-    public static  CompletableFuture runOnUiThread(final Callable action) {
-        if (isUiThread()) {
-            try {
-                return CompletableFuture.completed(action.call());
-            } catch (Exception e) {
-                throw N.toRuntimeException(e);
-            }
-        } else {
-            return AsyncExecutor.executeOnUiThread(action);
-        }
-    }
-
-    /**
-     * Execute the actions right now if current thread is UI thread or execute them asynchronously if current thread is a background thread.
-     * 
-     * @param actions
-     * @return
-     */
-    @Beta
-    static  void runOnUiThread(final Collection> actions) {
-        for (Callable action : actions) {
-            runOnUiThread(action);
-        }
-    }
-
-    //    /**
-    //     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param action
-    //     */
-    //    public static void callInBackground(final Runnable action) {
-    //        if (isUiThread()) {
-    //            try {
-    //                AsyncExecutor.execute(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        } else {
-    //            action.run();
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param actions
-    //     */
-    //    @Beta
-    //    static void callInBackground(final List actions) {
-    //        for (Runnable action : actions) {
-    //            callInBackground(action);
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param action
-    //     * @return
-    //     */
-    //    public static  T callInBackground(final Callable action) {
-    //        if (isUiThread()) {
-    //            try {
-    //                return AsyncExecutor.execute(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        } else {
-    //            try {
-    //                return action.call();
-    //            } catch (Exception e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#SERIAL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param actions
-    //     * @return
-    //     */
-    //    @Beta
-    //    static  List callInBackground(final Collection> actions) {
-    //        final List result = new ArrayList(actions.size());
-    //
-    //        for (Callable action : actions) {
-    //            result.add(callInBackground(action));
-    //        }
-    //
-    //        return result;
-    //    }
-    //
-    //    /**
-    //     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param action
-    //     */
-    //    public static void callInParallel(final Runnable action) {
-    //        if (isUiThread()) {
-    //            try {
-    //                AsyncExecutor.executeInParallel(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        } else {
-    //            action.run();
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param actions
-    //     */
-    //    @Beta
-    //    static void callInParallel(final List actions) {
-    //        for (Runnable action : actions) {
-    //            callInParallel(action);
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the action right now if current thread is a background thread or execute it asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param action
-    //     * @return
-    //     */
-    //    public static  T callInParallel(final Callable action) {
-    //        if (isUiThread()) {
-    //            try {
-    //                return AsyncExecutor.executeInParallel(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        } else {
-    //            try {
-    //                return action.call();
-    //            } catch (Exception e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is a background thread or execute them asynchronously with @{code android.os.AsyncTask#THREAD_POOL_EXECUTOR} and waiting for result before it returns if current thread is UI thread.
-    //     * 
-    //     * @param actions
-    //     * @return
-    //     */
-    //    @Beta
-    //    static  List callInParallel(final Collection> actions) {
-    //        final List result = new ArrayList(actions.size());
-    //
-    //        for (Callable action : actions) {
-    //            result.add(callInParallel(action));
-    //        }
-    //
-    //        return result;
-    //    }
-    //
-    //    /**
-    //     * Execute the action right now if current thread is UI thread or execute it asynchronously and waiting for result before it returns if current thread is a background thread.
-    //     * 
-    //     * @param action
-    //     */
-    //    public static void callOnUiThread(final Runnable action) {
-    //        if (isUiThread()) {
-    //            action.run();
-    //        } else {
-    //            try {
-    //                AsyncExecutor.executeOnUiThread(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is UI thread or execute them asynchronously and waiting for result before it returns if current thread is a background thread.
-    //     * 
-    //     * @param actions
-    //     */
-    //    @Beta
-    //    static void callOnUiThread(final List actions) {
-    //        for (Runnable action : actions) {
-    //            callOnUiThread(action);
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the action right now if current thread is UI thread or execute it asynchronously and waiting for result before it returns if current thread is a background thread.
-    //     * 
-    //     * @param action
-    //     * @return
-    //     */
-    //    public static  T callOnUiThread(final Callable action) {
-    //        if (isUiThread()) {
-    //            try {
-    //                return action.call();
-    //            } catch (Exception e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        } else {
-    //            try {
-    //                return AsyncExecutor.executeOnUiThread(action).get();
-    //            } catch (InterruptedException | ExecutionException e) {
-    //                throw N.toRuntimeException(e);
-    //            }
-    //        }
-    //    }
-    //
-    //    /**
-    //     * Execute the actions right now if current thread is UI thread or execute them asynchronously and waiting for result before it returns if current thread is a background thread.
-    //     * 
-    //     * @param actions
-    //     * @return
-    //     */
-    //    @Beta
-    //    static  List callOnUiThread(final Collection> actions) {
-    //        final List result = new ArrayList(actions.size());
-    //
-    //        for (Callable action : actions) {
-    //            result.add(callOnUiThread(action));
-    //        }
-    //
-    //        return result;
-    //    }
-
     public static  T getViewById(View root, int id) {
         return (T) root.findViewById(id);
     }
diff --git a/src/com/landawn/abacus/util/AsyncExecutor.java b/src/com/landawn/abacus/util/AsyncExecutor.java
index 7654d593..032ae099 100644
--- a/src/com/landawn/abacus/util/AsyncExecutor.java
+++ b/src/com/landawn/abacus/util/AsyncExecutor.java
@@ -19,10 +19,9 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
+import java.util.concurrent.FutureTask;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
@@ -92,11 +91,7 @@ public AsyncExecutor(final ExecutorService executorService) {
     }
 
     public CompletableFuture execute(final Runnable command) {
-        final CompletableFuture future = new CompletableFuture<>(this, command, null);
-
-        getExecutorService().execute(future);
-
-        return future;
+        return execute(new FutureTask(command, null));
     }
 
     public List> execute(final Runnable... commands) {
@@ -120,11 +115,7 @@ public List> execute(final List comm
     }
 
     public  CompletableFuture execute(final Callable command) {
-        final CompletableFuture future = new CompletableFuture<>(this, command);
-
-        getExecutorService().execute(future);
-
-        return future;
+        return execute(new FutureTask<>(command));
     }
 
     public  List> execute(final Callable... commands) {
@@ -147,24 +138,6 @@ public  List> execute(final Collection CompletableFuture invoke(final Method method, final Object... args) {
-    //        return invoke(null, method, args);
-    //    }
-    //
-    //    public  CompletableFuture invoke(final Object instance, final Method method, final Object... args) {
-    //        final CompletableFuture future = new CompletableFuture(this, new Callable() {
-    //            @Override
-    //            @SuppressWarnings("unchecked")
-    //            public T call() throws Exception {
-    //                return (T) method.invoke(instance, args);
-    //            }
-    //        });
-    //
-    //        getExecutorService().execute(future);
-    //
-    //        return future;
-    //    }
-
     public CompletableFuture execute(final Runnable action, final int retryTimes, final long retryInterval,
             final Function retryCondition) {
         return execute(new Runnable() {
@@ -186,591 +159,15 @@ public T call() throws Exception {
         });
     }
 
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param a
-     * @return
-     */
-    public static  Optional> firstResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @return
-     */
-    public static  Optional> firstResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  Optional> firstResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    return Optional.empty();
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    return Optional.of(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        return Optional.empty();
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param a
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param c
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  OptionalNullable firstSuccessResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    return OptionalNullable.empty();
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    return OptionalNullable.of(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        return OptionalNullable.empty();
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param a
-     * @return
-     */
-    public static  Optional> lastResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @return
-     */
-    public static  Optional> lastResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  Optional> lastResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder> holder = new Holder<>((Pair) N.NULL_MASK);
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    break;
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null) {
-                    holder.setValue(result);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return Optional.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return Optional.empty();
-        } else {
-            return Optional.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param a
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = a.length; i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first non-exception result or empty if fail to get result for all futures.
-     * 
-     * @param c
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                result = queue.poll(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    /**
-     * Returns the first result, which could be an exception.
-     * 
-     * @param c
-     * @param maxTimeout
-     * @return
-     */
-    public static  OptionalNullable lastSuccessResult(final Collection> c, final long maxTimeout) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        final Holder holder = new Holder<>((T) N.NULL_MASK);
-        final long endTime = N.currentMillis() + maxTimeout;
-
-        try {
-            Pair result = null;
-
-            for (int i = 0, len = c.size(); i < len; i++) {
-                long timeout = endTime - N.currentMillis();
-
-                if (timeout <= 0) {
-                    break;
-                }
-
-                result = queue.poll(timeout, TimeUnit.MILLISECONDS);
-
-                if (result != null && result.right == null) {
-                    holder.setValue(result.left);
-                }
-            }
-        } catch (InterruptedException e) {
-            // throw N.toRuntimeException(e);
-            logger.error("Thread is interrupted while retriving result from queue", e);
-            return OptionalNullable.empty();
-        }
-
-        if (holder.value == N.NULL_MASK) {
-            return OptionalNullable.empty();
-        } else {
-            return OptionalNullable.of(holder.value);
-        }
-    }
-
-    public static  List> concat(final CompletableFuture... a) {
-        final List> queue = new ArrayList<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).get(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.add(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
-
-    /**
-     * 
-     * @param c
-     * @return
-     */
-    public static  List> concat(final Collection> c) {
-        final List> queue = new ArrayList<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).get(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.add(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
-
-    public static  BlockingQueue> parallelConcat(final CompletableFuture... a) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(a.length);
-
-        for (CompletableFuture future : a) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
-
-        return queue;
-    }
+    private  CompletableFuture execute(final FutureTask futureTask) {
+        final ExecutorService executor = getExecutorService();
 
-    /**
-     * 
-     * @param c
-     * @return
-     */
-    public static  BlockingQueue> parallelConcat(final Collection> c) {
-        final BlockingQueue> queue = new ArrayBlockingQueue<>(c.size());
-
-        for (CompletableFuture future : c) {
-            ((CompletableFuture) future).callback(new Callback() {
-                @Override
-                public void on(Throwable e, T result) {
-                    queue.offer(Pair.of(result, e));
-                }
-            });
-        }
+        executor.execute(futureTask);
 
-        return queue;
+        return new CompletableFuture<>(futureTask, executor);
     }
 
-    ExecutorService getExecutorService() {
+    private ExecutorService getExecutorService() {
         if (executorService == null) {
             synchronized (this) {
                 if (executorService == null) {
@@ -790,6 +187,5 @@ ExecutorService getExecutorService() {
      */
     @Beta
     static final class Asyn extends AsyncExecutor {
-
     }
 }