33import java .util .Deque ;
44import java .util .concurrent .ConcurrentLinkedDeque ;
55import java .util .concurrent .atomic .AtomicReference ;
6+ import java .util .concurrent .atomic .LongAdder ;
67import java .util .function .Consumer ;
78import java .util .function .Function ;
8-
9+ import java .util .function .Supplier ;
10+
11+ /**
12+ * This is a utility class, whose main functionality is pooling object
13+ * with a huge memory footprint and that are costly to be recreated at
14+ * every usage like the {@link BufferRecycler}. It is intended for
15+ * internal use only.
16+ *
17+ * @since 2.16
18+ */
919public interface ObjectPool <T > extends AutoCloseable {
1020
1121 T acquire ();
@@ -21,7 +31,22 @@ default void withPooledObject(Consumer<T> objectConsumer) {
2131 }
2232
2333 enum Strategy {
24- CONCURRENT_DEQUEUE , LOCK_FREE
34+ CONCURRENT_DEQUEUE (ConcurrentDequePool ::new , false ), LOCK_FREE (LockFreePool ::new , false ),
35+ DEBUG_CONCURRENT_DEQUEUE (ConcurrentDequePool ::new , true ), DEBUG_LOCK_FREE (LockFreePool ::new , true );
36+
37+ private final Function <Supplier , ObjectPool > constructor ;
38+
39+ private final boolean debug ;
40+
41+ Strategy (Function <Supplier , ObjectPool > constructor , boolean debug ) {
42+ this .constructor = constructor ;
43+ this .debug = debug ;
44+ }
45+
46+ <T > ObjectPool <T > newObjectPool (Supplier <T > factory ) {
47+ ObjectPool <T > pool = constructor .apply (factory );
48+ return debug ? new DebugPoolDecorator <>(pool ) : pool ;
49+ }
2550 }
2651
2752 class StrategyHolder {
@@ -32,33 +57,29 @@ public static void setStrategy(String name) {
3257 }
3358 }
3459
35- static <T > ObjectPool <T > newObjectPool (Function <ObjectPool <T >, T > factory ) {
36- switch (StrategyHolder .strategy ) {
37- case CONCURRENT_DEQUEUE : return new ConcurrentDequePool <>(factory );
38- case LOCK_FREE : return new LockFreePool <>(factory );
39- }
40- throw new UnsupportedOperationException ();
60+ static <T > ObjectPool <T > newObjectPool (Supplier <T > factory ) {
61+ return StrategyHolder .strategy .newObjectPool (factory );
4162 }
4263
4364 class ConcurrentDequePool <T > implements ObjectPool <T > {
44- private final Function < ObjectPool < T >, T > factory ;
65+ private final Supplier < T > factory ;
4566 private final Consumer <T > destroyer ;
4667
4768 private final Deque <T > pool = new ConcurrentLinkedDeque <>();
4869
49- public ConcurrentDequePool (Function < ObjectPool < T >, T > factory ) {
70+ public ConcurrentDequePool (Supplier < T > factory ) {
5071 this (factory , null );
5172 }
5273
53- public ConcurrentDequePool (Function < ObjectPool < T >, T > factory , Consumer <T > destroyer ) {
74+ public ConcurrentDequePool (Supplier < T > factory , Consumer <T > destroyer ) {
5475 this .factory = factory ;
5576 this .destroyer = destroyer ;
5677 }
5778
5879 @ Override
5980 public T acquire () {
6081 T t = pool .pollFirst ();
61- return t != null ? t : factory .apply ( this );
82+ return t != null ? t : factory .get ( );
6283 }
6384
6485 @ Override
@@ -77,9 +98,9 @@ public void close() throws Exception {
7798 class LockFreePool <T > implements ObjectPool <T > {
7899 private final AtomicReference <Node <T >> head = new AtomicReference <>();
79100
80- private final Function < ObjectPool < T >, T > factory ;
101+ private final Supplier < T > factory ;
81102
82- public LockFreePool (Function < ObjectPool < T >, T > factory ) {
103+ public LockFreePool (Supplier < T > factory ) {
83104 this .factory = factory ;
84105 }
85106
@@ -88,14 +109,14 @@ public T acquire() {
88109 for (int i = 0 ; i < 3 ; i ++) {
89110 Node <T > currentHead = head .get ();
90111 if (currentHead == null ) {
91- return factory .apply ( this );
112+ return factory .get ( );
92113 }
93114 if (head .compareAndSet (currentHead , currentHead .next )) {
94115 currentHead .next = null ;
95116 return currentHead .value ;
96117 }
97118 }
98- return factory .apply ( this );
119+ return factory .get ( );
99120 }
100121
101122 @ Override
@@ -123,4 +144,42 @@ static class Node<T> {
123144 }
124145 }
125146 }
147+
148+ class DebugPoolDecorator <T > implements ObjectPool <T > {
149+
150+ private final ObjectPool <T > pool ;
151+
152+ private final LongAdder acquireCounter = new LongAdder ();
153+ private final LongAdder releaseCounter = new LongAdder ();
154+
155+ public DebugPoolDecorator (ObjectPool <T > pool ) {
156+ this .pool = pool ;
157+ }
158+
159+ @ Override
160+ public T acquire () {
161+ acquireCounter .increment ();
162+ return pool .acquire ();
163+ }
164+
165+ @ Override
166+ public void release (T t ) {
167+ releaseCounter .increment ();
168+ pool .release (t );
169+ }
170+
171+ @ Override
172+ public void close () throws Exception {
173+ System .out .println ("Closing " + this );
174+ pool .close ();
175+ }
176+
177+ @ Override
178+ public String toString () {
179+ return "DebugPoolDecorator{" +
180+ "acquires = " + acquireCounter .sum () +
181+ ", releases = " + releaseCounter .sum () +
182+ '}' ;
183+ }
184+ }
126185}
0 commit comments