View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.eclipse.aether.util.concurrency;
20  
21  import java.util.concurrent.Executor;
22  import java.util.concurrent.ExecutorService;
23  import java.util.concurrent.LinkedBlockingQueue;
24  import java.util.concurrent.ThreadPoolExecutor;
25  import java.util.concurrent.TimeUnit;
26  
27  import org.eclipse.aether.RepositorySystemSession;
28  import org.eclipse.aether.util.ConfigUtils;
29  
30  /**
31   * Utilities for executors and sizing them.
32   *
33   * @since 1.9.5
34   */
35  public final class ExecutorUtils {
36      /**
37       * Shared instance of "direct executor".
38       */
39      public static final Executor DIRECT_EXECUTOR = Runnable::run;
40  
41      /**
42       * Creates new thread pool {@link ExecutorService}. The {@code poolSize} parameter but be greater than 1.
43       */
44      public static ExecutorService threadPool(int poolSize, String namePrefix) {
45          if (poolSize < 2) {
46              throw new IllegalArgumentException("Invalid poolSize: " + poolSize + ". Must be greater than 1.");
47          }
48          return new ThreadPoolExecutor(
49                  poolSize,
50                  poolSize,
51                  3L,
52                  TimeUnit.SECONDS,
53                  new LinkedBlockingQueue<>(),
54                  new WorkerThreadFactory(namePrefix));
55      }
56  
57      /**
58       * Returns {@link #DIRECT_EXECUTOR} or result of {@link #threadPool(int, String)} depending on value of
59       * {@code size} parameter.
60       */
61      public static Executor executor(int size, String namePrefix) {
62          if (size <= 1) {
63              return DIRECT_EXECUTOR;
64          } else {
65              return threadPool(size, namePrefix);
66          }
67      }
68  
69      /**
70       * To be used with result of {@link #executor(int, String)} method, shuts down instance if it is
71       * {@link ExecutorService}.
72       */
73      public static void shutdown(Executor executor) {
74          if (executor instanceof ExecutorService) {
75              ((ExecutorService) executor).shutdown();
76          }
77      }
78  
79      /**
80       * Retrieves and validates requested thread count based on session and specified keys, or if none provided, the
81       * provided default value. This method validates result on top of what {@link ConfigUtils} does.
82       *
83       * @throws IllegalArgumentException if default value is less than 1.
84       * @see ConfigUtils#getInteger(RepositorySystemSession, int, String...)
85       */
86      public static int threadCount(RepositorySystemSession session, int defaultValue, String... keys) {
87          if (defaultValue < 1) {
88              throw new IllegalArgumentException("Invalid defaultValue: " + defaultValue + ". Must be greater than 0.");
89          }
90          int threadCount = ConfigUtils.getInteger(session, defaultValue, keys);
91          if (threadCount < 1) {
92              throw new IllegalArgumentException("Invalid value: " + threadCount + ". Must be greater than 0.");
93          }
94          return threadCount;
95      }
96  }