├── .github
└── FUNDING.yml
├── CHANGELOG
├── LICENSE
├── NOTICE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── vibur
│ └── objectpool
│ ├── BasePool.java
│ ├── ConcurrentPool.java
│ ├── PoolObjectFactory.java
│ ├── PoolService.java
│ └── util
│ ├── ArgumentValidation.java
│ ├── ConcurrentCollection.java
│ ├── ConcurrentLinkedDequeCollection.java
│ ├── ConcurrentLinkedQueueCollection.java
│ ├── ConcurrentStackCollection.java
│ ├── Listener.java
│ ├── MultithreadConcurrentQueueCollection.java
│ ├── SamplingPoolReducer.java
│ ├── TakenListener.java
│ └── ThreadedPoolReducer.java
└── test
└── java
└── org
└── vibur
└── objectpool
├── ConcurrentPoolTest.java
├── ExceptionThrowingObjectFactory.java
├── SimpleObjectFactory.java
├── perf
└── ConcurrentPoolTestPerf.java
└── util
└── SamplingPoolReducerTest.java
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: simeonmalchev
2 | custom: [www.buymeacoffee.com/simeonmalchev]
3 |
--------------------------------------------------------------------------------
/CHANGELOG:
--------------------------------------------------------------------------------
1 | Version 26.0 (09/01/2025)
2 | =========================
3 | * Migrated the source code base to Java 10.
4 | * Updated all project dependencies to latest versions.
5 | * Removed support for OSGi, added Automatic-Module-Name for Java 9 modules.
6 |
7 | Version 25.0 (30/11/2019)
8 | =========================
9 | * Allowed the ConcurrentPool ConcurrentCollection parameter to be a pre-initialized collection (or empty as before).
10 |
11 | Version 24.0 (28/11/2019)
12 | =========================
13 | * Updated the disruptor dependency in pom.xml to true.
14 |
15 | Version 23.0 (15/05/2019)
16 | =========================
17 | * Implemented catching and processing of undeclared checked exception in ConcurrentPool and SamplingPoolReducer.
18 | Such exceptions can be easily thrown from PoolObjectFactory if its implementation is in Kotlin. This processing
19 | logic is in addition to the existing logic for processing of RuntimeExceptions.
20 |
21 | Version 22.2 (05/05/2018)
22 | =========================
23 | * Catching-up with Vibur DBCP version 22.2.
24 |
25 | Version 22.1 (30/03/2018)
26 | =========================
27 | * Small refactoring in ConcurrentPool; moved the call to readyToRestore(..) to happen before the call to
28 | listener.onRestore(..).
29 | * Various javadoc improvements.
30 |
31 | Version 22.0 (08/02/2018)
32 | =========================
33 | * Catching-up with Vibur DBCP version 22.0.
34 |
35 | Version 21.3 (28/01/2018)
36 | =========================
37 | * Catching-up with Vibur DBCP version 21.3.
38 |
39 | Version 21.2 (29/11/2017)
40 | =========================
41 | * Catching-up with Vibur DBCP version 21.2.
42 |
43 | Version 21.1 (27/11/2017)
44 | =========================
45 | * Catching-up with Vibur DBCP version 21.1.
46 |
47 | Version 21.0 (22/11/2017)
48 | =========================
49 | * Transitioned the SamplingPoolReducer time measuring to nanoseconds.
50 |
51 | Version 20.0 (26/09/2017)
52 | =========================
53 | * Added a test for getting object from interrupted thread.
54 |
55 | Version 19.2 (14/09/2017)
56 | =========================
57 | * Catching-up with Vibur DBCP version 19.2.
58 |
59 | Version 19.1 (17/08/2017)
60 | =========================
61 | * Catching-up with Vibur DBCP version 19.1.
62 |
63 | Version 19.0 (09/08/2017)
64 | =========================
65 | * Introduced 3 new methods in the PoolService interface that are counterparts of the existing take(),
66 | takeUninterruptibly(), and tryTake() methods respectively. The newly introduced methods allow
67 | the real time spent waiting for an object to become available in the pool to be reported back to the
68 | caller via the waitedNanos parameter.
69 |
70 | Version 18.0 (28/06/2017)
71 | =========================
72 | * Catching-up with Vibur DBCP version 18.0.
73 |
74 | Version 17.1 (23/06/2017)
75 | =========================
76 | * Changed the object handling flow on take/restore when the pool is terminated.
77 |
78 | Version 17.0 (05/04/2017)
79 | =========================
80 | * Catching-up with Vibur DBCP version 17.0.
81 |
82 | Version 16.2 (10/02/2017)
83 | =========================
84 | * Javadoc improvements.
85 | * Minor refactoring.
86 |
87 | Version 16.1 (11/01/2017)
88 | =========================
89 | * Catching-up with Vibur DBCP version 16.1.
90 |
91 | Version 16.0 (09/01/2017)
92 | =========================
93 | * Catching-up with Vibur DBCP version 16.0.
94 |
95 | Version 15.0 (04/01/2017)
96 | =========================
97 | * Catching-up with Vibur DBCP version 15.0.
98 |
99 | Version 14.0 (22/12/2016)
100 | =========================
101 | * Minor refactoring; catching-up with Vibur DBCP version 14.0.
102 |
103 | Version 13.0 (23/11/2016)
104 | =========================
105 | * Added ConcurrentStackCollection as a stack pair of MultithreadConcurrentQueueCollection.
106 |
107 | Version 12.0 (11/11/2016)
108 | =========================
109 | * Added Conversant Disruptor as an optional concurrent queue/collection used by ConcurrentPool.
110 | * Refactoring to accommodate third-party collections having interface different than java.util.Queue/Deque,
111 | particularly introduced the ConcurrentCollection adapter interface.
112 | To configure ConcurrentPool with Conversant Disruptor:
113 | pool = new ConcurrentPool<>(new MultithreadConcurrentQueueCollection<>(100), new ObjectFactory(), 1, 100, true);
114 |
115 | Version 11.0 (18/09/2016)
116 | =========================
117 | * Minor change to the signature of getTaken() in TakenListener.
118 |
119 | Version 10.0 (31/07/2016)
120 | =========================
121 | * Renamed reduceCreated() to reduceCreatedBy() and added reduceCreatedTo() method in the BasePool interface.
122 | * JavaDoc fixes, importantly, addressed https://github.com/vibur/vibur-object-pool/issues/3.
123 |
124 | Version 9.0 (02/05/2016)
125 | ========================
126 | * Migrated the source code base to Java 1.7 and implemented AutoCloseable for ConcurrentLinkedPool - issue #1.
127 | * Fixed issue #2 - call destroy() on returned objects after pool termination; the implication of this fix is
128 | that now when closing a proxy connection after pool termination in the JDBC connection pool, the underlying
129 | physical connection will be closed, too.
130 | * Added a new parameter to the ConcurrentLinkedPool constructor in order to allow the underlying objects storing
131 | data structure used by the pool to be either FIFO or LIFO. Before it was always FIFO.
132 | * Refactoring - moved ThreadedPoolReducer and Listener interfaces and their implementation classes under
133 | org.vibur.objectpool.util package.
134 |
135 | Version 8.0 (02/02/2016)
136 | ========================
137 | * Catching-up with Vibur DBCP version 8.0.
138 |
139 | Version 7.0 (10/01/2016)
140 | ========================
141 | * Catching-up with Vibur DBCP version 7.0.
142 |
143 | Version 6.1 (05/01/2016)
144 | ========================
145 | * Catching-up with Vibur DBCP version 6.1.
146 |
147 | Version 6.0 (19/12/2015)
148 | ==========================
149 | * The call to PoolObjectFactory.destroy() is now included in a try-finally block after calling
150 | PoolObjectFactory.readyToTake() or PoolObjectFactory.readyToRestore().
151 |
152 | Version 5.0 (24/08/2015)
153 | ==========================
154 | * Catching-up with Vibur DBCP version 5.0.
155 | * Javadoc updates.
156 |
157 | Version 4.0 (08/08/2015)
158 | ==========================
159 | * Catching-up with Vibur DBCP version 4.0.
160 | * Various other refactoring and javadoc updates.
161 |
162 | Version 3.0 (03/06/2015)
163 | ==========================
164 | * Modified the SamplingPoolReducer pool shrinking algorithm to allow the number of allocated on the
165 | pool objects to reach zero.
166 | * Modified the SamplingPoolReducer logic to allow the afterReduce() method to be called even if the
167 | intended pool reduction is zero - useful for reporting/logging purposes.
168 | * Migrated the project to single digit version numbers, similarly to Vibur DBCP project.
169 |
170 | Version 2.0.0 (02/06/2014)
171 | ==========================
172 | * Overhauled the existing in version 1.0 validating and non-validating object pools and replaced
173 | them with a single object pool that does not provide any special validation means, but provides
174 | support for a Listener interface which methods will be called upon calling the pool take and
175 | restore operations.
176 | * Vibur Object Pool is now built and distributed as a valid R4 OSGi bundle.
177 |
178 | Version 1.0.0 (02/02/2014)
179 | ==========================
180 | * Making all vibur-dbcp dependencies having equal release version.
181 |
182 | Version 0.8.9 (15/10/2013)
183 | ==========================
184 | * Bug fix and refactoring.
185 |
186 | Version 0.8.8 (25/08/2013)
187 | ==========================
188 | * Minor refactoring and comments fixes.
189 | * The pool reducer functionality was re-implemented in the SamplingPoolReducer class.
190 |
191 | Version 0.8.7 (10/08/2013)
192 | ==========================
193 | * Packages structure refactoring.
194 |
195 | Version 0.8.6 (26/07/2013)
196 | ==========================
197 | * Minor refactoring, dependencies versions update.
198 |
199 | Version 0.8.5 (28/06/2013)
200 | ==========================
201 | * Fix in ConcurrentHolderLinkedPool, aiming to prevent the possibility that an object taken from
202 | one pool can be returned to another.
203 | * Changed the build artifact name to use "-" instead of "_".
204 |
205 | Version 0.8.4 (18/02/2013)
206 | ==========================
207 | * restore(Object, boolean valid) method introduced in the pool interfaces.
208 | * afterReduce(int, int, Throwable) method added in PoolReducer class.
209 | * Minor refactoring, improved javadoc, bug fix,
210 | lazily creates new objects if validates on restore fails.
211 |
212 | Version 0.8.3 (06/02/2013)
213 | ==========================
214 | * Minor refactoring, docs update.
215 |
216 | Version 0.8.2 (05/02/2013)
217 | ==========================
218 | * Major refactoring, have changed interface methods names,
219 | have added more information in the README file.
220 |
221 | Version 0.8.1 (31/01/2013)
222 | ==========================
223 | * Changed the reduceCreated(int) and drainCreated() contracts to allows the
224 | createdTotal() to become less than the initialSize(). I.e. a call to
225 | reduceCreated(int) may bring the number of created objects in the pool to zero.
226 |
227 | Version 0.8.0 (30/01/2013)
228 | ==========================
229 | * First tagged release.
230 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/NOTICE:
--------------------------------------------------------------------------------
1 | Vibur Object Pool
2 | A general-purpose concurrent Java object pool.
3 | Copyright 2013-2025 Simeon Malchev
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | Vibur Object Pool is a general-purpose concurrent Java object pool that is built entirely using standard
4 | Java concurrency utilities, does not use any synchronized blocks or methods, and does not have any
5 | external dependencies. Vibur Object Pool has been around for more than 10 years now.
6 |
7 | The project [home page](http://www.vibur.org/vibur-object-pool/) contains details of its inner workings,
8 | usage examples, and more.
9 |
10 | This project is a main building block of [Vibur DBCP](https://github.com/vibur/vibur-dbcp) - a concurrent
11 | and dynamic JDBC connection pool.
12 |
13 | The project maven coordinates are:
14 |
15 | ```
16 |
17 | org.vibur
18 | vibur-object-pool
19 | 26.0
20 |
21 | ```
22 |
23 | If you like these Vibur utilities, please ⭐ them here on GitHub. If you're using them in your projects and if you'd like
24 | to support their future development and upkeep, you can buy-me-a-coffee at:
25 |
26 | [](https://www.buymeacoffee.com/simeonmalchev)
27 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 | 4.0.0
20 |
21 | org.vibur
22 | vibur-object-pool
23 | 27.0-SNAPSHOT
24 | jar
25 |
26 | Vibur Object Pool
27 |
28 | General-purpose concurrent Java object pool that is built entirely using standard Java concurrency utilities,
29 | does not use any synchronized blocks or methods, and does not have any external dependencies.
30 |
31 | http://www.vibur.org/vibur-object-pool/
32 | 2013
33 |
34 |
35 |
36 | The Apache Software License, Version 2.0
37 | http://www.apache.org/licenses/LICENSE-2.0.txt
38 | repo
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | scm:git:https://github.com/vibur/vibur-object-pool.git
50 | scm:git:https://github.com/vibur/vibur-object-pool.git
51 | https://github.com/vibur/vibur-object-pool/tree/master/
52 | HEAD
53 |
54 |
55 |
56 |
57 | Simeon Malchev
58 | simeon.malchev@gmail.com
59 | simeonmalchev
60 | http://simeonmalchev.com
61 | +10
62 |
63 | owner
64 | developer
65 |
66 |
67 |
68 |
69 |
70 | vibur.org
71 | http://www.vibur.org/vibur-object-pool/
72 |
73 |
74 |
75 | https://github.com
76 | https://github.com/vibur/vibur-object-pool/issues
77 |
78 |
79 |
80 | UTF-8
81 | UTF-8
82 |
83 | 10
84 | 1.2.21
85 | 5.11.4
86 |
87 | 3.13.0
88 | 3.1.1
89 | 3.11.2
90 | 3.4.2
91 | 3.3.1
92 |
93 |
94 |
95 |
98 |
99 | com.conversantmedia
100 | disruptor
101 | ${disruptor.version}
102 | true
103 |
104 |
105 |
106 | org.junit.jupiter
107 | junit-jupiter
108 | ${junit.jupiter.version}
109 | test
110 |
111 |
112 |
113 |
114 |
115 |
116 | org.apache.maven.plugins
117 | maven-compiler-plugin
118 | ${maven.compiler.plugin.version}
119 |
120 | ${java.version}
121 |
122 |
123 |
124 |
125 | org.apache.maven.plugins
126 | maven-release-plugin
127 | ${maven.release.plugin.version}
128 |
129 |
130 | org.apache.maven.scm
131 | maven-scm-provider-gitexe
132 | 2.1.0
133 |
134 |
135 |
136 | deploy
137 |
138 |
139 |
140 |
141 | org.apache.maven.plugins
142 | maven-javadoc-plugin
143 | ${maven.javadoc.plugin.version}
144 |
145 | none
146 | ${project.basedir}/target
147 |
148 |
149 |
150 | aggregate
151 |
152 | aggregate
153 |
154 | site
155 |
156 |
157 |
158 |
159 |
160 | org.apache.maven.plugins
161 | maven-jar-plugin
162 | ${maven.jar.plugin.version}
163 |
164 |
165 |
166 | org.vibur.objectpool
167 |
168 |
169 |
170 |
171 |
172 |
173 | test-jar
174 |
175 |
176 |
177 |
178 |
179 |
180 | org.apache.maven.plugins
181 | maven-source-plugin
182 | ${maven.source.plugin.version}
183 |
184 |
185 | attach-sources
186 | verify
187 |
188 | jar-no-fork
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/BasePool.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool;
18 |
19 | /**
20 | * Defines the base object pool operations. These operations include various pool metrics,
21 | * pool termination methods, and support for shrinking (reduction) of the number of allocated
22 | * on the pool objects.
23 | *
24 | * @author Simeon Malchev
25 | */
26 | public interface BasePool extends AutoCloseable {
27 |
28 | /**
29 | * Returns the number of objects taken from this object pool.
30 | * This number is less than or equal to the object pool {@link #createdTotal()}.
31 | * Typically used for testing and debugging purposes.
32 | *
33 | * @return the number of objects taken from this object pool
34 | */
35 | int taken();
36 |
37 | /**
38 | * Returns the number of remaining created objects which are currently available in this object pool.
39 | * This number is less than or equal to the object pool {@link #remainingCapacity()}.
40 | * Typically used for testing and debugging purposes.
41 | *
42 | * @return the number of remaining created objects in this object pool
43 | */
44 | int remainingCreated();
45 |
46 | /**
47 | * Returns the total number of created objects which currently exist for this object pool.
48 | * This number is equal to {@link #taken()} + {@link #remainingCreated()}.
49 | * Typically used for testing and debugging purposes.
50 | *
51 | * @return the total number of created objects for this object pool
52 | */
53 | int createdTotal();
54 |
55 | /**
56 | * Returns the remaining capacity of this object pool, i.e. the number of objects which could be
57 | * taken from this object pool without blocking. It is not guaranteed that all these objects
58 | * exist at the time of the call (i.e. are already created) in the object pool - some of them
59 | * might be created on demand upon take requests. Also see {@link #remainingCreated()}.
60 | * Typically used for testing and debugging purposes.
61 | *
62 | * @return the object pool remaining capacity
63 | */
64 | int remainingCapacity();
65 |
66 | /**
67 | * Returns the {@code initialSize} of this object pool at construction time.
68 | * This parameter never changes.
69 | *
70 | * @return the object pool {@code initialSize}
71 | */
72 | int initialSize();
73 |
74 | /**
75 | * Returns the {@code maxSize} of this object pool. This parameter never changes.
76 | *
77 | * @return the object pool {@code maxSize}
78 | */
79 | int maxSize();
80 |
81 |
82 | /**
83 | * Tries to remove (and destroy) up to {@code reduceBy} objects from the object pool. This method may
84 | * bring the object pool {@link #createdTotal()} to a number less than its {@link #initialSize()}.
85 | *
86 | * @param reduceBy the desired amount of objects to be removed
87 | * @param ignoreInitialSize specifies whether the {@link #createdTotal()} may be
88 | * reduced to less than {@link #initialSize()}
89 | * @return the actual amount of objects removed
90 | */
91 | int reduceCreatedBy(int reduceBy, boolean ignoreInitialSize);
92 |
93 | /**
94 | * Tries to remove (and destroy) such number of objects from the object pool that the number of
95 | * {@link #createdTotal()} objects in the pool to become equal of {@code reduceTo}. This method may bring
96 | * the object pool {@link #createdTotal()} to a number smaller than its {@link #initialSize()}.
97 | *
98 | * @param reduceTo the desired amount of created objects to remain in the pool
99 | * @param ignoreInitialSize specifies whether the {@link #createdTotal()} may be
100 | * reduced to less than {@link #initialSize()}
101 | * @return the actual amount of objects removed
102 | */
103 | int reduceCreatedTo(int reduceTo, boolean ignoreInitialSize);
104 |
105 | /**
106 | * Tries to remove (and destroy) as many created objects from this object pool as possible.
107 | * May bring the object pool {@link #createdTotal()} to a number less than its {@link #initialSize()}.
108 | *
109 | * @return the actual amount of objects removed (and destroyed)
110 | */
111 | int drainCreated();
112 |
113 |
114 | /**
115 | * Terminates this object pool. Once terminated the object pool cannot be more revived.
116 | * All take and restore operations called on a terminated object pool should throw
117 | * an exception or be ignored. This method can be invoked multiple times.
118 | */
119 | void terminate();
120 |
121 | /**
122 | * Returns the current terminated state of this object pool.
123 | *
124 | * @return {@code true} if the object pool is terminated; false otherwise
125 | */
126 | boolean isTerminated();
127 |
128 | /**
129 | * A synonym for {@link #terminate()}. Overrides the {@link AutoCloseable}'s method in order to overrule
130 | * the throwing of a checked {@code Exception}.
131 | */
132 | @Override
133 | void close();
134 | }
135 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/ConcurrentPool.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool;
18 |
19 | import org.vibur.objectpool.util.ConcurrentCollection;
20 | import org.vibur.objectpool.util.Listener;
21 |
22 | import java.util.concurrent.Semaphore;
23 | import java.util.concurrent.TimeUnit;
24 | import java.util.concurrent.atomic.AtomicBoolean;
25 | import java.util.concurrent.atomic.AtomicInteger;
26 |
27 | import static java.util.Objects.requireNonNull;
28 | import static org.vibur.objectpool.util.ArgumentValidation.forbidIllegalArgument;
29 |
30 | /**
31 | * An object pool based on a {@link ConcurrentCollection} guarded by a {@link Semaphore}. If the injected
32 | * in the pool {@code ConcurrentCollection} has native implementation for {@code offerFirst()} then
33 | * this pool will operate in LIFO mode, otherwise in FIFO mode.
34 | *
35 | *
This pool enforces a maximum limit on the number of objects that can be contained or taken out of it at
36 | * any time. The pool will lazily create an object upon {@link #tryTake take} request if no ready and valid object
37 | * exists in it at the time of the call; not all objects need to exist and be valid in the pool at all times.
38 | * The {@link #restore} methods do not provide any validation whether the currently restored object has been taken
39 | * before that from the pool or whether it is in taken state. Correct usage of the {@code restore} operations is
40 | * established by programming convention in the application.
41 | *
42 | *
The pool provides support for fairness with regard to the waiting takers threads.
43 | * The creation of new objects and their lifecycle are controlled by the supplied during the
44 | * pool creation time {@link PoolObjectFactory}. If a {@code Listener} instance has been
45 | * supplied when instantiating the pool, its methods will be called when the pool executes {@code take}
46 | * or {@code restore} operations.
47 | *
48 | *
This pool also provides support for shrinking (reduction) of the number of allocated in it objects.
49 | * Note that the shrinking may reduce the {@link #createdTotal()} to less than the pool {@link #initialSize()}.
50 | *
51 | *
The pool cannot contain {@code null} objects.
52 | *
53 | * @author Simeon Malchev
54 | * @param the type of objects held in the pool
55 | */
56 | public class ConcurrentPool implements PoolService {
57 |
58 | private static final int RESERVED = 4096;
59 | private static final int MAX_ALLOWED_SIZE = Integer.MAX_VALUE - RESERVED;
60 |
61 | private final ConcurrentCollection available;
62 | private final Semaphore takeSemaphore;
63 |
64 | private final PoolObjectFactory poolObjectFactory;
65 | private final Listener listener;
66 |
67 | private final int initialSize;
68 | private final int maxSize;
69 | private final AtomicInteger createdTotal;
70 |
71 | private final AtomicBoolean terminated = new AtomicBoolean(false);
72 |
73 | /**
74 | * Creates a new {@code ConcurrentPool} with the given {@link PoolObjectFactory}, initial and max sizes,
75 | * and fairness setting.
76 | *
77 | * @param available the concurrent collection that will store the pooled objects;
78 | * it must be an empty collection or a collection pre-initialized with
79 | * {@code initialSize} objects
80 | * @param poolObjectFactory the factory which will be used to create new objects
81 | * in this object pool as well as to control their lifecycle
82 | * @param initialSize the object pool initial size, i.e. the initial number of
83 | * allocated in the object pool objects; this parameter never changes
84 | * @param maxSize the object pool max size, i.e. the max number of allocated
85 | * in the object pool objects; this parameter never changes
86 | * @param fair the object pool fairness setting with regard to waiting threads
87 | * @throws IllegalArgumentException if one of the following holds:
88 | * {@code initialSize < 0 || maxSize < 1 || maxSize < initialSize}
89 | * @throws NullPointerException if {@code available} or {@code poolObjectFactory} are null
90 | */
91 | public ConcurrentPool(ConcurrentCollection available, PoolObjectFactory poolObjectFactory,
92 | int initialSize, int maxSize, boolean fair) {
93 | this(available, poolObjectFactory, initialSize, maxSize, fair, null);
94 | }
95 |
96 | /**
97 | * Creates a new {@code ConcurrentPool} with the given {@link PoolObjectFactory}, initial and max sizes,
98 | * and fairness setting.
99 | *
100 | * @param available the concurrent collection that will store the pooled objects;
101 | * it must be an empty collection or a collection pre-initialized with
102 | * {@code initialSize} objects
103 | * @param poolObjectFactory the factory which will be used to create new objects
104 | * in this object pool as well as to control their lifecycle
105 | * @param initialSize the object pool initial size, i.e. the initial number of
106 | * allocated in the object pool objects; this parameter never changes
107 | * @param maxSize the object pool max size, i.e. the max number of allocated
108 | * in the object pool objects; this parameter never changes
109 | * @param fair the object pool fairness setting with regard to waiting threads
110 | * @param listener if not {@code null}, this listener instance methods will be called
111 | * when the pool executes {@code take} or {@code restore} operations
112 | * @throws IllegalArgumentException if one of the following holds:
113 | * {@code initialSize < 0 || maxSize < 1 || maxSize < initialSize}
114 | * @throws NullPointerException if {@code available} or {@code poolObjectFactory} are null
115 | */
116 | public ConcurrentPool(ConcurrentCollection available, PoolObjectFactory poolObjectFactory,
117 | int initialSize, int maxSize, boolean fair, Listener listener) {
118 | forbidIllegalArgument(initialSize < 0, "initialSize");
119 | forbidIllegalArgument(maxSize < 1 || maxSize < initialSize || maxSize > MAX_ALLOWED_SIZE, "maxSize");
120 | var availableSize = available.size(); // implicit null check of available collection
121 | forbidIllegalArgument(availableSize != 0 && availableSize != initialSize, "available");
122 |
123 | this.available = available;
124 | this.poolObjectFactory = requireNonNull(poolObjectFactory);
125 | this.listener = listener;
126 |
127 | this.initialSize = initialSize;
128 | this.maxSize = maxSize;
129 | this.takeSemaphore = new Semaphore(maxSize, fair);
130 |
131 | this.createdTotal = new AtomicInteger(availableSize);
132 | if (availableSize == 0) {
133 | addInitialObjects();
134 | }
135 | }
136 |
137 | private void addInitialObjects() {
138 | try {
139 | for (var i = 0; i < initialSize; i++) {
140 | available.offerLast(requireNonNull(poolObjectFactory.create()));
141 | createdTotal.incrementAndGet();
142 | }
143 | } catch (Throwable t) { // equivalent to catching "RuntimeException | Error", however, better for Kotlin interoperability
144 | drainCreated();
145 | throw t;
146 | }
147 | }
148 |
149 | @Override
150 | public T take() {
151 | try {
152 | takeSemaphore.acquire();
153 | return takeObject();
154 | } catch (InterruptedException ignored) {
155 | Thread.currentThread().interrupt(); // ignore and reset
156 | return null;
157 | }
158 | }
159 |
160 | @Override
161 | public T take(long[] waitedNanos) {
162 | try {
163 | var startTime = System.nanoTime();
164 | try {
165 | takeSemaphore.acquire();
166 | } finally {
167 | waitedNanos[0] = System.nanoTime() - startTime;
168 | }
169 |
170 | return takeObject();
171 | } catch (InterruptedException ignored) {
172 | Thread.currentThread().interrupt(); // ignore and reset
173 | return null;
174 | }
175 | }
176 |
177 | @Override
178 | public T takeUninterruptibly() {
179 | takeSemaphore.acquireUninterruptibly();
180 | return takeObject();
181 | }
182 |
183 | @Override
184 | public T takeUninterruptibly(long[] waitedNanos) {
185 | var startTime = System.nanoTime();
186 | try {
187 | takeSemaphore.acquireUninterruptibly();
188 | } finally {
189 | waitedNanos[0] = System.nanoTime() - startTime;
190 | }
191 |
192 | return takeObject();
193 | }
194 |
195 | @Override
196 | public T tryTake(long timeout, TimeUnit unit) {
197 | try {
198 | if (!takeSemaphore.tryAcquire(timeout, unit)) {
199 | return null;
200 | }
201 | return takeObject();
202 | } catch (InterruptedException ignored) {
203 | Thread.currentThread().interrupt(); // ignore and reset
204 | return null;
205 | }
206 | }
207 |
208 | @Override
209 | public T tryTake(long timeout, TimeUnit unit, long[] waitedNanos) {
210 | try {
211 | var startTime = System.nanoTime();
212 | try {
213 | if (!takeSemaphore.tryAcquire(timeout, unit)) {
214 | return null;
215 | }
216 | } finally {
217 | waitedNanos[0] = System.nanoTime() - startTime;
218 | }
219 |
220 | return takeObject();
221 | } catch (InterruptedException ignored) {
222 | Thread.currentThread().interrupt(); // ignore and reset
223 | return null;
224 | }
225 | }
226 |
227 | @Override
228 | public T tryTake() {
229 | if (!takeSemaphore.tryAcquire()) {
230 | return null;
231 | }
232 | return takeObject();
233 | }
234 |
235 | private T takeObject() {
236 | var object = prepareToTake(available.pollFirst());
237 |
238 | if (listener != null) {
239 | listener.onTake(object);
240 | }
241 |
242 | if (isTerminated()) {
243 | restore(object, false);
244 | return null;
245 | }
246 |
247 | return object;
248 | }
249 |
250 | @Override
251 | public void restore(T object) {
252 | restore(object, true);
253 | }
254 |
255 | @Override
256 | public void restore(T object, boolean valid) {
257 | var ready = readyToRestore(requireNonNull(object), valid);
258 |
259 | if (listener != null) {
260 | listener.onRestore(object, valid);
261 | }
262 |
263 | if (ready) {
264 | available.offerFirst(object);
265 | }
266 | takeSemaphore.release();
267 |
268 | if (isTerminated() && valid) {
269 | terminate();
270 | }
271 | }
272 |
273 | /**
274 | * Verifies whether the given object is valid and whether it can be given to the calling application.
275 | * If the object is {@code null}, a new object will be created and returned. If the object
276 | * is not {@code null}, it will be validated and if the validation fails, a new object will be created
277 | * and returned; otherwise a reference to the object itself will be returned. This method never
278 | * returns {@code null}.
279 | *
280 | * @param object the object to be validated
281 | * @return see above
282 | */
283 | private T prepareToTake(T object) {
284 | try {
285 | if (object == null) {
286 | createdTotal.incrementAndGet();
287 | object = requireNonNull(poolObjectFactory.create());
288 | }
289 | else {
290 | var ready = false;
291 | try {
292 | ready = poolObjectFactory.readyToTake(object);
293 | } finally {
294 | if (!ready) {
295 | poolObjectFactory.destroy(object);
296 | }
297 | }
298 | if (!ready) {
299 | object = requireNonNull(poolObjectFactory.create());
300 | }
301 | }
302 |
303 | return object;
304 | } catch (Throwable t) { // equivalent to catching "RuntimeException | Error", however, better for Kotlin interoperability
305 | recoverInnerState();
306 | throw t;
307 | }
308 | }
309 |
310 | /**
311 | * Verifies whether the given object is valid and whether it can be restored back to the pool. Returns {@code true}
312 | * if the object is valid; otherwise returns {@code false}.
313 | *
314 | * @param object the object that is to be restored to the pool and that needs to be validated
315 | * @param valid if {@code false}, the object is treated as invalid; otherwise a secondary validation on the object
316 | * will be performed
317 | * @return see above
318 | */
319 | private boolean readyToRestore(T object, boolean valid) {
320 | try {
321 | var ready = false;
322 | try {
323 | ready = valid && poolObjectFactory.readyToRestore(object);
324 | } finally {
325 | if (!ready) {
326 | poolObjectFactory.destroy(object);
327 | }
328 | }
329 | if (!ready) {
330 | createdTotal.decrementAndGet();
331 | }
332 |
333 | return ready;
334 | } catch (Throwable t) { // equivalent to catching "RuntimeException | Error", however, better for Kotlin interoperability
335 | recoverInnerState();
336 | throw t;
337 | }
338 | }
339 |
340 | private void recoverInnerState() {
341 | createdTotal.decrementAndGet();
342 | takeSemaphore.release();
343 | }
344 |
345 |
346 | @Override
347 | public Listener listener() {
348 | return listener;
349 | }
350 |
351 | @Override
352 | public int taken() {
353 | return !isTerminated() ? calculateTaken() : createdTotal();
354 | }
355 |
356 | private int calculateTaken() {
357 | return maxSize() - remainingCapacity();
358 | }
359 |
360 | @Override
361 | public int remainingCreated() {
362 | return !isTerminated() ? createdTotal() - calculateTaken() : 0;
363 | }
364 |
365 | @Override
366 | public int drainCreated() {
367 | return reduceCreatedTo(0, true);
368 | }
369 |
370 | @Override
371 | public String toString() {
372 | return super.toString() + (!isTerminated() ? "[remainingCreated = " + remainingCreated() + "]" : "[terminated]");
373 | }
374 |
375 |
376 | @Override
377 | public int createdTotal() {
378 | return createdTotal.get();
379 | }
380 |
381 | @Override
382 | public int remainingCapacity() {
383 | return !isTerminated() ? takeSemaphore.availablePermits() : 0;
384 | }
385 |
386 | @Override
387 | public int initialSize() {
388 | return initialSize;
389 | }
390 |
391 | @Override
392 | public int maxSize() {
393 | return maxSize;
394 | }
395 |
396 |
397 | @Override
398 | public int reduceCreatedBy(int reduceBy, boolean ignoreInitialSize) {
399 | forbidIllegalArgument(reduceBy < 0, "reduceBy");
400 |
401 | for (var cnt = 0; cnt < reduceBy; cnt++) {
402 | if (!reduceByOne(ignoreInitialSize)) {
403 | return cnt;
404 | }
405 | }
406 | return reduceBy;
407 | }
408 |
409 | @Override
410 | public int reduceCreatedTo(int reduceTo, boolean ignoreInitialSize) {
411 | forbidIllegalArgument(reduceTo < 0, "reduceTo");
412 |
413 | int cnt;
414 | for (cnt = 0; createdTotal() > reduceTo; cnt++) {
415 | if (!reduceByOne(ignoreInitialSize)) {
416 | break;
417 | }
418 | }
419 | return cnt;
420 | }
421 |
422 | private boolean reduceByOne(boolean ignoreInitialSize) {
423 | var newTotal = createdTotal.decrementAndGet();
424 | if (!ignoreInitialSize && newTotal < initialSize) {
425 | createdTotal.incrementAndGet();
426 | return false;
427 | }
428 | var object = available.pollLast();
429 | if (object == null) {
430 | createdTotal.incrementAndGet();
431 | return false;
432 | }
433 | poolObjectFactory.destroy(object);
434 | return true;
435 | }
436 |
437 |
438 | @Override
439 | public void terminate() {
440 | var wasTerminated = terminated.getAndSet(true);
441 |
442 | drainCreated();
443 |
444 | if (!wasTerminated) {
445 | takeSemaphore.release(takeSemaphore.getQueueLength() + RESERVED); // best effort to unblock any waiting on the takeSemaphore threads
446 | }
447 | }
448 |
449 | @Override
450 | public void close() {
451 | terminate();
452 | }
453 |
454 | @Override
455 | public boolean isTerminated() {
456 | return terminated.get();
457 | }
458 |
459 |
460 | @Override
461 | public boolean isFair() {
462 | return takeSemaphore.isFair();
463 | }
464 | }
465 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/PoolObjectFactory.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool;
18 |
19 | /**
20 | * Defines the interface that will be implemented by the factory used by the object pools
21 | * defined in the package, in order to control the lifecycle of the objects in the pools.
22 | *
23 | * @author Simeon Malchev
24 | * @param the type of objects held in the client object pool
25 | */
26 | public interface PoolObjectFactory {
27 |
28 | /**
29 | * Creates a new object for the calling object pool. This object is presumed to be ready (and valid)
30 | * for immediate use. Should never return {@code null}.
31 | *
32 | *
This method will be called by the constructors of {@link ConcurrentPool}, and by any of its
33 | * {@code take...} methods if they were able to obtain a permit from the counting {@code Semaphore}
34 | * guarding the pool, but there was no ready and valid object in the pool. I.e., this is the case when
35 | * a new object is created lazily in the pool upon request.
36 | *
37 | * @return a new object for this object pool
38 | */
39 | T create();
40 |
41 | /**
42 | * A validation/activation hook which will be called by the {@code take...} methods of
43 | * {@link ConcurrentPool} when an object from the object pool is requested by the application.
44 | * This is an optional operation which concrete implementation may simply always return {@code true}.
45 | *
46 | *
If there is a particular activation or validation which needs to be done
47 | * for the taken from the pool object, this is the ideal place where it can be done.
48 | *
49 | * @see #readyToRestore
50 | *
51 | * @param obj an object which is taken from the object pool and which is to be given
52 | * to the calling application
53 | * @return {@code true} if the validation/activation is successful, {@code false} otherwise
54 | */
55 | boolean readyToTake(T obj);
56 |
57 | /**
58 | * A validation/passivation hook which will be called by the {@code restore} methods of
59 | * {@link ConcurrentPool} when an object taken before that from the object pool is about to be
60 | * restored (returned back) to the pool. This is an optional operation which concrete implementation
61 | * may simply always return {@code true}.
62 | *
63 | *
If there is a particular passivation or validation which needs to be done
64 | * for the restored to the pool object, this is the ideal place where it can be done.
65 | *
66 | * @see #readyToTake
67 | *
68 | * @param obj an object which has been taken before that from this object pool and which is now
69 | * to be restored to the pool
70 | * @return {@code true} if the validation/passivation is successful, {@code false} otherwise
71 | */
72 | boolean readyToRestore(T obj);
73 |
74 | /**
75 | * A method which will be called when an object from the object pool needs to be destroyed,
76 | * which is when the {@link #readyToTake} or {@link #readyToRestore} methods have returned
77 | * {@code false}, or when the pool is shrinking its size (via calling {@code reduceCreatedBy/To}),
78 | * or when the pool is terminating. The simplest implementation of this method may simply
79 | * do nothing, however if there are any allocated resources associated with the to-be-destroyed
80 | * object, like network connections or similar, this is the ideal place where they can be
81 | * de-allocated.
82 | *
83 | * @param obj an object from the pool which needs to be destroyed
84 | */
85 | void destroy(T obj);
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/PoolService.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool;
18 |
19 | import org.vibur.objectpool.util.Listener;
20 |
21 | import java.util.concurrent.TimeUnit;
22 |
23 | /**
24 | * Defines the object pool operations. These operations include the {@code take} and {@code restore} pool
25 | * methods.
26 | *
27 | *
This pool enforces a maximum limit on the number of objects that can be contained or taken out
28 | * of it at any time. The pool may lazily create an object upon {@code take} request; not all objects need
29 | * to exist and be valid in the pool at all times. The {@code restore} methods do not provide any validation
30 | * whether the currently restored object has been taken before that from the pool or whether it is in taken state.
31 | * Correct usage of the {@code restore} operations is established by programming convention in the application.
32 | *
33 | *
The object pool implementation may support an optional fairness parameter (usually provided via the
34 | * pool constructor) that defines the pool behaviour with regard to waiting takers threads, as well as
35 | * an optional {@code Listener} interface which methods will be called when a {@code take} or
36 | * {@code restore} pool method executes.
37 | *
38 | *
The pool cannot contain {@code null} objects.
39 | *
40 | * @author Simeon Malchev
41 | * @param the type of objects held in this object pool
42 | */
43 | public interface PoolService extends BasePool {
44 |
45 | /**
46 | * A counterpart of {@link #take(long[])} that does not report back the time waited
47 | * to obtain an object from the pool.
48 | *
49 | * @return an object taken from the object pool or {@code null} if was interrupted while waiting
50 | */
51 | T take();
52 |
53 | /**
54 | * Takes an object from the object pool if there is such available. This is a blocking call that
55 | * waits indefinitely until an object becomes available; the object may need to be created as
56 | * described in {@link #tryTake(long, TimeUnit, long[])}. If the calling thread is interrupted
57 | * while waiting this call will return {@code null} and the thread's interrupted status will
58 | * be set to {@code true}.
59 | *
60 | * @param waitedNanos used to report the time waited, see {@link #tryTake(long, TimeUnit, long[])}
61 | * @return an object taken from the object pool or {@code null} if it was interrupted while waiting
62 | */
63 | T take(long[] waitedNanos);
64 |
65 | /**
66 | * A counterpart of {@link #takeUninterruptibly(long[])} that does not report back the time waited
67 | * to obtain an object from the pool.
68 | *
69 | * @return an object taken from the object pool
70 | */
71 | T takeUninterruptibly();
72 |
73 | /**
74 | * Takes an object from the object pool if there is such available. This is a blocking call that
75 | * waits indefinitely until an object becomes available; the object may need to be created as
76 | * described in {@link #tryTake(long, TimeUnit, long[])}.
77 | *
78 | * @param waitedNanos used to report the time waited, see {@link #tryTake(long, TimeUnit, long[])}
79 | * @return an object taken from the object pool
80 | */
81 | T takeUninterruptibly(long[] waitedNanos);
82 |
83 | /**
84 | * A counterpart of {@link #tryTake(long, TimeUnit, long[])} that does not report back the time waited
85 | * to obtain an object from the pool.
86 | *
87 | * @param timeout the maximum time to wait for an object to become available in the object pool;
88 | * this timeout does not include the object creation time, see above
89 | * @param unit the time unit of the {@code timeout} argument
90 | * @return an object taken from the object pool or {@code null} if the specified timeout expires
91 | * or if it was interrupted while waiting
92 | */
93 | T tryTake(long timeout, TimeUnit unit);
94 |
95 | /**
96 | * Tries to take an object from the object pool if there is one available. This is a blocking call that
97 | * waits for an object to become available up to the specified {@code timeout}. The real time spent waiting is
98 | * reported back via the {@code waitedNanos} parameter. The total method execution time may also include the
99 | * object creation time - an object can be (lazily) created in the pool when the pool capacity is not reached
100 | * yet but no ready and valid object existed in the pool. If the calling thread is interrupted while waiting
101 | * this call will return {@code null} and the thread's interrupted status will be set to {@code true}.
102 | *
103 | * @param timeout the maximum time to wait for an object to become available in the object pool;
104 | * this timeout does not include the object creation time
105 | * @param unit the time unit of the {@code timeout} argument
106 | * @param waitedNanos this parameter is used to report the nanoseconds time waited for an object to become
107 | * available in the pool, excluding any object creation time; the time waited will be stored
108 | * at index {@code 0} of this array; the array must be of size of at least one
109 | * @return an object taken from the object pool or {@code null} if the specified timeout expires
110 | * or if it was interrupted while waiting
111 | */
112 | T tryTake(long timeout, TimeUnit unit, long[] waitedNanos);
113 |
114 | /**
115 | * Tries to take an object from the object pool if there is one that is immediately available; the object may
116 | * need to be created as described in {@link #tryTake(long, TimeUnit, long[])}. Returns {@code null} if no object
117 | * is available in the pool at the time of the call.
118 | *
119 | * @return an object from the object pool or {@code null} if no object was available
120 | */
121 | T tryTake();
122 |
123 | /**
124 | * Restores (returns) an object to the object pool. The object pool does not
125 | * verify whether the currently restored object has been taken before that from this object pool
126 | * or whether it is currently in taken state. Equivalent to calling {@link #restore(Object, boolean)
127 | * restore(object, true)}.
128 | *
129 | * @param object the object to be restored / returned
130 | * @throws NullPointerException if the given object is {@code null}
131 | */
132 | void restore(T object);
133 |
134 | /**
135 | * Restores (returns) an object to the object pool. The object pool does not
136 | * verify whether the currently restored object has been taken before that from this object pool
137 | * or whether it is currently in taken state.
138 | *
139 | * @param object the object to be restored / returned
140 | * @param valid if {@code false}, the object is treated as invalid; otherwise a secondary validation on the object
141 | * will be performed
142 | * @throws NullPointerException if the given object is {@code null}
143 | */
144 | void restore(T object, boolean valid);
145 |
146 |
147 | /**
148 | * Returns the {@link Listener} interface instance associated with this object pool, if any.
149 | *
150 | * @return see above; {@code null} means no {@code Listener} is associated with this object pool.
151 | */
152 | Listener listener();
153 |
154 |
155 | /**
156 | * Returns the fairness setting of this object pool.
157 | *
158 | * @return {@code true} if the object pool is fair to waiting taker threads
159 | */
160 | boolean isFair();
161 | }
162 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ArgumentValidation.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | /**
20 | * @author Simeon Malchev
21 | */
22 | public final class ArgumentValidation {
23 |
24 | private ArgumentValidation() { }
25 |
26 | public static void forbidIllegalArgument(boolean condition) {
27 | if (condition) {
28 | throw new IllegalArgumentException();
29 | }
30 | }
31 |
32 | public static void forbidIllegalArgument(boolean condition, String param) {
33 | if (condition) {
34 | throw new IllegalArgumentException("Illegal value for parameter: \"" + param + "\"");
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ConcurrentCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | /**
20 | * An adapter interface to a concurrent collection that provides 4 access methods: {@link #offerFirst},
21 | * {@link #offerLast}, {@link #pollFirst}, and {@link #pollLast}. If the implementing subclass delegates the above
22 | * methods to a Collection that does not have native implementation for {@code offerFirst()} or {@code pollLast()}
23 | * it can implement these methods in the same way as {@code offerLast()} or {@code pollFirst()}, and the vice versa.
24 | *
25 | * @author Simeon Malchev
26 | * @param the type of objects held in this {@code ConcurrentCollection}
27 | */
28 | public interface ConcurrentCollection {
29 |
30 | /**
31 | * Adds the given {@code object} at the head of the {@code ConcurrentCollection}.
32 | *
33 | * @param object the given object
34 | */
35 | void offerFirst(T object);
36 |
37 | /**
38 | * Adds the given {@code object} at the tail of the {@code ConcurrentCollection}.
39 | *
40 | * @param object the given object
41 | */
42 | void offerLast(T object);
43 |
44 | /**
45 | * Polls an {@code object} from the head of the {@code ConcurrentCollection}.
46 | *
47 | * @return the head Collection object if available; {@code null} otherwise
48 | */
49 | T pollFirst();
50 |
51 | /**
52 | * Polls an {@code object} from the tail of the {@code ConcurrentCollection}.
53 | *
54 | * @return the tail Collection object if available; {@code null} otherwise
55 | */
56 | T pollLast();
57 |
58 | /**
59 | * Returns the number of elements in this collection.
60 | *
61 | * @return the number of elements in this collection
62 | */
63 | int size();
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ConcurrentLinkedDequeCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import java.util.Deque;
20 | import java.util.concurrent.ConcurrentLinkedDeque;
21 |
22 | /**
23 | * A {@link ConcurrentLinkedDeque} based implementation of {@link ConcurrentCollection}.
24 | *
25 | * @author Simeon Malchev
26 | * @param the type of objects held in this {@code ConcurrentCollection}
27 | */
28 | public class ConcurrentLinkedDequeCollection implements ConcurrentCollection {
29 |
30 | private final Deque deque = new ConcurrentLinkedDeque<>();
31 |
32 | @Override
33 | public void offerFirst(T object) {
34 | deque.addFirst(object);
35 | }
36 |
37 | @Override
38 | public void offerLast(T object) {
39 | deque.add(object);
40 | }
41 |
42 | @Override
43 | public T pollFirst() {
44 | return deque.poll();
45 | }
46 |
47 | @Override
48 | public T pollLast() {
49 | return deque.pollLast();
50 | }
51 |
52 | @Override
53 | public int size() {
54 | return deque.size();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ConcurrentLinkedQueueCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import java.util.Queue;
20 | import java.util.concurrent.ConcurrentLinkedQueue;
21 |
22 | /**
23 | * A {@link ConcurrentLinkedQueue} based implementation of {@link ConcurrentCollection}.
24 | *
25 | * @author Simeon Malchev
26 | * @param the type of objects held in this {@code ConcurrentCollection}
27 | */
28 | public class ConcurrentLinkedQueueCollection implements ConcurrentCollection {
29 |
30 | private final Queue queue = new ConcurrentLinkedQueue<>();
31 |
32 | @Override
33 | public void offerFirst(T object) {
34 | offerLast(object);
35 | }
36 |
37 | @Override
38 | public void offerLast(T object) {
39 | queue.add(object);
40 | }
41 |
42 | @Override
43 | public T pollFirst() {
44 | return queue.poll();
45 | }
46 |
47 | @Override
48 | public T pollLast() {
49 | return pollFirst();
50 | }
51 |
52 | @Override
53 | public int size() {
54 | return queue.size();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ConcurrentStackCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import com.conversantmedia.util.collection.Stack;
20 | import com.conversantmedia.util.concurrent.ConcurrentStack;
21 |
22 |
23 | /**
24 | * A {@link ConcurrentStack} based implementation of {@link ConcurrentCollection}.
25 | *
26 | * @author Simeon Malchev
27 | * @param the type of objects held in this {@code ConcurrentCollection}
28 | */
29 | public class ConcurrentStackCollection implements ConcurrentCollection {
30 |
31 | private final Stack stack;
32 |
33 | public ConcurrentStackCollection(int capacity) {
34 | stack = new ConcurrentStack<>(capacity);
35 | }
36 |
37 | @Override
38 | public void offerFirst(T object) {
39 | stack.push(object);
40 | }
41 |
42 | @Override
43 | public void offerLast(T object) {
44 | offerFirst(object);
45 | }
46 |
47 | @Override
48 | public T pollFirst() {
49 | return stack.pop();
50 | }
51 |
52 | @Override
53 | public T pollLast() {
54 | return pollFirst();
55 | }
56 |
57 | @Override
58 | public int size() {
59 | return stack.size();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/Listener.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | /**
20 | * An instance of this interface can be supplied to the pool at its creation time, and its methods will be called
21 | * upon calling the pool {@code take} and {@code restore} operations.
22 | *
23 | * @author Simeon Malchev
24 | */
25 | public interface Listener {
26 |
27 | void onTake(T object);
28 |
29 | void onRestore(T object, boolean valid);
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/MultithreadConcurrentQueueCollection.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2016 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import com.conversantmedia.util.concurrent.ConcurrentQueue;
20 | import com.conversantmedia.util.concurrent.MultithreadConcurrentQueue;
21 |
22 |
23 | /**
24 | * A {@link MultithreadConcurrentQueue} based implementation of {@link ConcurrentCollection}.
25 | *
26 | * @author Simeon Malchev
27 | * @param the type of objects held in this {@code ConcurrentCollection}
28 | */
29 | public class MultithreadConcurrentQueueCollection implements ConcurrentCollection {
30 |
31 | private final ConcurrentQueue queue;
32 |
33 | public MultithreadConcurrentQueueCollection(int capacity) {
34 | queue = new MultithreadConcurrentQueue<>(capacity);
35 | }
36 |
37 | @Override
38 | public void offerFirst(T object) {
39 | offerLast(object);
40 | }
41 |
42 | @Override
43 | public void offerLast(T object) {
44 | queue.offer(object);
45 | }
46 |
47 | @Override
48 | public T pollFirst() {
49 | return queue.poll();
50 | }
51 |
52 | @Override
53 | public T pollLast() {
54 | return pollFirst();
55 | }
56 |
57 | @Override
58 | public int size() {
59 | return queue.size();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/SamplingPoolReducer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import org.vibur.objectpool.BasePool;
20 |
21 | import java.util.concurrent.TimeUnit;
22 |
23 | import static java.util.Objects.requireNonNull;
24 | import static java.util.concurrent.TimeUnit.NANOSECONDS;
25 | import static org.vibur.objectpool.util.ArgumentValidation.forbidIllegalArgument;
26 |
27 | /**
28 | * A sampling pool reducer util, which is awakened up a given number of times during
29 | * a predefined period of time, and checks whether the number of available
30 | * allocated objects in the object pool needs to be reduced.
31 | *
32 | *
This pool reducer will not bring the number of allocated on the pool
33 | * objects to less than the pool {@code initial} size.
34 | *
35 | *
This pool reducer creates one daemon service thread which will be started when
36 | * the reducer's {@link #start()} method is called, and will be alive until the
37 | * {@link #terminate()} method is called or until the calling application exits.
38 | *
39 | *
Note that if an exception is thrown by the overridable
40 | * {@link #afterReduce(int, int, Throwable)} method hook, it will terminate the
41 | * SamplingPoolReducer, including the reducer's background daemon thread.
42 | *
43 | * @author Simeon Malchev
44 | */
45 | public class SamplingPoolReducer implements ThreadedPoolReducer {
46 |
47 | private final BasePool pool;
48 | private final long sleepNanoTime;
49 | private final int samples;
50 |
51 | private final Thread reducerThread;
52 |
53 | protected static final double MAX_REDUCTION_FRACTION = 0.2;
54 | protected int minRemainingCreated;
55 |
56 | /**
57 | * Creates a new {@link SamplingPoolReducer} with the given {@link BasePool} and
58 | * {@code timeInterval} settings. The created pool reducer is not started and needs to be
59 | * explicitly started via calling the {@link #start()} method.
60 | *
61 | * @param pool the pool that is to be reduced if necessary
62 | * @param timeInterval the time period after which the {@link SamplingPoolReducer} will try to
63 | * possibly reduce the number of created but unused objects in the
64 | * given {@code pool}
65 | * @param unit the time unit of the {@code timeInterval} argument
66 | * @param samples how many times the {@link SamplingPoolReducer} will wake up during the given
67 | * {@code timeInterval} period in order to sample various information from
68 | * the given {@code pool}
69 | * @throws IllegalArgumentException if one of the following holds:
70 | * {@code timeInterval <= 0 || samples <= 0}
71 | * @throws NullPointerException if one of the following holds:
72 | * {@code pool == null || unit == null}
73 | */
74 | public SamplingPoolReducer(BasePool pool, long timeInterval, TimeUnit unit, int samples) {
75 | forbidIllegalArgument(timeInterval <= 0, "timeInterval");
76 | forbidIllegalArgument(samples <= 0, "samples");
77 |
78 | this.sleepNanoTime = unit.toNanos(timeInterval) / samples;
79 | forbidIllegalArgument(sleepNanoTime == 0, "sleepNanoTime");
80 |
81 | this.pool = requireNonNull(pool);
82 | this.samples = samples;
83 |
84 | this.reducerThread = new Thread(new PoolReducerRunnable());
85 | }
86 |
87 | @Override
88 | public void start() {
89 | reducerThread.setName(getThreadName());
90 | reducerThread.setDaemon(true);
91 | reducerThread.setPriority(Thread.MAX_PRIORITY - 2);
92 | reducerThread.start();
93 | }
94 |
95 | protected String getThreadName() {
96 | return reducerThread.getName();
97 | }
98 |
99 | private class PoolReducerRunnable implements Runnable {
100 | @Override
101 | public void run() {
102 | var sample = 1;
103 | minRemainingCreated = Integer.MAX_VALUE;
104 | for (;;) {
105 | try {
106 | NANOSECONDS.sleep(sleepNanoTime);
107 | samplePool();
108 | if (sample++ % samples == 0) {
109 | reducePool();
110 | sample = 1;
111 | minRemainingCreated = Integer.MAX_VALUE;
112 | }
113 | } catch (InterruptedException ignored) {
114 | break;
115 | }
116 | }
117 | }
118 | }
119 |
120 | protected void samplePool() {
121 | var remainingCreated = pool.remainingCreated();
122 | minRemainingCreated = Math.min(minRemainingCreated, remainingCreated);
123 | }
124 |
125 | protected void reducePool() {
126 | var reduction = calculateReduction();
127 |
128 | var reduced = -1;
129 | Throwable thrown = null;
130 | try {
131 | reduced = pool.reduceCreatedBy(reduction, false);
132 | } catch (Throwable t) { // equivalent to catching "RuntimeException | Error", however, better for Kotlin interoperability
133 | thrown = t;
134 | } finally {
135 | afterReduce(reduction, reduced, thrown);
136 | }
137 | }
138 |
139 | /**
140 | * Calculates the number of currently allocated on the pool elements that needs to be destroyed/deallocated,
141 | * as a result of the stats collected during the just finished observational time period.
142 | * The number of remaining allocated on the pool objects will not fall below the pool {@code initial}
143 | * size as a result of this reduction.
144 | *
145 | * @return the calculated reduction number
146 | */
147 | protected int calculateReduction() {
148 | var createdTotal = pool.createdTotal();
149 | var maxReduction = (int) Math.ceil(createdTotal * MAX_REDUCTION_FRACTION);
150 | var reduction = Math.min(minRemainingCreated, maxReduction);
151 | var bottomThreshold = createdTotal - pool.initialSize();
152 | reduction = Math.min(reduction, bottomThreshold);
153 | return Math.max(reduction, 0);
154 | }
155 |
156 | /**
157 | * An after reduce pool hook. The default implementation will {@code terminate()} this pool reducer
158 | * if {@code thrown != null}. Note that if this method throws an exception, this
159 | * will terminate the pool reducer, too.
160 | *
161 | * @param reduction the intended reduction number
162 | * @param reduced the number of objects which were successfully removed/destroyed from the pool
163 | * @param thrown a thrown during the pool reduction exception if any.
164 | */
165 | protected void afterReduce(int reduction, int reduced, Throwable thrown) {
166 | if (thrown != null) {
167 | terminate();
168 | }
169 | }
170 |
171 | @Override
172 | public Thread.State getState() {
173 | return reducerThread.getState();
174 | }
175 |
176 | @Override
177 | public void terminate() {
178 | reducerThread.interrupt();
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/TakenListener.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2014 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | import java.util.Collections;
20 | import java.util.Set;
21 | import java.util.concurrent.ConcurrentHashMap;
22 |
23 | /**
24 | * An instance of this class can be supplied to the pool at its creation time, and its methods will be called
25 | * upon calling the pool take and restore operations. This listener can provide a list of all currently taken
26 | * objects from the pool, which can be useful for testing and debugging purposes.
27 | *
28 | * @author Simeon Malchev
29 | */
30 | public class TakenListener implements Listener {
31 |
32 | private final Set taken;
33 |
34 | public TakenListener() {
35 | taken = Collections.newSetFromMap(new ConcurrentHashMap<>());
36 | }
37 |
38 | public TakenListener(int initialCapacity) {
39 | taken = Collections.newSetFromMap(new ConcurrentHashMap<>(initialCapacity));
40 | }
41 |
42 | @Override
43 | public void onTake(T object) {
44 | taken.add(object);
45 | }
46 |
47 | @Override
48 | public void onRestore(T object, boolean valid) {
49 | taken.remove(object);
50 | }
51 |
52 | protected T[] getTaken(T[] a) {
53 | return taken.toArray(a);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/org/vibur/objectpool/util/ThreadedPoolReducer.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool.util;
18 |
19 | /**
20 | * The pool reducers implementing this interface will create one daemon service thread
21 | * which will be started when the reducer's {@link #start()} method is called, and will
22 | * be alive until the {@link #terminate()} method is called or until the calling application
23 | * exits.
24 | *
25 | * @author Simeon Malchev
26 | */
27 | public interface ThreadedPoolReducer {
28 |
29 | /**
30 | * Starts this pool reducer, which starts its underlying daemon thread.
31 | *
32 | * @exception IllegalThreadStateException if this pool reducer is started more then once
33 | */
34 | void start();
35 |
36 | /**
37 | * Returns the state of the underlying thread.
38 | */
39 | Thread.State getState();
40 |
41 | /**
42 | * Terminates this pool reducer, which terminates its underlying daemon thread.
43 | * Once terminated the pool reducer cannot be more revived.
44 | */
45 | void terminate();
46 | }
47 |
--------------------------------------------------------------------------------
/src/test/java/org/vibur/objectpool/ConcurrentPoolTest.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright 2013 Simeon Malchev
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.vibur.objectpool;
18 |
19 | import org.junit.jupiter.api.AfterEach;
20 | import org.junit.jupiter.api.Test;
21 | import org.vibur.objectpool.util.ConcurrentLinkedDequeCollection;
22 | import org.vibur.objectpool.util.ConcurrentLinkedQueueCollection;
23 |
24 | import static org.junit.jupiter.api.Assertions.assertEquals;
25 | import static org.junit.jupiter.api.Assertions.assertFalse;
26 | import static org.junit.jupiter.api.Assertions.assertNotNull;
27 | import static org.junit.jupiter.api.Assertions.assertNull;
28 | import static org.junit.jupiter.api.Assertions.assertSame;
29 | import static org.junit.jupiter.api.Assertions.assertThrows;
30 | import static org.junit.jupiter.api.Assertions.assertTrue;
31 | import static org.junit.jupiter.api.Assertions.fail;
32 |
33 | /**
34 | * @author Simeon Malchev
35 | */
36 | public class ConcurrentPoolTest {
37 |
38 | private PoolService