Removed libs/dist and now only have safe object pool (based on ArrayBlockingQueue)

This commit is contained in:
nathan 2016-02-09 17:57:19 +01:00
parent 253a777382
commit 2ae5328856
6 changed files with 48 additions and 340 deletions

View File

@ -11,7 +11,6 @@
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="jdk" jdkName="1.6" jdkType="JavaSDK" />
<orderEntry type="library" name="JCTools (1.4 alpha MTAQ)" level="application" />
<orderEntry type="library" name="junit-4.12" level="application" />
</component>
<component name="org.twodividedbyzero.idea.findbugs">

View File

@ -15,33 +15,74 @@
*/
package dorkbox.util.objectPool;
@SuppressWarnings("ALL")
import java.util.concurrent.ArrayBlockingQueue;
public
interface ObjectPool<T> {
class ObjectPool<T> {
private final ArrayBlockingQueue<T> queue;
private final PoolableObject<T> poolableObject;
ObjectPool(PoolableObject<T> poolableObject, int size) {
this.poolableObject = poolableObject;
this.queue = new ArrayBlockingQueue<T>(size);
for (int x = 0; x < size; x++) {
T e = poolableObject.create();
poolableObject.onReturn(e);
this.queue.add(e);
}
}
/**
* Takes an object from the pool, Blocks until an item is available in the pool.
*/
T take() throws InterruptedException;
public
T take() throws InterruptedException {
final T take = this.queue.take();
poolableObject.onTake(take);
return take;
}
/**
* Takes an object from the pool, Blocks until an item is available in the pool.
* <p/>
* This method catches {@link InterruptedException} and discards it silently.
*/
T takeUninterruptibly();
@SuppressWarnings({"Duplicates", "SpellCheckingInspection"})
public
T takeUninterruptibly() {
try {
T take = take();
return take;
} catch (InterruptedException e) {
return null;
}
}
/**
* Return object to the pool, waking those threads that have blocked during take()
*/
void release(T object);
public
void release(T object) {
poolableObject.onReturn(object);
this.queue.offer(object);
}
/**
* @return a new object instance created by the pool.
*/
T newInstance();
public
T newInstance() {
return poolableObject.create();
}
/**
* @return the number of pooled objects
*/
int size();
public
int size() {
return queue.size();
}
}

View File

@ -1,71 +0,0 @@
/*
* Copyright 2014 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.util.objectPool;
public
class ObjectPoolFactory {
private
ObjectPoolFactory() {
}
/**
* Creates a pool of the specified size. The "Fast/Unsafe" object pool will always have a size rounded up to the nearest power of 2.
*/
public static
<T> ObjectPool<T> create(PoolableObject<T> poolableObject, int size) {
try {
// here we use FAST (via UNSAFE)
UnsafeObjectPool<T> fastObjectPool = new UnsafeObjectPool<T>(poolableObject, size);
return fastObjectPool;
} catch (Throwable ignored) {
// fallback (LinkedBlockingDeque) in case UNSAFE isn't available. (ie: android)
SafeObjectPool<T> slowObjectPool = new SafeObjectPool<T>(poolableObject, size);
return slowObjectPool;
}
}
/**
* Creates an UNSAFE pool of the specified size, rounded up to the nearest power of 2.
*/
public static
<T> ObjectPool<T> createFast(PoolableObject<T> poolableObject, int size) {
// here we use FAST (via UNSAFE)
UnsafeObjectPool<T> fastObjectPool = null;
try {
fastObjectPool = new UnsafeObjectPool<T>(poolableObject, size);
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException("Unable to create a fast object pool, use 'create()' instead. Aborting.", e);
}
return fastObjectPool;
}
/**
* Creates a SAFE pool of the specified size.
*/
public static
<T> ObjectPool<T> createSafe(PoolableObject<T> poolableObject, int size) {
// fallback (LinkedBlockingDeque) in case UNSAFE isn't available. (ie: android)
SafeObjectPool<T> slowObjectPool = new SafeObjectPool<T>(poolableObject, size);
return slowObjectPool;
}
}

View File

@ -1,79 +0,0 @@
/*
* from: https://code.google.com/p/furious-objectpool/
* copyright Eddie Raapoto 2012
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modified by dorkbox, llc
*/
package dorkbox.util.objectPool;
import java.util.concurrent.ArrayBlockingQueue;
class SafeObjectPool<T> implements ObjectPool<T> {
private final ArrayBlockingQueue<T> queue;
private final PoolableObject<T> poolableObject;
SafeObjectPool(PoolableObject<T> poolableObject, int size) {
this.poolableObject = poolableObject;
this.queue = new ArrayBlockingQueue<T>(size);
for (int x = 0; x < size; x++) {
T e = poolableObject.create();
poolableObject.onReturn(e);
this.queue.add(e);
}
}
@Override
public
T take() throws InterruptedException {
final T take = this.queue.take();
poolableObject.onTake(take);
return take;
}
@SuppressWarnings({"Duplicates", "SpellCheckingInspection"})
@Override
public
T takeUninterruptibly() {
try {
T take = take();
return take;
} catch (InterruptedException e) {
return null;
}
}
@Override
public
void release(T object) {
poolableObject.onReturn(object);
this.queue.offer(object);
}
@Override
public
T newInstance() {
return poolableObject.create();
}
@Override
public
int size() {
return queue.size();
}
}

View File

@ -1,132 +0,0 @@
/*
* from: http://ashkrit.blogspot.com/2013/05/lock-less-java-object-pool.html
* https://github.com/ashkrit/blog/tree/master/FastObjectPool
* copyright ashkrit 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Modified by dorkbox, llc
*/
package dorkbox.util.objectPool;
import org.jctools.queues.MpmcArrayQueue;
import org.jctools.util.Pow2;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class UnsafeObjectPool<T> implements ObjectPool<T> {
public static final int FULL_RETRY_LIMIT = 200;
private final MpmcArrayQueue<T> objects;
private final Lock lock = new ReentrantLock();
private final Condition empty = lock.newCondition();
private final PoolableObject<T> poolableObject;
UnsafeObjectPool(final PoolableObject<T> poolableObject, final int size) throws Throwable {
this.poolableObject = poolableObject;
int newSize = Pow2.roundToPowerOfTwo(size);
objects = new MpmcArrayQueue<T>(newSize);
for (int x = 0; x < newSize; x++) {
T e = poolableObject.create();
poolableObject.onReturn(e);
objects.offer(e);
}
}
@Override
public
T take() throws InterruptedException {
T poll = objects.poll();
if (poll == null) {
lock.lock();
try {
while ((poll = objects.poll()) == null) {
empty.await();
}
} finally {
lock.unlock();
}
}
poolableObject.onTake(poll);
return poll;
}
@SuppressWarnings({"Duplicates", "SpellCheckingInspection"})
@Override
public
T takeUninterruptibly() {
try {
final T take = take();
return take;
} catch (InterruptedException e) {
return null;
}
}
@Override
public
void release(T object) {
poolableObject.onReturn(object);
boolean waiting = objects.peek() == null;
// This could potentially happen due to optimistic calculations by the implementation queue.
// From my observations, 1 retry was all that was needed.
if (!objects.offer(object)) {
int limit = FULL_RETRY_LIMIT;
while (!objects.offer(object) && limit-- > 0) {
try {
Thread.sleep(2L);
} catch (InterruptedException ignored) {
}
}
if (limit <= 0) {
throw new RuntimeException("Unable to insert item into object pool. Pool is full, and retry limit exceeded.");
}
}
if (waiting) {
lock.lock();
try {
if (objects.peek() == null) {
// we only need to signal one, since the take/release calls must be symmetric
empty.signal();
}
} finally {
lock.unlock();
}
}
}
@Override
public
T newInstance() {
return poolableObject.create();
}
/**
* This is an optimistic calculation, and if being used by multiple threads, can be inaccurate.
*/
@Override
public
int size() {
return objects.size();
}
}

View File

@ -1,50 +0,0 @@
package dorkbox.util.objectPool;
import org.junit.Test;
/**
*
*/
public
class ObjectPoolFactoryTest {
public static
void main(String[] args) throws Exception {
new ObjectPoolFactoryTest().testCreate();
}
@Test
public
void testCreate() throws Exception {
final ObjectPool<Integer> pool = ObjectPoolFactory.create(new PoolableObject<Integer>() {
int id = 1;
@Override
public
Integer create() {
return this.id++;
}
}, 4);
Integer one = pool.take();
Integer two = pool.take();
Integer three = pool.take();
Integer four = pool.take();
pool.release(one);
pool.release(two);
pool.release(three);
pool.release(four);
one = pool.take();
two = pool.take();
pool.release(one);
pool.release(two);
three = pool.take();
four = pool.take();
one = pool.take();
two = pool.take();
}
}