首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java并发对象池?

Java并发对象池?
EN

Stack Overflow用户
提问于 2013-02-25 00:07:26
回答 1查看 13.1K关注 0票数 6

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

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

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

我该怎么做呢?如果有一个行之有效的例子,我将不胜感激。

EN

回答 1

Stack Overflow用户

发布于 2013-02-25 00:07:26

这个问题和解决方案是从https://www.dbtsai.com/blog/2013/java-concurrent-dynamic-object-pool-for-non-thread-safe-objects-using-blocking-queue/中总结出来的。

Java并发包中的阻塞队列可以建立并发对象池,ArrayBlockingQueue也支持我们所要求的公平性。在这个实现中,我使用ReentrantLock来控制我们是否可以在池中创建一个新对象。因此,在非动态创建模式(即在构造函数中创建所有对象)中,此锁将始终被锁定;在动态创建模式中,每次只能创建一个对象,因此如果有另一个线程获取该对象,它将从pool.take()获取对象,该对象正在阻塞删除,并将等待队列中的新可用资源。

代码语言:javascript
复制
    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次计算。

代码语言:javascript
复制
    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();
        }
    }
}
票数 17
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15058247

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档