Java并发对象池?
我尝试将外部非线程安全库集成到我的Web项目中; 我发现为每个客户端线程创建此对象的实例太昂贵了。
因此,我想创建一个具有以下属性的对象池。
- 动态对象创建时,动态创建池中的对象,而不是在构造函数中创建它们。 池最初为空,当客户端线程获取资源对象时,池可以按需创建新资源。 一旦创建的对象的数量达到池的大小; 然后将阻止新的客户端线程,并等待其他线程回收资源。
- 池应该是公平的,公平性确保第一个要求的线程是获得的第一个线程; 否则有些线程可能会永远等待。
我该怎么做? 如果有一个有效的例子,我将不胜感激。
这个问题和解决方案总结自https://www.dbtsai.com/blog/2013/java-concurrent-dynamic-object-pool-for-non-thread-safe-objects-using-blocking-queue/
并发对象池可以由Java并发包中的阻塞队列构建,而ArrayBlockingQueue也支持我们需要的公平性。 在此实现中,我使用ReentrantLock来控制是否可以在池中创建新对象。 因此,在非动态创建模式中,即在构造函数中创建所有对象,此锁将始终被锁定; 在动态创建模式中,每次只能创建一个对象,所以如果有另一个线程获取该对象,它将从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 { 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 task = new Callable () { @Override public Date call() throws Exception { return pool.convert("20130224"); } }; ExecutorService exec = Executors.newFixedThreadPool(5); List> results = new ArrayList<>(); for (int i = 0; i < 30; i++) { results.add(exec.submit(task)); } exec.shutdown(); try { for (Future result : results) { System.out.println(result.get()); } } catch (Exception ex) { ex.printStackTrace(); } } }