@@ -24,23 +24,74 @@ of this software and associated documentation files (the "Software"), to deal
2424package com .jano7 .executor ;
2525
2626import java .util .concurrent .Executor ;
27+ import java .util .concurrent .RejectedExecutionException ;
28+ import java .util .concurrent .Semaphore ;
2729import java .util .concurrent .TimeUnit ;
2830
31+ import static com .jano7 .executor .BoundedStrategy .BLOCK ;
32+ import static com .jano7 .executor .Util .checkNotNull ;
33+
2934public final class KeySequentialBoundedExecutor implements DrainableExecutor {
3035
31- private final BoundedExecutor boundedExecutor ;
36+ private final int maxTasks ;
37+
38+ private final Semaphore semaphore ;
39+
40+ private final KeySequentialExecutor keySequentialExecutor ;
41+
42+ private final Runnable acquire ;
43+
44+ private boolean drained = false ;
3245
3346 public KeySequentialBoundedExecutor (int maxTasks , BoundedStrategy onTasksExceeded , Executor underlyingExecutor ) {
34- boundedExecutor = new BoundedExecutor (maxTasks , onTasksExceeded , new KeySequentialExecutor (underlyingExecutor ));
47+ this .maxTasks = maxTasks ;
48+ this .semaphore = new Semaphore (maxTasks );
49+ this .keySequentialExecutor = new KeySequentialExecutor (underlyingExecutor );
50+ this .acquire = onTasksExceeded == BLOCK ? this ::blockOnTasksExceeded : this ::rejectOnTasksExceeded ;
51+ }
52+
53+ private void blockOnTasksExceeded () {
54+ semaphore .acquireUninterruptibly ();
55+ }
56+
57+ private void rejectOnTasksExceeded () {
58+ if (!semaphore .tryAcquire ()) {
59+ throw new RejectedExecutionException ("task limit of " + maxTasks + " exceeded" );
60+ }
3561 }
3662
3763 @ Override
3864 public void execute (Runnable task ) {
39- boundedExecutor .execute (task );
65+ checkNotNull (task );
66+ synchronized (this ) {
67+ if (drained ) {
68+ throw new RejectedExecutionException ("executor drained" );
69+ } else {
70+ acquire .run ();
71+ }
72+ }
73+ try {
74+ keySequentialExecutor .execute (new KeyRunnable <>(
75+ task ,
76+ () -> {
77+ try {
78+ task .run ();
79+ } finally {
80+ semaphore .release ();
81+ }
82+ })
83+ );
84+ } catch (RejectedExecutionException e ) {
85+ semaphore .release ();
86+ throw e ;
87+ }
4088 }
4189
4290 @ Override
43- public boolean drain (long timeout , TimeUnit unit ) throws InterruptedException {
44- return boundedExecutor .drain (timeout , unit );
91+ public synchronized boolean drain (long timeout , TimeUnit unit ) throws InterruptedException {
92+ if (!drained && semaphore .tryAcquire (maxTasks , timeout , unit )) {
93+ drained = true ;
94+ }
95+ return drained ;
4596 }
4697}
0 commit comments