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

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

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 5.2.4
Show newest version
/*
 * 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 java.util.function.BiPredicate;
import java.util.function.Predicate;

import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;

/**
 *
 * @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 * 2);

    private final int coreThreadPoolSize;

    private final int maxThreadPoolSize;

    private final long keepAliveTime;

    private final TimeUnit unit;

    private volatile Executor executor; //NOSONAR

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

    /**
     * 
     *
     * @param coreThreadPoolSize 
     * @param maxThreadPoolSize 
     * @param keepAliveTime 
     * @param unit 
     */
    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;
    }

    /**
     * 
     *
     * @param executor 
     */
    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<>(() -> {
            command.run();
            return null;
        }));
    }

    /**
     *
     * @param command
     * @param actionInFinal
     * @return
     */
    public ContinuableFuture execute(final Throwables.Runnable command, final java.lang.Runnable actionInFinal) {
        return execute(new FutureTask<>(() -> {
            try {
                command.run();
                return null;
            } finally {
                actionInFinal.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 (Throwables.Runnable command : commands) {
            results.add(execute(command));
        }

        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 actioInFinal
     * @return
     */
    public  ContinuableFuture execute(final Callable command, final java.lang.Runnable actioInFinal) {
        return execute(new FutureTask<>(() -> {
            try {
                return command.call();
            } finally {
                actioInFinal.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 (Callable command : commands) {
            results.add(execute(command));
        }

        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 retryIntervallInMillis
     * @param retryCondition
     * @return
     */
    public ContinuableFuture execute(final Throwables.Runnable action, final int retryTimes, final long retryIntervallInMillis,
            final Predicate retryCondition) {
        return execute((Callable) () -> {
            Retry.of(retryTimes, retryIntervallInMillis, retryCondition).run(action);
            return null;
        });
    }

    /**
     *
     * @param 
     * @param action
     * @param retryTimes
     * @param retryIntervallInMillis
     * @param retryCondition
     * @return
     */
    public  ContinuableFuture execute(final Callable action, final int retryTimes, final long retryIntervallInMillis,
            final BiPredicate retryCondition) {
        return execute((Callable) () -> {
            final Retry retry = Retry.of(retryTimes, retryIntervallInMillis, retryCondition);
            return retry.call(action);
        });
    }

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

        executor.execute(futureTask);

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

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

                    executor = threadPoolExecutor;

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

        return executor;
    }

    /**
     * 
     */
    public synchronized void shutdown() {
        shutdown(0, TimeUnit.SECONDS);
    }

    /**
     * 
     *
     * @param terminationTimeout 
     * @param timeUnit 
     */
    public synchronized void shutdown(final long terminationTimeout, final TimeUnit timeUnit) {
        if (executor == null || !(executor instanceof ExecutorService executorService)) {
            return;
        }

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

        try {
            executorService.shutdown();

            if (terminationTimeout > 0 && !executorService.isTerminated()) {
                executorService.awaitTermination(terminationTimeout, timeUnit);
            }
        } 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");
        }
    }

    /**
     * 
     *
     * @return 
     */
    @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) + "}";
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy