2121import java .util .concurrent .ScheduledFuture ;
2222import java .util .concurrent .ScheduledThreadPoolExecutor ;
2323import java .util .concurrent .TimeUnit ;
24+ import java .util .function .Supplier ;
2425
2526import org .apache .commons .lang3 .Validate ;
2627
111112 */
112113public class TimedSemaphore {
113114
115+ /**
116+ * Builds new {@link TimedSemaphore}.
117+ *
118+ * @since 3.20.0
119+ */
120+ public static class Builder implements Supplier <TimedSemaphore > {
121+
122+ private ScheduledExecutorService service ;
123+ private long period ;
124+ private TimeUnit timeUnit ;
125+ private int limit ;
126+
127+ /**
128+ * Constructs a new Builder.
129+ */
130+ public Builder () {
131+ // empty
132+ }
133+
134+ @ Override
135+ public TimedSemaphore get () {
136+ return new TimedSemaphore (this );
137+ }
138+
139+ /**
140+ * Sets the limit.
141+ *
142+ * @param limit The limit.
143+ * @return {@code this} instance.
144+ */
145+ public Builder setLimit (final int limit ) {
146+ this .limit = limit ;
147+ return this ;
148+ }
149+
150+ /**
151+ * Sets the time period.
152+ *
153+ * @param period The time period.
154+ * @return {@code this} instance.
155+ */
156+ public Builder setPeriod (final long period ) {
157+ this .period = period ;
158+ return this ;
159+ }
160+
161+ /**
162+ * Sets the executor service.
163+ *
164+ * @param service The executor service.
165+ * @return {@code this} instance.
166+ */
167+ public Builder setService (final ScheduledExecutorService service ) {
168+ this .service = service ;
169+ return this ;
170+ }
171+
172+ /**
173+ * Sets the time unit for the period.
174+ *
175+ * @param timeUnit The time unit for the period.
176+ * @return {@code this} instance.
177+ */
178+ public Builder setTimeUnit (final TimeUnit timeUnit ) {
179+ this .timeUnit = timeUnit ;
180+ return this ;
181+ }
182+ }
183+
114184 /**
115185 * Constant for a value representing no limit. If the limit is set to a value less or equal this constant, the {@link TimedSemaphore} will be effectively
116186 * switched off.
@@ -120,10 +190,20 @@ public class TimedSemaphore {
120190 /** Constant for the thread pool size for the executor. */
121191 private static final int THREAD_POOL_SIZE = 1 ;
122192
193+ /**
194+ * Constructs a new Builder.
195+ *
196+ * @return a new Builder.
197+ * @since 3.20.0
198+ */
199+ public static Builder builder () {
200+ return new Builder ();
201+ }
202+
123203 /** The executor service for managing the timer thread. */
124204 private final ScheduledExecutorService executorService ;
125205
126- /** Stores the period for this timed semaphore. */
206+ /** The period for this timed semaphore. */
127207 private final long period ;
128208
129209 /** The time unit for the period. */
@@ -155,6 +235,23 @@ public class TimedSemaphore {
155235 /** A flag whether shutdown() was called. */
156236 private boolean shutdown ; // @GuardedBy("this")
157237
238+ private TimedSemaphore (final Builder builder ) {
239+ Validate .inclusiveBetween (1 , Long .MAX_VALUE , builder .period , "Time period must be greater than 0." );
240+ period = builder .period ;
241+ unit = builder .timeUnit ;
242+ if (builder .service != null ) {
243+ executorService = builder .service ;
244+ ownExecutor = false ;
245+ } else {
246+ final ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor (THREAD_POOL_SIZE );
247+ stpe .setContinueExistingPeriodicTasksAfterShutdownPolicy (false );
248+ stpe .setExecuteExistingDelayedTasksAfterShutdownPolicy (false );
249+ executorService = stpe ;
250+ ownExecutor = true ;
251+ }
252+ setLimit (builder .limit );
253+ }
254+
158255 /**
159256 * Constructs a new instance of {@link TimedSemaphore} and initializes it with the given time period and the limit.
160257 *
@@ -178,20 +275,7 @@ public TimedSemaphore(final long timePeriod, final TimeUnit timeUnit, final int
178275 * @throws IllegalArgumentException if the period is less or equals 0.
179276 */
180277 public TimedSemaphore (final ScheduledExecutorService service , final long timePeriod , final TimeUnit timeUnit , final int limit ) {
181- Validate .inclusiveBetween (1 , Long .MAX_VALUE , timePeriod , "Time period must be greater than 0!" );
182- period = timePeriod ;
183- unit = timeUnit ;
184- if (service != null ) {
185- executorService = service ;
186- ownExecutor = false ;
187- } else {
188- final ScheduledThreadPoolExecutor s = new ScheduledThreadPoolExecutor (THREAD_POOL_SIZE );
189- s .setContinueExistingPeriodicTasksAfterShutdownPolicy (false );
190- s .setExecuteExistingDelayedTasksAfterShutdownPolicy (false );
191- executorService = s ;
192- ownExecutor = true ;
193- }
194- setLimit (limit );
278+ this (builder ().setService (service ).setPeriod (timePeriod ).setTimeUnit (timeUnit ).setLimit (limit ));
195279 }
196280
197281 /**
0 commit comments