[
https://issues.apache.org/jira/browse/POOL-231?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13508945#comment-13508945
]
Thomas Neidhart commented on POOL-231:
--------------------------------------
I think the proposed change is correct:
it will require two lookups in the allObjects map for the nominal case, but
otoh will only need synchronization on the pooled object itself rather than the
map.
> GOP, GKOP invalidateObject is not threadsafe
> --------------------------------------------
>
> Key: POOL-231
> URL: https://issues.apache.org/jira/browse/POOL-231
> Project: Commons Pool
> Issue Type: Bug
> Affects Versions: Nightly Builds
> Reporter: Phil Steitz
> Fix For: 2.0
>
>
> There does not appear to be sufficient sync protection for the destroyCount
> and createCount counters when destroy is activated by invalidateObject in
> GOP, GKOP, v2 trunk. The test below fails when added to GOP tests. The
> destroyCount is over-incremented due (I think) to the fact that multiple
> threads can enter destroy before the object being invalidated is removed from
> allObjects. This problem was originally reported by Thomas Neidhart in a
> comment on POOL-213.
> {code}
> @Test
> public void testConcurrentInvalidate() throws Exception {
> // Get allObjects and idleObjects loaded with some instances
> final int nObjects = 1000;
> pool.setMaxTotal(nObjects);
> pool.setMaxIdle(nObjects);
> final Object[] obj = new Object[nObjects];
> for (int i = 0; i < nObjects; i++) {
> obj[i] = pool.borrowObject();
> }
> for (int i = 0; i < nObjects; i++) {
> if (i % 2 == 0) {
> pool.returnObject(obj[i]);
> }
> }
> final int nThreads = 100;
> final int nIterations = 100;
> final InvalidateThread[] threads = new InvalidateThread[nThreads];
> // Randomly generated list of distinct invalidation targets
> final ArrayList<Integer> targets = new ArrayList<Integer>();
> final Random random = new Random();
> for (int j = 0; j < nIterations; j++) {
> // Get a new invalidation target
> Integer targ = new Integer(random.nextInt(nObjects));
> while (targets.contains(targ)) {
> targ = new Integer(random.nextInt(nObjects));
> }
> targets.add(targ);
> // Launch nThreads threads all trying to invalidate the target
> for (int i = 0; i < nThreads; i++) {
> threads[i] = new InvalidateThread(pool, obj[targ]);
> }
> for (int i = 0; i < nThreads; i++) {
> new Thread(threads[i]).start();
> }
> boolean done = false;
> while (!done) {
> done = true;
> for (int i = 0; i < nThreads; i++) {
> done = done && threads[i].complete();
> }
> Thread.sleep(100);
> }
> }
> Assert.assertEquals(nIterations, pool.getDestroyedCount());
> }
>
> static class InvalidateThread implements Runnable {
> final private Object obj;
> final private ObjectPool<Object> pool;
> private boolean done = false;
> public InvalidateThread(ObjectPool<Object> pool, Object obj) {
> this.obj = obj;
> this.pool = pool;
> }
> public void run() {
> try {
> pool.invalidateObject(obj);
> } catch (IllegalStateException ex) {
> // Ignore
> } catch (Exception ex) {
> Assert.fail("Unexpected exception " + ex.toString());
> } finally {
> done = true;
> }
> }
> public boolean complete() {
> return done;
> }
> }
> {code}
--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira