java Java并发对象池?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15058247/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Concurrent Object Pool?
提问by DB Tsai
I tried to integrate an external non-thread-safe library to my web project; I found out that it's too expensive to create an instance of this object for each client thread.
我尝试将外部非线程安全库集成到我的 Web 项目中;我发现为每个客户端线程创建这个对象的实例太昂贵了。
As a result, I would like to create an object pool which has the following property.
因此,我想创建一个具有以下属性的对象池。
- Dynamic object creation, the objects in the pool are dynamically created instead of creating them in the constructor. The pool is initially empty, and when a client thread acquires a resource object, the pool can create a new resource on demand. Once the numbers of created objects are reached the size of the pool; then the new client threads will be blocked, and wait for other thread to recycle the resource.
- The pool should be fair, and the fairness ensures that the first thread that asks is the first thread that gets; otherwise there is probability that some threads will just wait forever.
- 动态对象创建,池中的对象是动态创建的,而不是在构造函数中创建。池最初是空的,当客户端线程获取资源对象时,池可以按需创建新资源。一旦创建对象的数量达到池的大小;那么新的客户端线程将被阻塞,并等待其他线程回收资源。
- 池子应该是公平的,公平保证第一个请求的线程是第一个得到的线程;否则,某些线程可能会永远等待。
How can I do it? I will appreciate if there is a working example.
我该怎么做?如果有一个工作示例,我将不胜感激。
回答by DB Tsai
This question and solution are summarized from https://www.dbtsai.com/blog/2013/java-concurrent-dynamic-object-pool-for-non-thread-safe-objects-using-blocking-queue/
The concurrent object pool can be built by the blocking queue in Java concurrent package, and ArrayBlockingQueue also supports fairness which we require. In this implementation, I use ReentrantLock to control if we can create a new object in the pool or not. As a result, in the non dynamic creation mode i.e., creating all the objects in the constructor, this lock will always be locked; in the dynamic creation mode, in each time, only one object can be created, so if there is another thread acquiring this object, it will get the object from pool.take() which is blocking remove, and will wait for a new available resource in the queue.
并发对象池可以通过Java并发包中的阻塞队列来构建,ArrayBlockingQueue也支持我们所要求的公平性。在这个实现中,我使用 ReentrantLock 来控制我们是否可以在池中创建一个新对象。因此,在非动态创建模式下,即在构造函数中创建所有对象,这个锁会一直被锁住;在动态创建模式下,每次只能创建一个对象,所以如果有另一个线程获取这个对象,它会从阻塞remove的pool.take()中获取该对象,并等待一个新的可用队列中的资源。
public abstract class ResourcePool {
????private final BlockingQueue pool;
????private final ReentrantLock lock = new ReentrantLock();
????private int createdObjects = 0;
????private int size;
?
????protected ResourcePool(int size) {
????????this(size, false);
????}
?
????protected ResourcePool(int size, Boolean dynamicCreation) {
????????// Enable the fairness; otherwise, some threads
????????// may wait forever.
????????pool = new ArrayBlockingQueue<>(size, true);
????????this.size = size;
????????if (!dynamicCreation) {
????????????lock.lock();
????????}
????}
?
????public Resource acquire() throws Exception {
????????if (!lock.isLocked()) {
????????????if (lock.tryLock()) {
????????????????try {
????????????????????++createdObjects;
????????????????????return createObject();
????????????????} finally {
????????????????????if (createdObjects < size) lock.unlock();
????????????????}
????????????}
????????}
????????return pool.take();
????}
?
????public void recycle(Resource resource) throws Exception {
????????// Will throws Exception when the queue is full,
????????// but it should never happen.
????????pool.add(resource);
????}
?
????public void createPool() {
????????if (lock.isLocked()) {
????????????for (int i = 0; i < size; ++i) {
????????????????pool.add(createObject());
????????????????createdObjects++;
????????????}
????????}
????}
?
????protected abstract Resource createObject();
}
In the following example, there are 5 client threads simultaneously acquiring two DataTimeFormat objects in resource pool, and those client threads will do 30 computations in total.
在下面的例子中,有 5 个客户端线程同时获取资源池中的两个 DataTimeFormat 对象,这些客户端线程总共会做 30 次计算。
class DataTimeFormatResourcePool extends ResourcePool<SimpleDateFormat> {
?
????DataTimeFormatResourcePool(int size, Boolean dynamicCreation) {
????????super(size, dynamicCreation);
????????createPool();
????}
?
????@Override
????protected SimpleDateFormat createObject() {
????????return new SimpleDateFormat("yyyyMMdd");
????}
?
????public Date convert(String input) throws Exception {
????????SimpleDateFormat format = acquire();
????????try {
????????????return format.parse(input);
????????} finally {
????????????recycle(format);
????????}
????}
}
?
public class ResourcePoolExample {
????public static void main(String args[]) {
????????final DataTimeFormatResourcePool pool = new DataTimeFormatResourcePool(2, true);
?
????????Callable<Date> task = new Callable<Date>() {
????????????@Override
????????????public Date call() throws Exception {
????????????????return pool.convert("20130224");
????????????}
????????};
?
????????ExecutorService exec = Executors.newFixedThreadPool(5);
????????List<Future<Date>> results = new ArrayList<>();
?
????????for (int i = 0; i < 30; i++) {
????????????results.add(exec.submit(task));
????????}
????????exec.shutdown();
????????try {
????????????for (Future<Date> result : results) {
????????????????System.out.println(result.get());
????????????}
????????} catch (Exception ex) {
????????????ex.printStackTrace();
????????}
????}
}