Reputation: 631
This question is related to my homework assignment in Java concurrency topic. I have been tasked to spawn new threads and limit them by a given concurrencyFactor
. That is, keep on dispatching new threads until number of active threads is less than or equal to concurrencyFactor
. If the number of active threads is equal to concurrencyFactor
, program will wait until number of active threads reduce to concurrencyFactor - 1
and create a new one.
As a first approach, I am using ExecutorService
and created a new fixed pool by Executors.newFixedThreadPool(concurrencyFactor);
and whenever my method is called, I am just submitting a new runnable to this pool. Code for the logic is below:
private final ExecutorService fixedPoolExecutor = Executors.newFixedThreadPool(concurrencyFactor);
public void handleRequest(final RequestHandler handler) {
if (handler == null) throw new IllegalArgumentException("Handler cannot be null");
fixedPoolExecutor.submit(new Runnable() {
@Override
public void run() {
handler.serviceRoutine();
}
});
}
Now, the second part asks me to achieve the same goal but without using executor. I have thought of following two approaches:
1) Use countDownLatch
but this latch would wait(i.e. latch.await()
) until activeCount
becomes 0
. I want to wait only till the countDown becomes concurrencyFactor - 1
.
2) Use ThreadGroup
and wait until threadGroup.activeCount() < concurrencyFactor
. But, the problem with this approach is how can I make the incoming request wait until the condition threadGroup.activeCount() < concurrencyFactor
meets? I have used the below code for this approach:
private final Lock lock = new ReentrantLock();
private final ThreadGroup threadGroup = new ThreadGroup("myGroup");
public void handleRequest(final RequestHandler handler) {
if (handler == null) throw new IllegalArgumentException("Handler cannot be null");
lock.lock();
try {
while (threadGroup.activeCount() >= concurrencyFactor) {
}
Thread t = new Thread(threadGroup, new Runnable() {
@Override
public void run() {
handler.service();
}
});
t.start();
} finally {
lock.unlock();
}
}
Can I replace the blank while loop with some wait condition in the second approach?
Any suggestions on above approaches or advice for any new approach would be appreciated.
Upvotes: 0
Views: 159
Reputation: 11280
I would suggest using Sempahore
. The semaphore would represent the number of threads still allowed to be started. Initially it holds permits equal to the configured concurrency factor.
Before starting a new thread, the handleRequest method needs to acquire a permit from the semaphore. The threads that are started should, upon completion release that permit again.
Sample code :
private final ThreadGroup threadGroup = new ThreadGroup("myGroup");
private final Semaphore concurrencyFactor = new Semaphore(CONCURRENCY_FACTOR);
public void handleRequest(final RequestHandler handler) throws InterruptedException {
if (handler == null) throw new IllegalArgumentException("Handler cannot be null");
concurrencyFactor.acquire(); // Get permit
Thread t = new Thread(threadGroup, new Runnable() {
@Override
public void run() {
try {
handler.service();
} finally {
concurrencyFactor.release(); // make sure to release permit
}
}
});
t.start();
}
(you may want to deal differently with possible interruption)
Upvotes: 1