john ms created POOL-419:
----------------------------

             Summary: 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
         Environment:  

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}
 

 

 
            Reporter: john ms


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=-5

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 its done in 
invalidateObject. 

{*}Workaround{*}:

Synchronize the  pooled object before calling returnObject/invalidateObject 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to