【问题标题】:Java Concurrent Object Pool?Java并发对象池?
【发布时间】:2013-02-10 01:57:48
【问题描述】:

我尝试将外部非线程安全库集成到我的 Web 项目中;我发现为每个客户端线程创建这个对象的实例太昂贵了。

因此,我想创建一个具有以下属性的对象池。

  1. 动态对象创建,池中的对象是动态创建的,而不是在构造函数中创建。池最初是空的,当客户端线程获取资源对象时,池可以按需创建新资源。一旦创建的对象数量达到池的大小;然后新的客户端线程将被阻塞,并等待其他线程回收资源。
  2. 池应该是公平的,公平保证第一个请求的线程是第一个得到的线程;否则有可能某些线程将永远等待。

我该怎么做?如果有工作示例,我将不胜感激。

【问题讨论】:

    标签: java concurrency thread-safety threadpool java.util.concurrent


    【解决方案1】:

    这个问题和解决方法总结自https://www.dbtsai.com/blog/2013/java-concurrent-dynamic-object-pool-for-non-thread-safe-objects-using-blocking-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();
        }
    

    在下面的例子中,有 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();
            }
        }
    }
    

    【讨论】:

    • 链接现在不可用
    猜你喜欢
    • 2016-05-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    • 2019-09-29
    • 2015-03-27
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多