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

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

There is a newer version: 1.10.1
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.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

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

/**
 * 
 * @since 0.8
 * 
 * @author Haiyang Li
 */
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 static final ScheduledExecutorService SCHEDULED_EXECUTOR;
    static {
        final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(64);
        executor.setKeepAliveTime(180, TimeUnit.SECONDS);
        executor.allowCoreThreadTimeOut(true);
        executor.setRemoveOnCancelPolicy(true);
        SCHEDULED_EXECUTOR = MoreExecutors.getExitingScheduledExecutorService(executor);
    }

    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, 300, TimeUnit.SECONDS);
    }

    public AsyncExecutor(int maxThreadPoolSize, long keepAliveTime, TimeUnit unit) {
        this(DEFAULT_CORE_POOL_SIZE, maxThreadPoolSize, keepAliveTime, 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 = maxThreadPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.unit = unit;

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                if (executor == null || !(executor instanceof ExecutorService)) {
                    return;
                }

                final ExecutorService executorService = (ExecutorService) executor;
                logger.warn("Starting to shutdown task in AsyncExecutor");

                try {
                    executorService.shutdown();

                    while (executorService.isTerminated() == false) {
                        N.sleepUninterruptibly(100);
                    }
                } finally {
                    logger.warn("Completed to shutdown task in AsyncExecutor");
                }
            }
        });
    }

    /**
     * 
     * @param asyncExecutor
     */
    public AsyncExecutor(final Executor executor) {
        this(DEFAULT_CORE_POOL_SIZE, DEFAULT_MAX_THREAD_POOL_SIZE, 300, TimeUnit.SECONDS);

        this.executor = executor;
    }

    public ContinuableFuture execute(final Try.Runnable command) {
        return execute(new FutureTask(FN.toCallable(command)));
    }

    public ContinuableFuture execute(final Try.Runnable action, final long delay) {
        return execute(action, delay, TimeUnit.MILLISECONDS);
    }

    public ContinuableFuture execute(final Try.Runnable action, final long delay, final TimeUnit timeUnit) {
        final Executor executor = getExecutor();

        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return execute(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delay, timeUnit);

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

    @SafeVarargs
    public final List> execute(final Try.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;
    }

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

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

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

        return results;
    }

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

    public  ContinuableFuture execute(final Callable action, final long delay) {
        return execute(action, delay, TimeUnit.MILLISECONDS);
    }

    public  ContinuableFuture execute(final Callable action, final long delay, final TimeUnit timeUnit) {
        final Executor executor = getExecutor();

        final Callable> scheduledAction = new Callable>() {
            @Override
            public ContinuableFuture call() throws Exception {
                return execute(action);
            }
        };

        final ScheduledFuture> scheduledFuture = SCHEDULED_EXECUTOR.schedule(scheduledAction, delay, timeUnit);

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

    @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;
    }

    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;
    }

    public ContinuableFuture execute(final Try.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;
            }
        });
    }

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

    private  ContinuableFuture execute(final FutureTask futureTask) {
        final Executor executor = getExecutor();

        executor.execute(futureTask);

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

    private static  Future wrap(final ScheduledFuture> scheduledFuture) {
        return new Future() {
            @Override
            public boolean cancel(boolean mayInterruptIfRunning) {
                if (scheduledFuture.cancel(mayInterruptIfRunning) && scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.cancel(mayInterruptIfRunning);
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public boolean isCancelled() {
                if (scheduledFuture.isCancelled() && scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.isCancelled();
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public boolean isDone() {
                if (scheduledFuture.isDone()) {
                    try {
                        final ContinuableFuture resFuture = scheduledFuture.get();
                        return resFuture == null || resFuture.isDone();
                    } catch (Exception e) {
                        return false;
                    }
                }

                return false;
            }

            @Override
            public T get() throws InterruptedException, ExecutionException {
                final ContinuableFuture resFuture = scheduledFuture.get();
                return resFuture == null ? null : resFuture.get();
            }

            @Override
            public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
                final long beginTime = System.currentTimeMillis();

                final ContinuableFuture resFuture = scheduledFuture.get(timeout, unit);

                final long remainingTimeout = unit.toMillis(timeout) - (System.currentTimeMillis() - beginTime);

                return resFuture == null ? null : (remainingTimeout > 0 ? resFuture.get(remainingTimeout, TimeUnit.MILLISECONDS) : resFuture.get());
            }
        };
    }

    private 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;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy