1 /*
2 * Copyright 2012 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty5.util.concurrent;
17
18 import java.util.Iterator;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.Executor;
21 import java.util.concurrent.TimeUnit;
22
23 import static io.netty5.util.concurrent.AbstractEventExecutor.DEFAULT_SHUTDOWN_QUIET_PERIOD;
24 import static io.netty5.util.concurrent.AbstractEventExecutor.DEFAULT_SHUTDOWN_TIMEOUT;
25
26 /**
27 * The {@link EventExecutorGroup} is responsible for providing the {@link EventExecutor}'s to use
28 * via its {@link #next()} method. Besides this, it is also responsible for handling their
29 * life-cycle and allows shutting them down in a global fashion.
30 *
31 */
32 public interface EventExecutorGroup extends Iterable<EventExecutor>, Executor {
33 /**
34 * Returns {@code true} if and only if all {@link EventExecutor}s managed by this {@link EventExecutorGroup}
35 * are being {@linkplain #shutdownGracefully() shut down gracefully} or was {@linkplain #isShutdown() shut down}.
36 * <p>
37 * An executor group that "is shutting down" can still accept new tasks for a little while (the grace period),
38 * but will eventually start rejecting new tasks.
39 * At that point, the executor group will be {@linkplain #isShutdown() shut down}.
40 *
41 * @return {@code true} if all executors in this group have at least started shutting down, otherwise {@code false}.
42 */
43 boolean isShuttingDown();
44
45 /**
46 * Returns {@code true} if all {@link EventExecutor}s managed by this {@link EventExecutorGroup} have been
47 * {@linkplain #shutdownGracefully() shut down gracefully} and moved past the grace period so that they are no
48 * longer accepting any new tasks.
49 * <p>
50 * An executor group that "is shut down" might still be executing tasks that it has queued up, but it will no
51 * longer be accepting any new tasks.
52 * Once all running and queued tasks have completed, the executor group will be
53 * {@linkplain #isTerminated() terminated}.
54 *
55 * @return {@code true} if all executors in this group have shut down and are no longer accepting any new tasks.
56 */
57 boolean isShutdown();
58
59 /**
60 * Returns {@code true} if all {@link EventExecutor}s managed by this {@link EventExecutorGroup} are
61 * {@linkplain #isShutdown() shut down}, and all of their tasks have completed.
62 *
63 * @return {@code true} if all executors in this group have terminated.
64 */
65 default boolean isTerminated() {
66 return terminationFuture().isDone();
67 }
68
69 /**
70 * Wait for this {@link EventExecutorGroup} to {@linkplain #isTerminated() terminate}, up to the given timeout.
71 *
72 * @param timeout The non-negative maximum amount of time to wait for the executor group to terminate.
73 * @param unit The non-null time unit of the timeout.
74 * @return {@code true} if the executor group terminated within the specific timeout.
75 * @throws InterruptedException If this thread was {@linkplain Thread#interrupt() interrupted} while waiting for
76 * executor group to terminate.
77 */
78 default boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
79 return terminationFuture().asStage().await(timeout, unit);
80 }
81
82 /**
83 * Shortcut method for {@link #shutdownGracefully(long, long, TimeUnit)} with sensible default values.
84 *
85 * @return the {@link #terminationFuture()}
86 */
87 default Future<Void> shutdownGracefully() {
88 return shutdownGracefully(DEFAULT_SHUTDOWN_QUIET_PERIOD, DEFAULT_SHUTDOWN_TIMEOUT, TimeUnit.SECONDS);
89 }
90
91 /**
92 * Signals this executor that the caller wants the executor to be shut down. Once this method is called,
93 * {@link #isShuttingDown()} starts to return {@code true}, and the executor prepares to shut itself down.
94 * This method ensures that no tasks are submitted for <i>'the quiet period'</i> (usually a couple seconds) before
95 * it shuts itself down. If a task is submitted during the quiet period, it is guaranteed to be accepted and the
96 * quiet period will start over.
97 *
98 * @param quietPeriod the quiet period as described in the documentation
99 * @param timeout the maximum amount of time to wait until the executor is
100 * {@linkplain #isShuttingDown() shutting down} regardless if a task was submitted during the quiet period.
101 * @param unit the unit of {@code quietPeriod} and {@code timeout}
102 *
103 * @return the {@link #terminationFuture()}
104 */
105 Future<Void> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit);
106
107 /**
108 * Returns the {@link Future} which is notified when all {@link EventExecutor}s managed by this
109 * {@link EventExecutorGroup} have been terminated.
110 *
111 * @return The {@link Future} representing the termination of this {@link EventExecutorGroup}.
112 */
113 Future<Void> terminationFuture();
114
115 /**
116 * Returns one of the {@link EventExecutor}s managed by this {@link EventExecutorGroup}.
117 */
118 EventExecutor next();
119
120 @Override
121 Iterator<EventExecutor> iterator();
122
123 /**
124 * Submit the given task for execution in the next available {@link EventExecutor} in this group,
125 * and return a future that produces a {@code null} result when the task completes.
126 *
127 * @param task The task that should be executed in this {@link EventExecutorGroup}.
128 * @return A future that represents the completion of the submitted task.
129 */
130 default Future<Void> submit(Runnable task) {
131 return next().submit(task);
132 }
133
134 /**
135 * Submit the given task for execution in the next available {@link EventExecutor} in this group,
136 * and return a future that produces the given result when the task completes.
137 *
138 * @param task The task that should be executed in this {@link EventExecutorGroup}.
139 * @param result The value that the returned future will complete with, if the task completes successfully.
140 * @param <T> The type of the future result.
141 * @return A future that represents the completion of the submitted task.
142 */
143 default <T> Future<T> submit(Runnable task, T result) {
144 return next().submit(task, result);
145 }
146
147 /**
148 * Submit the given task for execution in the next available {@link EventExecutor} in this group,
149 * and return a future that will return the result of the callable when the task completes.
150 *
151 * @param task The task that should be executed in this {@link EventExecutorGroup}.
152 * @param <T> The type of the future result.
153 * @return A future that represents the completion of the submitted task.
154 */
155 default <T> Future<T> submit(Callable<T> task) {
156 return next().submit(task);
157 }
158
159 /**
160 * Schedule the given task for execution after the given delay, in the next available {@link EventExecutor}
161 * in this group, and return a future that produces a {@code null} result when the task completes.
162 *
163 * @param task The task that should be executed in this {@link EventExecutorGroup} after the given delay.
164 * @param delay A positive time delay, in the given time unit.
165 * @param unit The non-null time unit for the delay.
166 * @return A future that represents the completion of the scheduled task.
167 */
168 default Future<Void> schedule(Runnable task, long delay, TimeUnit unit) {
169 return next().schedule(task, delay, unit);
170 }
171
172 /**
173 * Schedule the given task for execution after the given delay, in the next available {@link EventExecutor}
174 * in this group, and return a future that will return the result of the callable when the task completes.
175 *
176 * @param task The task that should be executed in this {@link EventExecutorGroup} after the given delay.
177 * @param delay A positive time delay, in the given time unit.
178 * @param unit The non-null time unit for the delay.
179 * @param <V> The type of the future result.
180 * @return A future that represents the completion of the scheduled task.
181 */
182 default <V> Future<V> schedule(Callable<V> task, long delay, TimeUnit unit) {
183 return next().schedule(task, delay, unit);
184 }
185
186 /**
187 * Schedule the given task for periodic execution in the next available {@link EventExecutor}.
188 * The first execution will occur after the given initial delay, and the following repeated executions will occur
189 * with the given period of time between each execution is started.
190 * If the task takes longer to complete than the requested period, then the following executions will be delayed,
191 * rather than allowing multiple instances of the task to run concurrently.
192 * <p>
193 * The task will be executed repeatedly until it either fails with an exception, or its future is
194 * {@linkplain Future#cancel() cancelled}. The future thus will never complete successfully.
195 *
196 * @param task The task that should be scheduled to execute at a fixed rate in this {@link EventExecutorGroup}.
197 * @param initialDelay The positive initial delay for the first task execution, in terms of the given time unit.
198 * @param period The positive period for the execution frequency to use after the first execution has started,
199 * in terms of the given time unit.
200 * @param unit The non-null time unit for the delay and period.
201 * @return A future that represents the recurring task, and which can be cancelled to stop future executions.
202 */
203 default Future<Void> scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit unit) {
204 return next().scheduleAtFixedRate(task, initialDelay, period, unit);
205 }
206
207 /**
208 * Schedule the given task for periodic execution in the next available {@link EventExecutor}.
209 * The first execution will occur after the given initial delay, and the following repeated executions will occur
210 * with the given subsequent delay between one task completing and the next task starting.
211 * The delay from the completion of one task, to the start of the next, stays unchanged regardless of how long a
212 * task takes to complete.
213 * <p>
214 * This is in contrast to {@link #scheduleAtFixedRate(Runnable, long, long, TimeUnit)} which varies the delays
215 * between the tasks in order to hit a given frequency.
216 * <p>
217 * The task will be executed repeatedly until it either fails with an exception, or its future is
218 * {@linkplain Future#cancel() cancelled}. The future thus will never complete successfully.
219 *
220 * @param task The task that should be scheduled to execute with fixed delays in this {@link EventExecutorGroup}.
221 * @param initialDelay The positive initial delay for the first task execution, in terms of the given time unit.
222 * @param delay The positive subsequent delay between task, to use after the first execution has completed,
223 * in terms of the given time unit.
224 * @param unit The non-null time unit for the delays.
225 * @return A future that represents the recurring task, and which can be cancelled to stop future executions.
226 */
227 default Future<Void> scheduleWithFixedDelay(Runnable task, long initialDelay, long delay, TimeUnit unit) {
228 return next().scheduleWithFixedDelay(task, initialDelay, delay, unit);
229 }
230
231 @Override
232 default void execute(Runnable task) {
233 next().execute(task);
234 }
235 }