You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@commons.apache.org by "Codievilky August (Jira)" <ji...@apache.org> on 2020/12/16 09:13:00 UTC
[jira] [Updated] (POOL-391) GenericKeyedObjectPool is not thread
safe when invoke method `borrowObject` and `destroy` simultaneously
[ https://issues.apache.org/jira/browse/POOL-391?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Codievilky August updated POOL-391:
-----------------------------------
Description:
The method `brrowObject` is not thread safe with `destroy` or `clear` method.
The reason is when use GenericKeyedObjectPool#destroy method,it did not ensure the *Atomicity* of destroy object from the ObjectDeque。
This may cause in the GenericKeyedObjectPool#borrowObject method,may get the wrong number of GenericKeyedObjectPool.ObjectDeque#getCreateCount when need to create. And the GenericKeyedObjectPool#borrowObject will block until timeout.
Here is the sample test code to recur the bug:
{code:java}
// code placeholder
public class CommonPoolMultiThreadTest {
public static void main(String[] args) {
GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
config.setMaxTotalPerKey(1);
config.setMinIdlePerKey(0);
config.setMaxIdlePerKey(-1);
config.setMaxTotal(-1);
config.setMaxWaitMillis(TimeUnit.SECONDS.toMillis(5));
GenericKeyedObjectPool<Integer, Integer> testPool = new GenericKeyedObjectPool<>(
new KeyedPooledObjectFactory<Integer, Integer>() {
@Override
public PooledObject<Integer> makeObject(Integer key) throws Exception {
System.out.println("start to create");
return new DefaultPooledObject<>(10);
} @Override
public void destroyObject(Integer key, PooledObject<Integer> p) throws Exception {
System.out.println("start to destroy");
Thread.sleep(2000);
} @Override
public boolean validateObject(Integer key, PooledObject<Integer> p) {
return true;
} @Override
public void activateObject(Integer key, PooledObject<Integer> p) throws Exception {
// do nothing
} @Override
public void passivateObject(Integer key, PooledObject<Integer> p) throws Exception {
// do nothing
}
}, config
);
int borrowKey = 10;
Thread t = new Thread(() -> {
try {
while (true) {
Integer integer = testPool.borrowObject(borrowKey);
testPool.returnObject(borrowKey, integer);
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
});
Thread t2 = new Thread(() -> {
try {
while (true) {
testPool.clear(borrowKey);
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
});
t.start();
t2.start();
}
}
{code}
was:
The method `brrowObject` is not thread safe with `destroy` or `clear` method.
The reason is when use GenericKeyedObjectPool#destroy method,it did not ensure the *Atomicity* of destroy object from the ObjectDeque。
This may cause in the GenericKeyedObjectPool#borrowObject method,may get the wrong number of GenericKeyedObjectPool.ObjectDeque#getCreateCount when need to create. And the GenericKeyedObjectPool#borrowObject will block until timeout.
Here is the sample test code to recur the bug:
{code:java}
// code placeholder
public class CommonPoolMultiThreadTest {
public static void main(String[] args) {
GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
config.setMaxTotalPerKey(1);
config.setMinIdlePerKey(0);
config.setMaxIdlePerKey(-1);
config.setMaxTotal(-1);
config.setMaxWaitMillis(TimeUnit.SECONDS.toMillis(5));
GenericKeyedObjectPool<Integer, Integer> testPool = new GenericKeyedObjectPool<>(
new KeyedPooledObjectFactory<Integer, Integer>() {
@Override
public PooledObject<Integer> makeObject(Integer key) throws Exception {
System.out.println("start to create");
return new DefaultPooledObject<>(10);
} @Override
public void destroyObject(Integer key, PooledObject<Integer> p) throws Exception {
System.out.println("start to destroy");
Thread.sleep(2000);
} @Override
public boolean validateObject(Integer key, PooledObject<Integer> p) {
return true;
} @Override
public void activateObject(Integer key, PooledObject<Integer> p) throws Exception {
// do nothing
} @Override
public void passivateObject(Integer key, PooledObject<Integer> p) throws Exception {
// do nothing
}
}, config
);
int borrowKey = 10;
Thread t = new Thread(() -> {
try {
while (true) {
testPool.borrowObject(borrowKey);
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
});
Thread t2 = new Thread(() -> {
try {
while (true) {
testPool.clear(borrowKey);
Thread.sleep(10);
}
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
});
t.start();
t2.start();
}
}
{code}
> GenericKeyedObjectPool is not thread safe when invoke method `borrowObject` and `destroy` simultaneously
> ---------------------------------------------------------------------------------------------------------
>
> Key: POOL-391
> URL: https://issues.apache.org/jira/browse/POOL-391
> Project: Commons Pool
> Issue Type: Bug
> Affects Versions: 2.4.2, 2.5.0, 2.6.0, 2.7.0, 2.8.0, 2.9.0
> Reporter: Codievilky August
> Priority: Blocker
> Original Estimate: 24h
> Remaining Estimate: 24h
>
> The method `brrowObject` is not thread safe with `destroy` or `clear` method.
> The reason is when use GenericKeyedObjectPool#destroy method,it did not ensure the *Atomicity* of destroy object from the ObjectDeque。
> This may cause in the GenericKeyedObjectPool#borrowObject method,may get the wrong number of GenericKeyedObjectPool.ObjectDeque#getCreateCount when need to create. And the GenericKeyedObjectPool#borrowObject will block until timeout.
> Here is the sample test code to recur the bug:
> {code:java}
> // code placeholder
> public class CommonPoolMultiThreadTest {
> public static void main(String[] args) {
> GenericKeyedObjectPoolConfig config = new GenericKeyedObjectPoolConfig();
> config.setMaxTotalPerKey(1);
> config.setMinIdlePerKey(0);
> config.setMaxIdlePerKey(-1);
> config.setMaxTotal(-1);
> config.setMaxWaitMillis(TimeUnit.SECONDS.toMillis(5));
> GenericKeyedObjectPool<Integer, Integer> testPool = new GenericKeyedObjectPool<>(
> new KeyedPooledObjectFactory<Integer, Integer>() {
> @Override
> public PooledObject<Integer> makeObject(Integer key) throws Exception {
> System.out.println("start to create");
> return new DefaultPooledObject<>(10);
> } @Override
> public void destroyObject(Integer key, PooledObject<Integer> p) throws Exception {
> System.out.println("start to destroy");
> Thread.sleep(2000);
> } @Override
> public boolean validateObject(Integer key, PooledObject<Integer> p) {
> return true;
> } @Override
> public void activateObject(Integer key, PooledObject<Integer> p) throws Exception {
> // do nothing
> } @Override
> public void passivateObject(Integer key, PooledObject<Integer> p) throws Exception {
> // do nothing
> }
> }, config
> );
> int borrowKey = 10;
> Thread t = new Thread(() -> {
> try {
> while (true) {
> Integer integer = testPool.borrowObject(borrowKey);
> testPool.returnObject(borrowKey, integer);
> Thread.sleep(10);
> }
> } catch (Exception e) {
> e.printStackTrace();
> System.exit(1);
> }
> });
> Thread t2 = new Thread(() -> {
> try {
> while (true) {
> testPool.clear(borrowKey);
> Thread.sleep(10);
> }
> } catch (Exception e) {
> e.printStackTrace();
> System.exit(1);
> }
> });
> t.start();
> t2.start();
> }
> }
> {code}
>
--
This message was sent by Atlassian Jira
(v8.3.4#803005)