All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.AsyncExecutor Maven / Gradle / Ivy

/*
 * Copyright (c) 2015, Haiyang Li.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.landawn.abacus.util;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
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;

import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.Predicate;

/**
 *
 * @author Haiyang Li
 * @since 0.8
 */
public class AsyncExecutor {

    private static final Logger logger = LoggerFactory.getLogger(AsyncExecutor.class);

    private static final int DEFAULT_CORE_POOL_SIZE = Math.max(8, IOUtil.CPU_CORES);

    private static final int DEFAULT_MAX_THREAD_POOL_SIZE = Math.max(16, IOUtil.CPU_CORES);

    private final int coreThreadPoolSize;

    private final int maxThreadPoolSize;

    private final long keepAliveTime;

    private final TimeUnit unit;

    private volatile Executor executor;

    public AsyncExecutor() {
        this(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAX_THREAD_POOL_SIZE, 180L, TimeUnit.SECONDS);
    }

    public AsyncExecutor(int coreThreadPoolSize, int maxThreadPoolSize, long keepAliveTime, TimeUnit unit) {
        N.checkArgNotNegative(coreThreadPoolSize, "coreThreadPoolSize");
        N.checkArgNotNegative(maxThreadPoolSize, "maxThreadPoolSize");
        N.checkArgNotNegative(keepAliveTime, "keepAliveTime");
        N.checkArgNotNull(unit, "unit");

        this.coreThreadPoolSize = coreThreadPoolSize;
        this.maxThreadPoolSize = Math.max(coreThreadPoolSize, maxThreadPoolSize);
        this.keepAliveTime = keepAliveTime;
        this.unit = unit;

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                shutdown();
            }
        });
    }

    public AsyncExecutor(final Executor executor) {
        this(getCorePoolSize(executor), getMaximumPoolSize(executor), getKeepAliveTime(executor), TimeUnit.MILLISECONDS);

        this.executor = executor;
    }

    private static int getCorePoolSize(final Executor executor) {
        return executor instanceof ThreadPoolExecutor ? ((ThreadPoolExecutor) executor).getCorePoolSize() : DEFAULT_CORE_POOL_SIZE;
    }

    private static int getMaximumPoolSize(final Executor executor) {
        return executor instanceof ThreadPoolExecutor ? ((ThreadPoolExecutor) executor).getMaximumPoolSize() : DEFAULT_CORE_POOL_SIZE;
    }

    private static long getKeepAliveTime(final Executor executor) {
        return executor instanceof ThreadPoolExecutor ? ((ThreadPoolExecutor) executor).getKeepAliveTime(TimeUnit.MILLISECONDS)
                : TimeUnit.SECONDS.toMillis(180);
    }

    /**
     *
     * @param command
     * @return
     */
    public ContinuableFuture execute(final Throwables.Runnable command) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                command.run();
                return null;
            }
        }));
    }

    /**
     * 
     * @param command
     * @param onComplete
     * @return
     */
    public ContinuableFuture execute(final Throwables.Runnable command, final java.lang.Runnable onComplete) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public Void call() throws Exception {
                try {
                    command.run();
                    return null;
                } finally {
                    onComplete.run();
                }
            }
        }));
    }

    /**
     *
     * @param commands
     * @return
     * @deprecated
     */
    @Deprecated
    @SafeVarargs
    public final List> execute(final Throwables.Runnable... commands) {
        if (N.isNullOrEmpty(commands)) {
            return new ArrayList<>();
        }

        final List> results = new ArrayList<>(commands.length);

        for (int i = 0, len = commands.length; i < len; i++) {
            results.add(execute(commands[i]));
        }

        return results;
    }

    /**
     *
     * @param commands
     * @return
     */
    public List> execute(final List> commands) {
        if (N.isNullOrEmpty(commands)) {
            return new ArrayList<>();
        }

        final List> results = new ArrayList<>(commands.size());

        for (Throwables.Runnable cmd : commands) {
            results.add(execute(cmd));
        }

        return results;
    }

    /**
     *
     * @param 
     * @param command
     * @return
     */
    public  ContinuableFuture execute(final Callable command) {
        return execute(new FutureTask<>(command));
    }

    /**
     * 
     * @param 
     * @param command
     * @param onComplete
     * @return
     */
    public  ContinuableFuture execute(final Callable command, final java.lang.Runnable onComplete) {
        return execute(new FutureTask<>(new Callable() {
            @Override
            public R call() throws Exception {
                try {
                    return command.call();
                } finally {
                    onComplete.run();
                }
            }
        }));
    }

    /**
     *
     * @param 
     * @param commands
     * @return
     * @deprecated
     */
    @Deprecated
    @SafeVarargs
    public final  List> execute(final Callable... commands) {
        if (N.isNullOrEmpty(commands)) {
            return new ArrayList<>();
        }

        final List> results = new ArrayList<>(commands.length);

        for (int i = 0, len = commands.length; i < len; i++) {
            results.add(execute(commands[i]));
        }

        return results;
    }

    /**
     *
     * @param 
     * @param commands
     * @return
     */
    public  List> execute(final Collection> commands) {
        if (N.isNullOrEmpty(commands)) {
            return new ArrayList<>();
        }

        final List> results = new ArrayList<>(commands.size());

        for (Callable cmd : commands) {
            results.add(execute(cmd));
        }

        return results;
    }

    /**
     *
     * @param action
     * @param retryTimes
     * @param retryInterval
     * @param retryCondition
     * @return
     */
    public ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes, final long retryInterval,
            final Predicate retryCondition) {
        return execute(new Callable() {
            @Override
            public Void call() throws Exception {
                Retry.of(retryTimes, retryInterval, retryCondition).run(action);
                return null;
            }
        });
    }

    /**
     *
     * @param 
     * @param action
     * @param retryTimes
     * @param retryInterval
     * @param retryCondition
     * @return
     */
    public  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryInterval,
            final BiPredicate retryCondition) {
        return execute(new Callable() {
            @Override
            public R call() throws Exception {
                final Retry retry = Retry.of(retryTimes, retryInterval, retryCondition);
                return retry.call(action);
            }
        });
    }

    /**
     *
     * @param 
     * @param futureTask
     * @return
     */
     ContinuableFuture execute(final FutureTask futureTask) {
        final Executor executor = getExecutor();

        executor.execute(futureTask);

        return new ContinuableFuture<>(futureTask, null, executor);
    }

    /**
     * Gets the executor.
     *
     * @return
     */
    Executor getExecutor() {
        if (executor == null) {
            synchronized (this) {
                if (executor == null) {
                    final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(coreThreadPoolSize, maxThreadPoolSize, keepAliveTime, unit,
                            new LinkedBlockingQueue());
                    threadPoolExecutor.allowCoreThreadTimeOut(true);
                    executor = threadPoolExecutor;
                }
            }
        }

        return executor;
    }

    @Override
    public String toString() {
        final String activeCount = executor instanceof ThreadPoolExecutor ? "" + ((ThreadPoolExecutor) executor).getActiveCount() : "?";

        return "{coreThreadPoolSize: " + coreThreadPoolSize + ", maxThreadPoolSize: " + maxThreadPoolSize + ", activeCount: " + activeCount
                + ", keepAliveTime: " + unit.toMillis(keepAliveTime) + "ms, Executor: " + N.toString(executor) + "}";
    }

    public synchronized void shutdown() {
        if (executor == null || !(executor instanceof ExecutorService)) {
            return;
        }

        final ExecutorService executorService = (ExecutorService) executor;

        logger.warn("Starting to shutdown task in AsyncExecutor");

        try {
            executorService.shutdown();

            if (!executorService.isTerminated()) {
                executorService.awaitTermination(60, TimeUnit.SECONDS);
            }
        } catch (InterruptedException e) {
            logger.warn("Not all the requests/tasks executed in AsyncExecutor are completed successfully before shutdown.");
        } finally {
            executor = null;
            logger.warn("Completed to shutdown task in AsyncExecutor");
        }

    }

    @Override
    public void finalize() {
        shutdown();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy