Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Concurrent Object Pool?

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.

As a result, I would like to create an object pool which has the following property.

  1. 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.
  2. 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.

like image 912
DB Tsai Avatar asked Feb 25 '13 00:02

DB Tsai


People also ask

What is object pooling in Java?

An object pool is a collection of a particular object that an application will create and keep on hand for those situations where creating each instance is expensive. A good example would be a database connection or a worker thread. The pool checks instances in and out for users like books out of a library.

What is the advantage of object pool design patterns?

Advantage of Object Pool design patternIt is most effective in a situation where the rate of initializing a class instance is high. It manages the connections and provides a way to reuse and share them. It can also provide the limit for the maximum number of objects that can be created.

What is the benefit of object pooling?

Benefits. Object pooling can offer a significant performance boost in situations where the cost of initializing a class instance is high and the rate of instantiation and destruction of a class is high – in this case objects can frequently be reused, and each reuse saves a significant amount of time.

What is object pooling in Ado net?

ObjectPool is part of the ASP.NET Core infrastructure that supports keeping a group of objects in memory for reuse rather than allowing the objects to be garbage collected. You might want to use the object pool if the objects that are being managed are: Expensive to allocate/initialize.


1 Answers

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.

    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.

    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();
        }
    }
}
like image 175
DB Tsai Avatar answered Sep 28 '22 09:09

DB Tsai