@@ -143,9 +143,6 @@ public void run() {
143143
144144 private boolean safeRunTask (Runnable r ) {
145145 try {
146- if (maxQueueCapacity > 0 ) {
147- waiterCountUpdater .decrementAndGet (this );
148- }
149146 r .run ();
150147 tasksCompleted .increment ();
151148 } catch (Throwable t ) {
@@ -156,6 +153,8 @@ private boolean safeRunTask(Runnable r) {
156153 tasksFailed .increment ();
157154 log .error ("Error while running task: {}" , t .getMessage (), t );
158155 }
156+ } finally {
157+ releaseQueuePermits (1 );
159158 }
160159
161160 return true ;
@@ -219,25 +218,44 @@ public long getFailedTasksCount() {
219218
220219 @ Override
221220 public void execute (Runnable r ) {
222- execute (r , null );
221+ executeRunnableOrList (r , null );
223222 }
224223
225224 @ VisibleForTesting
226- void execute (Runnable r , List <Runnable > runnableList ) {
225+ void executeRunnableOrList (Runnable runnable , List <Runnable > runnableList ) {
227226 if (state != State .Running ) {
228227 throw new RejectedExecutionException ("Executor is shutting down" );
229228 }
230229
230+ boolean hasSingle = runnable != null ;
231+ boolean hasList = runnableList != null && !runnableList .isEmpty ();
232+
233+ if (hasSingle == hasList ) {
234+ // Both are provided or both are missing
235+ throw new IllegalArgumentException ("Provide either 'runnable' or a non-empty 'runnableList', not both." );
236+ }
237+
231238 try {
232239 if (!rejectExecution ) {
233- queue .put (r );
234- tasksCount .increment ();
240+ if (hasSingle ) {
241+ queue .put (runnable );
242+ tasksCount .increment ();
243+ } else {
244+ for (Runnable task : runnableList ) {
245+ queue .put (task );
246+ tasksCount .increment ();
247+ }
248+ }
235249 } else {
236- int delta = r != null ? 1 : runnableList .size ();
237- validateQueueCapacity (delta );
238- if (r != null ? queue .offer (r ) : queue .addAll (runnableList )) {
239- tasksCount .add (delta );
250+ int permits = runnable != null ? 1 : runnableList .size ();
251+ reserveQueuePermits (permits );
252+ boolean success = hasSingle
253+ ? queue .offer (runnable )
254+ : queue .addAll (runnableList );
255+ if (success ) {
256+ tasksCount .add (permits );
240257 } else {
258+ releaseQueuePermits (permits );
241259 reject ();
242260 }
243261 }
@@ -246,12 +264,36 @@ void execute(Runnable r, List<Runnable> runnableList) {
246264 }
247265 }
248266
249- private void validateQueueCapacity (int delta ) {
250- if (maxQueueCapacity > 0 && waiterCountUpdater .addAndGet (this , delta ) > maxQueueCapacity ) {
267+ private void reserveQueuePermits (int permits ) {
268+ if (maxQueueCapacity <= 0 ) {
269+ return ; // // Unlimited capacity, nothing to release
270+ }
271+
272+ if (permits < 0 ) {
273+ throw new IllegalArgumentException ("Number of permits must be non-negative" );
274+ }
275+
276+ if (waiterCountUpdater .addAndGet (this , permits ) > maxQueueCapacity ) {
277+ releaseQueuePermits (permits );
251278 reject ();
252279 }
253280 }
254281
282+ private void releaseQueuePermits (int permits ) {
283+ if (maxQueueCapacity <= 0 ) {
284+ return ; // // Unlimited capacity, nothing to release
285+ }
286+
287+ if (permits < 0 ) {
288+ throw new IllegalArgumentException ("Number of permits must be non-negative" );
289+ }
290+
291+ int waiterCount = waiterCountUpdater .addAndGet (this , -permits );
292+ if (log .isDebugEnabled ()) {
293+ log .debug ("Released {} permits, current waiter count: {}" , permits , waiterCount );
294+ }
295+ }
296+
255297 private void reject () {
256298 tasksRejected .increment ();
257299 throw new ExecutorRejectedException ("Executor queue is full" );
@@ -321,6 +363,11 @@ public Number getSample() {
321363 });
322364 }
323365
366+ @ VisibleForTesting
367+ int getWaiterCount () {
368+ return waiterCountUpdater .get (this );
369+ }
370+
324371 private static class ExecutorRejectedException extends RejectedExecutionException {
325372
326373 private ExecutorRejectedException (String msg ) {
0 commit comments