1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.pool2;
19
20 import java.time.Duration;
21 import java.time.Instant;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.NoSuchElementException;
25 import java.util.concurrent.Callable;
26 import java.util.concurrent.ExecutionException;
27 import java.util.concurrent.ExecutorService;
28 import java.util.concurrent.Executors;
29 import java.util.concurrent.Future;
30
31 import org.apache.commons.pool2.impl.BaseObjectPoolConfig;
32 import org.apache.commons.pool2.impl.DefaultPooledObject;
33 import org.apache.commons.pool2.impl.GenericKeyedObjectPool;
34 import org.apache.commons.pool2.impl.GenericKeyedObjectPoolConfig;
35
36
37
38
39
40
41
42
43 public final class ObjectPoolIssue326 {
44 private static class ObjectFactory extends BaseKeyedPooledObjectFactory<Integer, Object> {
45 @Override
46 public Object create(final Integer s) {
47 return new TestObject();
48 }
49
50 @Override
51 public PooledObject<Object> wrap(final Object o) {
52 return new DefaultPooledObject<>(o);
53 }
54 }
55
56 private static class Task<E extends Exception> implements Callable<Object> {
57 private final GenericKeyedObjectPool<Integer, Object> m_pool;
58 private final int m_key;
59
60 Task(final GenericKeyedObjectPool<Integer, Object> pool, final int count) {
61 m_pool = pool;
62 m_key = count % 20;
63 }
64
65 private void busyWait(final long timeMillis) {
66
67 final long endTimeMillis = System.currentTimeMillis() + timeMillis;
68 while (System.currentTimeMillis() < endTimeMillis) {
69
70 }
71 }
72
73 @Override
74 public Object call() throws Exception {
75 try {
76 final Object value;
77 value = m_pool.borrowObject(m_key);
78
79
80
81 busyWait(System.currentTimeMillis() % 4);
82 m_pool.returnObject(m_key, value);
83 return "success";
84 } catch (final NoSuchElementException e) {
85
86
87 busyWait(System.currentTimeMillis() % 20);
88 return "exhausted";
89 }
90 }
91 }
92
93 private static class TestObject {
94 }
95
96 public static void main(final String[] args) {
97 try {
98 new ObjectPoolIssue326().run();
99 } catch (final Exception e) {
100 e.printStackTrace();
101 }
102 }
103
104 private <E extends Exception> List<Task<E>> createTasks(final GenericKeyedObjectPool<Integer, Object> pool) {
105 final List<Task<E>> tasks = new ArrayList<>();
106 for (int i = 0; i < 250; i++) {
107 tasks.add(new Task<>(pool, i));
108 }
109 return tasks;
110 }
111
112 private void run() throws InterruptedException, ExecutionException {
113 final GenericKeyedObjectPoolConfig<Object> poolConfig = new GenericKeyedObjectPoolConfig<>();
114 poolConfig.setMaxTotal(10);
115 poolConfig.setMaxTotalPerKey(5);
116 poolConfig.setMinIdlePerKey(-1);
117 poolConfig.setMaxIdlePerKey(-1);
118 poolConfig.setLifo(true);
119 poolConfig.setFairness(true);
120 poolConfig.setMaxWait(Duration.ofSeconds(30));
121 poolConfig.setMinEvictableIdleDuration(Duration.ofMillis(-1));
122 poolConfig.setMinEvictableIdleTime(Duration.ofMillis(-1));
123 poolConfig.setSoftMinEvictableIdleDuration(Duration.ofMillis(-1));
124 poolConfig.setSoftMinEvictableIdleTime(Duration.ofMillis(-1));
125 poolConfig.setNumTestsPerEvictionRun(1);
126 poolConfig.setTestOnCreate(false);
127 poolConfig.setTestOnBorrow(false);
128 poolConfig.setTestOnReturn(false);
129 poolConfig.setTestWhileIdle(false);
130 poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(5));
131 poolConfig.setEvictionPolicyClassName(BaseObjectPoolConfig.DEFAULT_EVICTION_POLICY_CLASS_NAME);
132 poolConfig.setBlockWhenExhausted(false);
133 poolConfig.setJmxEnabled(false);
134 poolConfig.setJmxNameBase(null);
135 poolConfig.setJmxNamePrefix(null);
136
137 final GenericKeyedObjectPool<Integer, Object> pool = new GenericKeyedObjectPool<>(new ObjectFactory(), poolConfig);
138
139
140
141
142 final ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
143 final Instant startTime = Instant.now();
144 long testIter = 0;
145 try {
146 while (true) {
147 testIter++;
148 if (testIter % 1000 == 0) {
149 System.out.println(testIter);
150 }
151 final List<Task<RuntimeException>> tasks = createTasks(pool);
152 final List<Future<Object>> futures = service.invokeAll(tasks);
153 for (final Future<Object> future : futures) {
154 future.get();
155 }
156 }
157 } finally {
158 System.out.println("Time: " + Duration.between(startTime, Instant.now()));
159 service.shutdown();
160 }
161 }
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186