如果我们要实现一个资源池,比如数据库连接池。您将使用哪个并发集合?BlockingQueue
还是Semaphore
?
因为BlockingQueue
,就像生产者-消费者设计模式一样,生产者将所有连接放在队列中,消费者将从队列中获取下一个可用连接。
对于Semaphore
,您将信号量指定为池大小,并获取许可,直到达到池大小并等待其中任何一个释放许可并将资源放回池中。
哪一个更简单更容易?什么情况下我们只能使用一种而不能使用另一种?
如果我们要实现一个资源池,比如数据库连接池。您将使用哪个并发集合?BlockingQueue
还是Semaphore
?
因为BlockingQueue
,就像生产者-消费者设计模式一样,生产者将所有连接放在队列中,消费者将从队列中获取下一个可用连接。
对于Semaphore
,您将信号量指定为池大小,并获取许可,直到达到池大小并等待其中任何一个释放许可并将资源放回池中。
哪一个更简单更容易?什么情况下我们只能使用一种而不能使用另一种?
BlockingQueue 更简单,因为它也会跟踪连接/资源。
例如
public abstract class ResourcePool<Resource> {
private final BlockingQueue<Resource> free;
protected ResourcePool(int freeLimit) {
free = new ArrayBlockingQueue<>(freeLimit);
}
public Resource acquire() {
Resource resource = free.poll();
return resource == null ? create() : resource;
}
public void recycle(Resource resource) {
if (!free.offer(resource))
close(resource);
}
protected abstract Resource create();
protected abstract void close(Resource resource);
}
如您所见,BlockingQueue 有助于跟踪空闲资源并确保没有太多空闲资源。它是线程安全的,不需要显式锁定。
如果您使用信号量,您仍然需要将资源存储在集合中(使信号量变得多余;)
无论如何,许多阻塞队列都是用信号量实现的(也许是互斥体/futex/CS)。我经常使用阻塞队列来存储对象——一旦你有一个有效的阻塞队列,为什么还要为对象池使用其他任何东西呢?
对于高级连接池,我可能都不会使用。正如@PeterLawrey 指出的那样,BlockingQueue 对于最初存在所有资源的简单池最有意义。但是,如果您想做更复杂的事情,比如按需创建资源,那么您很可能需要额外的并发构造。在这种情况下,您很可能最终会使用一个简单的同步块或 Lock。