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

com.swirlds.base.internal.impl.BaseScheduledExecutorService Maven / Gradle / Ivy

Go to download

Swirlds is a software platform designed to build fully-distributed applications that harness the power of the cloud without servers. Now you can develop applications with fairness in decision making, speed, trust and reliability, at a fraction of the cost of traditional server-based platforms.

There is a newer version: 0.54.0
Show newest version
/*
 * Copyright (C) 2024 Hedera Hashgraph, LLC
 *
 * 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.swirlds.base.internal.impl;

import com.swirlds.base.internal.observe.BaseExecutorObserver;
import com.swirlds.base.internal.observe.BaseTaskDefinition;
import edu.umd.cs.findbugs.annotations.NonNull;
import java.time.Duration;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A scheduled executor service for the base modules. The executor is based on a single thread and is a daemon thread
 * with a low priority.
 * 

* This class is a singleton and should only be used by code in the base modules that highly needs an asynchronous * executor. */ public class BaseScheduledExecutorService implements ScheduledExecutorService { /** * The number of threads in the pool. */ public static final int CORE_POOL_SIZE = 1; private static final class InstanceHolder { private static final BaseScheduledExecutorService INSTANCE = new BaseScheduledExecutorService(); } /** * The lock for creating the singleton instance. */ private static final Lock instanceLock = new ReentrantLock(); /** * The inner executor service. */ private final ScheduledExecutorService innerService; /* * The observers of this executor. */ private final List observers; /** * Constructs a new executor. */ private BaseScheduledExecutorService() { final ThreadFactory threadFactory = new BaseExecutorThreadFactory(); this.innerService = Executors.newScheduledThreadPool(CORE_POOL_SIZE, threadFactory); this.observers = new CopyOnWriteArrayList<>(); final Thread shutdownHook = new Thread(() -> innerService.shutdown()); shutdownHook.setName("BaseScheduledExecutorService-shutdownHook"); Runtime.getRuntime().addShutdownHook(shutdownHook); } /** * Adds an observer to this executor. * * @param observer the observer to add */ public void addObserver(@NonNull final BaseExecutorObserver observer) { Objects.requireNonNull(observer, "observer must not be null"); observers.add(observer); } /** * Removes an observer from this executor. * @param observer the observer to remove */ public void removeObserver(@NonNull final BaseExecutorObserver observer) { Objects.requireNonNull(observer, "observer must not be null"); observers.add(observer); } /** * Wraps the given command with the observer calls. * @param command the command to wrap * @return the wrapped command */ @NonNull private Runnable wrapOnSubmit(@NonNull final Runnable command) { Objects.requireNonNull(command, "command must not be null"); final BaseTaskDefinition taskDefinition = BaseTaskDefinition.of(command); observers.forEach(observer -> observer.onTaskSubmitted(taskDefinition)); return () -> { final long start = System.currentTimeMillis(); observers.forEach(observer -> observer.onTaskStarted(taskDefinition)); try { command.run(); observers.forEach(observer -> observer.onTaskDone(taskDefinition, Duration.ofMillis(System.currentTimeMillis() - start))); } catch (Throwable t) { observers.forEach(observer -> observer.onTaskFailed(taskDefinition, Duration.ofMillis(System.currentTimeMillis() - start))); throw t; } }; } /** * Wraps the given callable with the observer calls. * @param callable the callable to wrap * @return the wrapped callable * @param the type of the callable's result */ @NonNull private Callable wrapOnSubmit(@NonNull final Callable callable) { Objects.requireNonNull(callable, "callable must not be null"); final BaseTaskDefinition taskDefinition = BaseTaskDefinition.of(callable); observers.forEach(observer -> observer.onTaskSubmitted(taskDefinition)); return () -> { final long start = System.currentTimeMillis(); observers.forEach(observer -> observer.onTaskStarted(taskDefinition)); try { final V result = callable.call(); observers.forEach(observer -> observer.onTaskDone(taskDefinition, Duration.ofMillis(System.currentTimeMillis() - start))); return result; } catch (Throwable t) { observers.forEach(observer -> observer.onTaskFailed(taskDefinition, Duration.ofMillis(System.currentTimeMillis() - start))); throw t; } }; } @Override public ScheduledFuture schedule( @NonNull final Runnable command, final long delay, @NonNull final TimeUnit unit) { final Runnable wrapped = wrapOnSubmit(command); return innerService.schedule(wrapped, delay, unit); } @Override public ScheduledFuture schedule( @NonNull final Callable callable, final long delay, @NonNull final TimeUnit unit) { final Callable wrapped = wrapOnSubmit(callable); return innerService.schedule(wrapped, delay, unit); } @Override public ScheduledFuture scheduleAtFixedRate( @NonNull final Runnable command, final long initialDelay, final long period, @NonNull final TimeUnit unit) { final Runnable wrapped = wrapOnSubmit(command); return innerService.scheduleAtFixedRate(wrapped, initialDelay, period, unit); } @Override public ScheduledFuture scheduleWithFixedDelay( @NonNull final Runnable command, final long initialDelay, final long delay, @NonNull final TimeUnit unit) { final Runnable wrapped = wrapOnSubmit(command); return innerService.scheduleWithFixedDelay(wrapped, initialDelay, delay, unit); } @Override public void shutdown() { throw new IllegalStateException("This executor is managed by the base modules and should not be shut down"); } @Override public List shutdownNow() { throw new IllegalStateException("This executor is managed by the base modules and should not be shut down"); } @Override public boolean isShutdown() { return innerService.isShutdown(); } @Override public boolean isTerminated() { return innerService.isTerminated(); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return innerService.awaitTermination(timeout, unit); } @Override public Future submit(Callable task) { final Callable wrapped = wrapOnSubmit(task); return innerService.submit(wrapped); } @Override public Future submit(Runnable task, T result) { final Runnable wrapped = wrapOnSubmit(task); return innerService.submit(wrapped, result); } @Override public Future submit(Runnable task) { final Runnable wrapped = wrapOnSubmit(task); return innerService.submit(wrapped); } @Override public List> invokeAll(Collection> tasks) throws InterruptedException { Collection> wrapped = tasks.stream().map(this::wrapOnSubmit).toList(); return innerService.invokeAll(wrapped); } @Override public List> invokeAll(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException { Collection> wrapped = tasks.stream().map(this::wrapOnSubmit).toList(); return innerService.invokeAll(wrapped, timeout, unit); } @Override public T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException { Collection> wrapped = tasks.stream().map(this::wrapOnSubmit).toList(); return innerService.invokeAny(wrapped); } @Override public T invokeAny(Collection> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { Collection> wrapped = tasks.stream().map(this::wrapOnSubmit).toList(); return innerService.invokeAny(wrapped, timeout, unit); } @Override public void execute(Runnable command) { final Runnable wrapped = wrapOnSubmit(command); innerService.execute(wrapped); } /** * Returns the singleton instance of this executor. * * @return the instance */ @NonNull public static BaseScheduledExecutorService getInstance() { return InstanceHolder.INSTANCE; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy