[
https://issues.apache.org/jira/browse/POOL-419?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17953944#comment-17953944
]
Raju Gupta commented on POOL-419:
---------------------------------
This is a very key insight. "the sync protections on pooled objects within pool
are to handle contention between client threads and the evictor, not multiple
client threads concurrently invoking lifecycle methods on the same pooled
object.". Thanks for providing this.
I would have liked some benchmark results for this change but I am going to
defer to your expertise for that. Glad to contribute.
> GenericObjectPoolConfig getNumActive return negative value
> ----------------------------------------------------------
>
> Key: POOL-419
> URL: https://issues.apache.org/jira/browse/POOL-419
> Project: Commons Pool
> Issue Type: Bug
> Affects Versions: 2.12.0
> Reporter: john ms
> Priority: Major
> Fix For: 2.12.2
>
>
> We've notice unexpected counting that is return from getNumActive .
> and it means that allObjects and idleObjects are out of sync.
> Calling returnObject and invalidateObject on the same pooled object from two
> different threads is causing getNumActive to return negative value.
> Why two threads are working on the same object at the same time and the real
> running use case is much complex to described and not relevant, I think.
> Bellow is a simple program to demo the behavior
> {*}Expected result{*}:
> getNumActive=0
>
> {*}Actual result{*}:
> getNumActive=\{negative number}
> If it help debugging the RC, I've notice that returnObject is not
> synchronized over pooled object and verify it's status before using it, like
> it's done in invalidateObject.
> {*}Workaround{*}:
> Synchronize the pooled object before calling returnObject/invalidateObject
>
> Java 17
> {code:java}
> public class PoolObject extends BasePooledObjectFactory<PoolObject> {
> @Override
> public PoolObject create() {
> return new PoolObject();
> }
> @Override
> public PooledObject<PoolObject> wrap(PoolObject poolObject) {
> return new DefaultPooledObject<>(poolObject);
> }
> @Override
> public void passivateObject(PooledObject<PoolObject> pooledObject) {
> }
> }{code}
>
> {code:java}
> public static void main (String [] args) throws Exception {
> ExecutorService executor = Executors.newCachedThreadPool();
> GenericObjectPoolConfig<PoolObject> poolConfig = new
> GenericObjectPoolConfig<>();
> poolConfig.setMaxTotal(200000);
> poolConfig.setMaxIdle(200000);
> poolConfig.setMinIdle(200000);
> ObjectPool<PoolObject> objectPool = new GenericObjectPool<>(new
> PoolObject(), poolConfig);
> for (int i=0; i<1000000; i++){
> PoolObject poolObject= objectPool.borrowObject();
> FutureTask invalidateObject = new FutureTask<>(() -> {
> Thread.sleep(RandomUtils.nextInt(0,10));
> //synchronized (poolObject) { // Workaround bug
> objectPool.invalidateObject(poolObject);
> //}
> return true;
> });
> executor.execute(invalidateObject);
> FutureTask returnObject = new FutureTask<>(() -> {
> Thread.sleep(RandomUtils.nextInt(0,10));
> //synchronized (poolObject) { // Workaround bug
> objectPool.returnObject(poolObject);
> //}
> return true;
> });
> executor.execute(returnObject);
> }
> Thread.sleep(2000);
> executor.shutdown();
> System.out.println("getNumActive=" + objectPool.getNumActive());
> }{code}
>
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)