On Fri, Jun 20, 2008 at 10:14 PM, Guillermo Cantu <[EMAIL PROTECTED]>
wrote:
> My problem is that I need a pool manager to control the number of instances
> of
> a 3rd party library that are loaded to service the requests. Each request
> needs
> an instance of the 3rd party library.
>
> So let's say I can service 10 requests at a time. I need to make the other
> requests wait while an instance of the library is freed.
The usual way to restrict access to a bounded pool of resources is with
semaphores:
public class BoundedPool<T> {
private final Semaphore semaphore;
private final Producer<T> producer;
private final Consumer<T> consumer;
public interface Producer<T> {
T produce();
}
public interface Consumer<T> {
void consume(T t);
}
public interface Task<T, V> {
V perform(T t);
}
public BoundedPool(int bound, Producer<T> producer, Consumer<T>
consumer) {
this.semaphore = new Semaphore(bound);
this.producer = producer;
this.consumer = consumer;
}
public <V> V perform(Task<T, V> task) throws InterruptedException {
semaphore.acquire();
try {
T t = producer.produce();
try {
return task.perform(t);
} finally {
consumer.consume(t);
}
} finally {
semaphore.release();
}
}
}
In your case, you would specialize this abstraction to your third party
library resources:
class BoundedThirdPartyLibraryResourcePool
extends BoundedPool<ThirdPartyLibraryResource> {
public BoundedThirdPartyLibraryResourcePool() {
super(
10,
new BoundedPool.Producer<ThirdPartyLibraryResource>() {
public ThirdPartyLibraryResource produce() {
return ThirdPartyLibraryResource.allocate();
}
},
new BoundedPool.Consumer<ThirdPartyLibraryResource>() {
public void consume(ThirdPartyLibraryResource t) {
ThirdPartyLibraryResource.release(t);
}
}
);
}
}
Then you would use it inside your (Restlet) Resource's methods as follows:
int n = pool.perform(new BoundedPool.Task<ThirdPartyLibraryResource,
Integer>() {
public Integer perform(ThirdPartyLibraryResource t) {
// Except presumably you'd do more than just this.
return t.count();
}
});
This would ensure that no more than 10 of your third party library resource
instances were in use at a time.
>From what I've been reading, this can't be easily accomplished. If I use a
> thread pool manager to manage the requests, a response will be
> automatically
> returned when the handle method returns.
>
> So what I'm trying to do is to block the Resource that handles each
> request, in
> the handleGet method, so it won't return until the request has been
> serviced.
I think it's better to throttle the use of these library objects with a
separate abstraction like the one above rather than tie the behavior to the
request handling logic.
The problem now is that when calling wait() inside the handleGet method, the
> other requests are not processed until after that handleGet returns.
>
> As I understand from the documentation, each Resource has it's own thread,
> right? So shouldn't the other requests be handled while the first one is
> waiting?
While it's currently true of Restlet that each Resource instance is confined
to a single thread, this may change in the future, so it would be unwise to
rely too heavily on it.
At any rate, there is no guarantee from the Restlet API itself that requests
will be handled in multiple threads -- they could be handled sequentially
all in a single thread. (They'd still all be confined to a single thread:
the same one.)
> Inside handleGet I'm using:
>
> synchronized (this)
> {
> this.wait();
> }
>
Since Java 5 came out, there is rarely any reason to use raw
Object.wait()/notifyAll(). See Item 69 in *Effective Java, 2nd edition*. I
can't tell from this fragment what you're doing, but I suspect it isn't
right. The correct idiom for waiting is (generalizing slightly):
synchronized (obj) {
while (!conditionHolds(obj)) { // conditionHolds is a predicate on the
state of obj
obj.wait();
}
// condition holds for obj: do what needs to be done
}
You would also need a corresponding call to obj.notifyAll() when the state
of obj changes so that conditionHolds(obj) might have become true.
--tim