io.pravega.common.concurrent.ExecutorServiceHelpers.java Source code

Java tutorial

Introduction

Here is the source code for io.pravega.common.concurrent.ExecutorServiceHelpers.java

Source

/**
 * Copyright (c) 2017 Dell Inc., or its subsidiaries. All Rights Reserved.
 *
 * 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
 */
package io.pravega.common.concurrent;

import com.google.common.base.Preconditions;
import io.pravega.common.ExceptionHelpers;
import io.pravega.common.function.RunnableWithException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Consumer;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.val;

/**
 * Helper methods for ExecutorService.
 */
public final class ExecutorServiceHelpers {
    /**
     * Gets a snapshot of the given ExecutorService.
     *
     * @param service The ExecutorService to request a snapshot on.
     * @return A Snapshot of the given ExecutorService, or null if not supported.
     */
    public static Snapshot getSnapshot(ExecutorService service) {
        Preconditions.checkNotNull(service, "service");
        if (service instanceof ThreadPoolExecutor) {
            val tpe = (ThreadPoolExecutor) service;
            return new Snapshot(tpe.getQueue().size(), tpe.getActiveCount(), tpe.getPoolSize());
        } else if (service instanceof ForkJoinPool) {
            val fjp = (ForkJoinPool) service;
            return new Snapshot(fjp.getQueuedSubmissionCount(), fjp.getActiveThreadCount(), fjp.getPoolSize());
        } else {
            return null;
        }
    }

    /**
     * Executes the given task on the given Executor.
     *
     * @param task             The RunnableWithException to execute.
     * @param exceptionHandler A Consumer that will be invoked in case the task threw an Exception. This is not invoked if
     *                         the executor could not execute the given task.
     * @param runFinally       A Runnable that is guaranteed to be invoked at the end of this execution. If the executor
     *                         did accept the task, it will be invoked after the task is complete (or ended in failure).
     *                         If the executor did not accept the task, it will be executed when this method returns.
     * @param executor         An Executor to execute the task on.
     */
    public static void execute(RunnableWithException task, Consumer<Throwable> exceptionHandler,
            Runnable runFinally, Executor executor) {
        Preconditions.checkNotNull(task, "task");
        Preconditions.checkNotNull(exceptionHandler, "exceptionHandler");
        Preconditions.checkNotNull(runFinally, "runFinally");

        boolean scheduledSuccess = false;
        try {
            executor.execute(() -> {
                try {
                    task.run();
                } catch (Throwable ex) {
                    if (!ExceptionHelpers.mustRethrow(ex)) {
                        // Invoke the exception handler, but there's no point in rethrowing the exception, as it will simply
                        // be ignored by the executor.
                        exceptionHandler.accept(ex);
                    }
                } finally {
                    runFinally.run();
                }
            });

            scheduledSuccess = true;
        } finally {
            // Invoke the finally callback in case we were not able to successfully schedule the task.
            if (!scheduledSuccess) {
                runFinally.run();
            }
        }
    }

    @AllArgsConstructor(access = AccessLevel.PRIVATE)
    public static class Snapshot {
        @Getter
        final int queueSize;
        @Getter
        final int activeThreadCount;
        @Getter
        final int poolSize;
    }
}