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)