Best Queue Consumer implementation in Java - java

Good day!
I want to make an ExecutorService consumers for taking data from queue and working with it on server side. The idea is - I poll queue from time to time and if I see that it is not empty I start ExecutorService with N threads (lets say 5). Then I w8 while queue will be empty and shutdown threads. And all again - poll queue for data....
Is this alg ok? Or may be there are some ready implementations/frameworks for such task?
I found this implementation of ConcurrentQueue cunsumers :
public class ConcurrentQueueClient implements Runnable {
private Queue<String> concurrentQueue;
public ConcurrentQueueClient(Queue concurrentQueue) {
this.concurrentQueue = concurrentQueue;
}
public void run() {
boolean stopCondition = (concurrentQueue.size() == 0);
while (!stopCondition) {
for (int i = 0; i < concurrentQueue.size(); i++) {
System.out.println("Client dequeue item "
+ concurrentQueue.poll());
}
stopCondition = (concurrentQueue.size() == 0);
}
System.out.println("Client thread exiting...");
}
}
and testing it in such way :
Queue<String> queue = new ConcurrentLinkedQueue<String>();
ExecutorService consumers = null;
while(true) {
if(queue.size() != 0) {
consumers = Executors.newFixedThreadPool(100);
for (int i = 0; i < 5; i++) {
ConcurrentQueueClient client = new ConcurrentQueueClient(queue);
consumers.execute(client);
}
}
while (queue.size() != 0) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
consumers.shutdown();
try {
consumers.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Start over.
Wrap your strings in callable or runnable, and queue those to the executor service.
If you have a finite set of data to process, then it's ok to have the main thread calling consumer.shutdown() and consumer.awaitTermination(...) as before, but no sleep loop. If you are going to process indefinitely from the queue, then no shutdown() until the service is.
You will face memory issues too if you don't have a limited blocking queue (nothing to block queue.put()). An ArrayBlockingQueue can be given to the executor service on creation (see ThreadPoolExecutor(...) )
Executor service's threads are doing that check (queue.take()) of the tasks queue by design. Try to avoid polling, it waste CPU. Always try to wait/notify (or await/signal) on conditions from reentrantlocks (which is all taken care of for you in the executor service code)

Related

How to stop execution when working queue is empty and all threads have stopped working?

While writing a state-space search like algorithm, I have a working queue with node elements. I have multiple threads with access to that queue that pop an element, do some transformations and checks to it, and may add more nodes to be visited to the queue.
I want the program to stop whenever the queue is empty, and all threads have stopped working (since they could add more elements in which case we would need the other threads to help handling these new nodes).
How should I go about making that check? I was currently thinking keeping some AtomicBitSet, keeping track of which threads are working and which are not, and stop execution when the bitset is empty. I would set and unset with the following, in the run method of my handlers
while (!bitset.isAllUnset()) {
Node node = queue.poll();
if (node == null) {
bitset.unset(THREAD_INDEX);
} else {
bitset.set(THREAD_INDEX);
// HANDLE THE NODE
}
}
Is there any recommended method to go about this?
What you could do is the following approach:
Create a ThreadPool and push the initial Task to your Queue.
Keep one Thread (you main Thread) as a Monitor on the ThreadPool.
The job of this Thread is to start new Threads as long as the Queue is not empty, the Thread Pool still has capacity left and give them their Task.
A Thread that is started will do its job and writes the results back to the queue.
Afterwards it is returned to the pool and you will have to wake up your Monitor.
Your Main Thread will then try to start a new thread as long as the Thread Pool has not reached is limit and the Task Queue is not empty.
Use an ExecutorService to which you submit the Runnables that read the queue and which stop running when the queue is empty.
Then call the executor service 's awaitTermination() method which will block until all threads are finished.
Or use CompletableFuture:
CompleteableFuture.allOf(
CompleteableFuture.runAsync(
() -> while(!queue.isEmpty()) handle(queue.poll())
));
I think this is actually rather complicated. I do not know how to write a correct version using a set based approach. For example, the following approach is wrong:
public class ThreadsStopWorkingWrong {
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
ConcurrentHashMap activeThreads = new ConcurrentHashMap();
volatile int prozessedCount = 0;
volatile boolean stop = false;
#Interleave(group = ThreadsStopWorkingWrong.class, threadCount = 1)
public void readFromQueue() {
int prozessAdditionalElements = 1;
while (!stop) {
Object element = queue.poll();
if (element != null) {
activeThreads.put(Thread.currentThread(), "");
if (prozessAdditionalElements > 0) {
prozessAdditionalElements--;
queue.offer("2");
}
prozessedCount++;
} else {
activeThreads.remove(Thread.currentThread());
}
}
}
#Interleave(group = ThreadsStopWorkingWrong.class, threadCount = 1)
public void waitTillProzessed() throws InterruptedException {
while (!queue.isEmpty() && !activeThreads.isEmpty()) {
Thread.sleep(1);
}
assertEquals(2, prozessedCount);
}
#Test
public void test() throws InterruptedException {
queue.offer("1");
Thread worker = new Thread(() -> readFromQueue());
worker.start();
waitTillProzessed();
worker.join();
}
}
The problem is that when you poll the message out of the queue you have not yet added the thread to the activated set so !queue.isEmpty() && !activeThreads.isEmpty() becomes true. What works is using a message counter as in the following example:
public class ThreadsStopWorkingCorrect {
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
AtomicLong messageCount = new AtomicLong();
volatile int prozessedCount = 0;
volatile boolean stop = false;
#Interleave(group = ThreadsStopWorkingCorrect.class, threadCount = 1)
public void readFromQueue() {
int prozessAdditionalElements = 1;
while (!stop) {
Object element = queue.poll();
if (element != null) {
if (prozessAdditionalElements > 0) {
prozessAdditionalElements--;
queue.offer("2");
messageCount.incrementAndGet();
}
prozessedCount++;
messageCount.decrementAndGet();
}
}
}
#Interleave(group = ThreadsStopWorkingCorrect.class, threadCount = 1)
public void waitTillProzessed() throws InterruptedException {
while (messageCount.get() > 0) {
Thread.sleep(1);
}
assertEquals(2, prozessedCount);
}
#Test
public void test() throws InterruptedException {
queue.offer("1");
messageCount.incrementAndGet();
Thread worker = new Thread(() -> readFromQueue());
worker.start();
waitTillProzessed();
worker.join();
}
}
I tested both the example with vmlens, a tool I wrote to test multithreaded software. Therefore the Interleave annotations.
In the set-based version, some thread interleavings lead to prozessedCount==0.
In the counter-based version, the prozessedCount is always 2.

Does threads of ThreadPoolExecutor not runs concurrently using with PriorityBlockingQueue

I am using java ThreadPoolExecutor to run concurrent thread execution. I used ArrayBlockingQueue to keep threads in queue. But now requirement has changed and I need to add thread run time(no size limit) and it should be prioritized.
So i decided to use PriorityBlockingQueue instead of ArrayBlockingQueue with some comparison Logic.
After using PriorityBlockingQueue, threads are running sequentially one after one not concurrently. Only one thread run at a time, rather than whatever the active thread count will be.
Please let me know if anybody have any suggestions to resolve this issue and achieve my requirement(thread should be added in pool at run time and it execution should be based on priority).
My demo code:
//RejectedExecutionHandler implementation
RejectedExecutionHandlerImpl rejectionHandler = new RejectedExecutionHandlerImpl();
//Get the ThreadFactory implementation to use
BlockingQueue<Runnable> queue = new PriorityBlockingQueue<Runnable>(50, ThreadComparator.getComparator());
ThreadPoolExecutor executorPool = new ThreadPoolExecutor(1, activeThread, 10, TimeUnit.SECONDS, queue, threadFactory, rejectionHandler);
//start the monitoring thread
MyMonitorThread monitor = new MyMonitorThread(executorPool, 20, "Demo");
Thread monitorThread = new Thread(monitor);
monitorThread.start();
for (int i = 0; i < totalThead; i++) {
int prio = i % 3 == 0 ? 3 : 5;
executorPool.execute(new MyThread("Thread-" + i, prio));
}
// Inserting more threads in between concurrent execution.
try {
Thread.sleep(40000);
for (int j = 101; j < 110; j++) {
executorPool.execute(new MyThread("Thread-" + j, 2));
}
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(executorPool.getActiveCount() != 0) {
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Error while thread sleeping: " + e);
}
}
//shut down the pool
executorPool.shutdown();
//shut down the monitor thread
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
System.out.println("Error while thread sleeping: " + e);
}
monitor.shutdown();
public abstract class ThreadComparator implements Comparator<Runnable>{
public static Comparator<Runnable> getComparator() {
return new Comparator<Runnable>() {
#Override
public int compare(Runnable t1, Runnable t2) {
CompareToBuilder compare = new CompareToBuilder();
MyThread mt1 = (MyThread) t1;
MyThread mt2 = (MyThread) t2;
compare.append(mt1.getPriority(), mt2.getPriority());
return compare.toComparison();
}
};
}
}
This is the expected behaviour of ThreadPoolExecutor with an unbounded work queue.
To cite the ThreadPoolExecutor JavaDoc:
Core and maximum pool sizes
A ThreadPoolExecutor will automatically adjust the pool size [..].
When a new task is submitted in method execute(Runnable), and fewer
than corePoolSize threads are running, a new thread is created to
handle the request, even if other worker threads are idle. If there
are more than corePoolSize but less than maximumPoolSize threads
running, a new thread will be created only if the queue is full. [...]
Since you define corePoolSize as 1 and a PriorityBlockingQueue is essentially an unbounded queue (that can never become full), you will never have more than one thread.
The fix is to adjust the corePoolSize to the required number of threads.

How to process contents from large text file using multiple threads?

I have to read a huge file contains text, around 3GB (and 40 Million lines). Just reading it happens really fast:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
while ((line = br.readLine()) != null) {
//Nothing here
}
}
With each read line from above code i do some parsing on the string and process it further.(a huge task). I try to do that multiple threads.
A) I have tried BlockingQueue like this
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
BlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
int numThreads = 5;
Consumer[] consumer = new Consumer[numThreads];
for (int i = 0; i < consumer.length; i++) {
consumer[i] = new Consumer(queue);
consumer[i].start();
}
while ((line = br.readLine()) != null) {
queue.put(line);
}
queue.put("exit");
} catch (FileNotFoundException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException | InterruptedException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
class Consumer extends Thread {
private final BlockingQueue<String> queue;
Consumer(BlockingQueue q) {
queue = q;
}
public void run() {
while (true) {
try {
String result = queue.take();
if (result.equals("exit")) {
queue.put("exit");
break;
}
System.out.println(result);
} catch (InterruptedException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
This approach took more time than normal single threaded processing.
I am not sure why - what am I doing wrong?
B) I have tried ExecutorService:
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
ExecutorService pool = Executors.newFixedThreadPool(10);
while ((line = br.readLine()) != null) {
pool.execute(getRunnable(line));
}
pool.shutdown();
} catch (FileNotFoundException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ReadFileTest.class.getName()).log(Level.SEVERE, null, ex);
}
private static Runnable getRunnable(String run){
Runnable task = () -> {
System.out.println(run);
};
return task;
}
This approach also takes more time than printing directly inside while loop. What am I doing wrong?
What is the correct way to do it?
How can I efficiently process the read line with multiple threads?
Answering one part here - why is the BlockingQueue option slower.
It is important to understand that threads don't come for "free". There is always certain overhead required to get them up and "manage" them.
And of course, when you are actually using more threads than your hardware can support "natively" then context switching is added to the bill.
Beyond that, also the BlockingQueue doesn't come free either. You see, in order to preserve order, that ArrayBlockingQueue probably has to synchronize somewhere. Worst case, that means locking and waiting. Yes, the JVM and JIT are usually pretty good about such things; but again, a certain "percentage" gets added to the bill.
But just for the record, that shouldn't matter. From the javadoc:
This class supports an optional fairness policy for ordering waiting producer and consumer threads. By default, this ordering is not guaranteed. However, a queue constructed with fairness set to true grants threads access in FIFO order. Fairness generally decreases throughput but reduces variability and avoids starvation.
As you are not setting "fairness"
BlockingQueue queue = new ArrayBlockingQueue<>(100);
that shouldn't affect you. On the other hand: I am pretty sure you expected those lines to be processed in order, so you would actually want to go for
BlockingQueue<String> queue = new ArrayBlockingQueue<>(100, true);
and thereby further slowing down the whole thing.
Finally: I agree with the comments given so far. Benchmarking such things is a complex undertaking; and many aspects influence the results. The most important question is definitely: where is your bottle neck?! Is it IO performance (then more threads don't help much!) - or is it really overall processing time (and then the "correct" number of threads for processing should definitely speed up things).
And regarding "how to do this in the correct way" - I suggest to check out this question on softwareengineering.SE.
How to process contents from large text file using multiple threads?
If your computer has enough RAM, I would do the following:
read the entire file into a variable (an ArrayList for example) - using only one thread to read the whole file.
then launch one ExecutorService (with a thread pool that uses no more than the maximum number of cores that your computer can run simultaneously)
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService executorService = Executors.newFixedThreadPool(cores);
finally, divide the lines read, among a limited number of callables/runnables and submit those callables/runnables to your ExecutorService (so all of them can execute simultaneously in your ExecutorService).
unless your processing of lines uses I/O, I assume that you will reach near 100% CPU utilization, and none of your threads will be in waiting state.
do you want even faster processing?
scale vertically is the easiest option: buy even more RAM, better CPU (with more cores), use a Solid State Drive
May be all thread accessing same shared resource concurrently so result more contentious.
One thing you can try reader thread put all line in single key do submit in partition way so it will less contentious.
public void execute(Runnable command) {
final int key= command.getKey();
//Some code to check if it is runing
final int index = key != Integer.MIN_VALUE ? Math.abs(key) % size : 0;
workers[index].execute(command);
}
Create worker with queue so that if you want some task required sequentially then run.
private final AtomicBoolean scheduled = new AtomicBoolean(false);
private final BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(maximumQueueSize);
public void execute(Runnable command) {
long timeout = 0;
TimeUnit timeUnit = TimeUnit.SECONDS;
if (command instanceof TimeoutRunnable) {
TimeoutRunnable timeoutRunnable = ((TimeoutRunnable) command);
timeout = timeoutRunnable.getTimeout();
timeUnit = timeoutRunnable.getTimeUnit();
}
boolean offered;
try {
if (timeout == 0) {
offered = workQueue.offer(command);
} else {
offered = workQueue.offer(command, timeout, timeUnit);
}
} catch (InterruptedException e) {
throw new RejectedExecutionException("Thread is interrupted while offering work");
}
if (!offered) {
throw new RejectedExecutionException("Worker queue is full!");
}
schedule();
}
private void schedule() {
//if it is already scheduled, we don't need to schedule it again.
if (scheduled.get()) {
return;
}
if (!workQueue.isEmpty() && scheduled.compareAndSet(false, true)) {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
scheduled.set(false);
throw e;
}
}
}
public void run() {
try {
Runnable r;
do {
r = workQueue.poll();
if (r != null) {
r.run();
}
}
while (r != null);
} finally {
scheduled.set(false);
schedule();
}
}
As suggested above there is no fixed rule for thread pool size .But there is some suggestion or best practice available can be used depending upon your use case.
CPU Bound Tasks
For CPU bound tasks, Goetz (2002, 2006) recommends
threads = number of CPUs + 1
IO Bound Tasks
Working out the optimal number for IO bound tasks is less obvious. During an IO bound task, a CPU will be left idle (waiting or blocking). This idle time can be better used in initiating another IO bound request.

Java Producer Consumer ArrayBlockingQueue deadlock on take()

In my app there are 2 phases, one download some big data, and the other manipulates it.
so i created 2 classes which implements runnable: ImageDownloader and ImageManipulator, and they share a downloadedBlockingQueue:
public class ImageDownloader implements Runnable {
private ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue;
private ArrayBlockingQueue<String> imgUrlsBlockingQueue;
public ImageDownloader(ArrayBlockingQueue<String> imgUrlsBlockingQueue, ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue) {
this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
this.imgUrlsBlockingQueue = imgUrlsBlockingQueue;
}
#Override
public void run() {
while (!this.imgUrlsBlockingQueue.isEmpty()) {
try {
String imgUrl = this.imgUrlsBlockingQueue.take();
ImageBean imageBean = doYourThing(imgUrl);
this.downloadedImagesBlockingQueue.add(imageBean);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ImageManipulator implements Runnable {
private ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue;
private AtomicInteger capacity;
public ImageManipulator(ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue,
AtomicInteger capacity) {
this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
this.capacity = capacity;
}
#Override
public void run() {
while (capacity.get() > 0) {
try {
ImageBean imageBean = downloadedImagesBlockingQueue.take(); // <- HERE I GET THE DEADLOCK
capacity.decrementAndGet();
} catch (InterruptedException e) {
e.printStackTrace();
}
// ....
}
}
}
public class Main {
public static void main(String[] args) {
String[] imageUrls = new String[]{"url1", "url2"};
int capacity = imageUrls.length;
ArrayBlockingQueue<String> imgUrlsBlockingQueue = initImgUrlsBlockingQueue(imageUrls, capacity);
ArrayBlockingQueue<ImageBean> downloadedImagesBlockingQueue = new ArrayBlockingQueue<>(capacity);
ExecutorService downloaderExecutor = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
Runnable worker = new ImageDownloader(imgUrlsBlockingQueue, downloadedImagesBlockingQueue);
downloaderExecutor.execute(worker);
}
downloaderExecutor.shutdown();
ExecutorService manipulatorExecutor = Executors.newFixedThreadPool(3);
AtomicInteger manipulatorCapacity = new AtomicInteger(capacity);
for (int i = 0; i < 3; i++) {
Runnable worker = new ImageManipulator(downloadedImagesBlockingQueue, manipulatorCapacity);
manipulatorExecutor.execute(worker);
}
manipulatorExecutor.shutdown();
while (!downloaderExecutor.isTerminated() && !manipulatorExecutor.isTerminated()) {
}
}
}
The deadlock happens because this scenario:
t1 checks capacity its 1.
t2 checks its 1.
t3 checks its 1.
t2 takes, sets capacity to 0, continue with flow and eventually exits.
t1 and t3 now on deadlock, cause there will be no adding to the downloadedImagesBlockingQueue.
Eventually i want something like that: when the capacity is reached && the queue is empty = break the "while" loop, and terminate gracefully.
to set "is queue empty" as only condition won't work, cause in the start it is empty, until some ImageDownloader puts a imageBean into the queue.
There area a couple of things you can do to prevent deadlock:
Use a LinkedBlockingQueue which has a capacity
Use offer to add to the queue which does not block
Use drainTo or poll to take items from the queue which are not blocking
There are also some tips you might want to consider:
Use a ThreadPool:
final ExecutorService executorService = Executors.newFixedThreadPool(4);
If you use a fixed size ThreadPool you can add "poison pill"s when you finished adding data to the queue corresponding to the size of your ThreadPool and check it when you poll
Using a ThreadPool is as simple as this:
final ExecutorService executorService = Executors.newFixedThreadPool(4);
final Future<?> result = executorService.submit(new Runnable() {
#Override
public void run() {
}
});
There is also the less known ExecutorCompletionService which abstracts this whole process. More info here.
You don't need the capacity in your consumer. It's now read and updated in multiple threads, which cause the synchronization issue.
initImgUrlsBlockingQueue creates the url blocking queue with capacity number of URL items. (Right?)
ImageDownloader consumes the imgUrlsBlockingQueue and produce images, it terminates when all the URLs are downloaded, or, if capacity means number of images that should be downloaded because there may be some failure, it terminates when it added capacity number of images.
Before ImageDownloader terminates, it add a marker in to the downloadedImagesBlockingQueue, for example, a null element, a static final ImageBean static final ImageBean marker = new ImageBean().
All ImageManipulator drains the queue use the following construct, and when it sees the null element, it add it to the queue again and terminate.
// use identity comparison
while ((imageBean = downloadedImagesBlockingQueue.take()) != marker) {
// process image
}
downloadedImagesBlockingQueue.add(marker);
Note that the BlockingQueue promises its method call it atomic, however, if you check it's capacity first, and consume an element according to the capacity, the action group won't be atomic.
Well i used some of the features suggested, but this is the complete solution for me, the one which does not busy waiting and wait until the Downloader notify it.
public ImageManipulator(LinkedBlockingQueue<ImageBean> downloadedImagesBlockingQueue,
LinkedBlockingQueue<ImageBean> manipulatedImagesBlockingQueue,
AtomicInteger capacity,
ManipulatedData manipulatedData,
ReentrantLock downloaderReentrantLock,
ReentrantLock manipulatorReentrantLock,
Condition downloaderNotFull,
Condition manipulatorNotFull) {
this.downloadedImagesBlockingQueue = downloadedImagesBlockingQueue;
this.manipulatedImagesBlockingQueue = manipulatedImagesBlockingQueue;
this.capacity = capacity;
this.downloaderReentrantLock = downloaderReentrantLock;
this.manipulatorReentrantLock = manipulatorReentrantLock;
this.downloaderNotFull = downloaderNotFull;
this.manipulatorNotFull = manipulatorNotFull;
this.manipulatedData = manipulatedData;
}
#Override
public void run() {
while (capacity.get() > 0) {
downloaderReentrantLock.lock();
if (capacity.get() > 0) { //checks if the value is updated.
ImageBean imageBean = downloadedImagesBlockingQueue.poll();
if (imageBean != null) { // will be null if no downloader finished is work (successfully downloaded or not)
capacity.decrementAndGet();
if (capacity.get() == 0) { //signal all the manipulators to wake up and stop waiting for downloaded images.
downloaderNotFull.signalAll();
}
downloaderReentrantLock.unlock();
if (imageBean.getOriginalImage() != null) { // the downloader will set it null iff it failes to download it.
// business logic
}
manipulatedImagesBlockingQueue.add(imageBean);
signalAllPersisters(); // signal the persisters (which has the same lock/unlock as this manipulator.
} else {
try {
downloaderNotFull.await(); //manipulator will wait for downloaded image - downloader will signalAllManipulators (same as signalAllPersisters() here) when an imageBean will be inserted to queue.
downloaderReentrantLock.unlock();
} catch (InterruptedException e) {
logger.log(Level.ERROR, e.getMessage(), e);
}
}
}
}
logger.log(Level.INFO, "Manipulator: " + Thread.currentThread().getId() + " Ended Gracefully");
}
private void signalAllPersisters() {
manipulatorReentrantLock.lock();
manipulatorNotFull.signalAll();
manipulatorReentrantLock.unlock();
}
For full flow you can check this project on my github: https://github.com/roy-key/image-service/
Your issue is that you are trying to use a counter to track queue elements and aren't composing operations that need to be atomic. You are doing check, take, decrement. This allows the queue size and counter to desynchronize and your threads block forever. It would be better to write a synchronization primitive that is 'closeable' so that you don't have to keep an associated counter. However, a quick fix would be to change it so you are get and decrementing the counter atomically:
while (capacity.getAndDecrement() > 0) {
try {
ImageBean imageBean = downloadedImagesBlockingQueue.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
In this case if there are 3 threads and only one element left in the queue then only one thread will atomically decrement the counter and see that it can take without blocking. Both other threads will see 0 or <0 and break out of the loop.
You also need to make all of your class instance variables final so that they have the correct memory visibility. You should also determine how you are going to handle interrupts rather than relying on the default print trace template.

How to wait for a number of threads to complete?

What is a way to simply wait for all threaded process to finish? For example, let's say I have:
public class DoSomethingInAThread implements Runnable{
public static void main(String[] args) {
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread());
t.start();
}
// wait for all threads' run() methods to complete before continuing
}
public void run() {
// do something here
}
}
How do I alter this so the main() method pauses at the comment until all threads' run() methods exit? Thanks!
You put all threads in an array, start them all, and then have a loop
for(i = 0; i < threads.length; i++)
threads[i].join();
Each join will block until the respective thread has completed. Threads may complete in a different order than you joining them, but that's not a problem: when the loop exits, all threads are completed.
One way would be to make a List of Threads, create and launch each thread, while adding it to the list. Once everything is launched, loop back through the list and call join() on each one. It doesn't matter what order the threads finish executing in, all you need to know is that by the time that second loop finishes executing, every thread will have completed.
A better approach is to use an ExecutorService and its associated methods:
List<Callable> callables = ... // assemble list of Callables here
// Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
// bother saving them
Using an ExecutorService (and all of the new stuff from Java 5's concurrency utilities) is incredibly flexible, and the above example barely even scratches the surface.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class DoSomethingInAThread implements Runnable
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
//limit the number of actual threads
int poolSize = 10;
ExecutorService service = Executors.newFixedThreadPool(poolSize);
List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
for (int n = 0; n < 1000; n++)
{
Future f = service.submit(new DoSomethingInAThread());
futures.add(f);
}
// wait for all tasks to complete before continuing
for (Future<Runnable> f : futures)
{
f.get();
}
//shut down the executor service so that this thread can exit
service.shutdownNow();
}
public void run()
{
// do something here
}
}
instead of join(), which is an old API, you can use CountDownLatch. I have modified your code as below to fulfil your requirement.
import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
CountDownLatch latch;
public DoSomethingInAThread(CountDownLatch latch){
this.latch = latch;
}
public void run() {
try{
System.out.println("Do some thing");
latch.countDown();
}catch(Exception err){
err.printStackTrace();
}
}
}
public class CountDownLatchDemo {
public static void main(String[] args) {
try{
CountDownLatch latch = new CountDownLatch(1000);
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread(latch));
t.start();
}
latch.await();
System.out.println("In Main thread after completion of 1000 threads");
}catch(Exception err){
err.printStackTrace();
}
}
}
Explanation:
CountDownLatch has been initialized with given count 1000 as per your requirement.
Each worker thread DoSomethingInAThread will decrement the CountDownLatch, which has been passed in constructor.
Main thread CountDownLatchDemo await() till the count has become zero. Once the count has become zero, you will get below line in output.
In Main thread after completion of 1000 threads
More info from oracle documentation page
public void await()
throws InterruptedException
Causes the current thread to wait until the latch has counted down to zero, unless the thread is interrupted.
Refer to related SE question for other options:
wait until all threads finish their work in java
Avoid the Thread class altogether and instead use the higher abstractions provided in java.util.concurrent
The ExecutorService class provides the method invokeAll that seems to do just what you want.
Consider using java.util.concurrent.CountDownLatch. Examples in javadocs
Depending on your needs, you may also want to check out the classes CountDownLatch and CyclicBarrier in the java.util.concurrent package. They can be useful if you want your threads to wait for each other, or if you want more fine-grained control over the way your threads execute (e.g., waiting in their internal execution for another thread to set some state). You could also use a CountDownLatch to signal all of your threads to start at the same time, instead of starting them one by one as you iterate through your loop. The standard API docs have an example of this, plus using another CountDownLatch to wait for all threads to complete their execution.
As Martin K suggested java.util.concurrent.CountDownLatch seems to be a better solution for this. Just adding an example for the same
public class CountDownLatchDemo
{
public static void main (String[] args)
{
int noOfThreads = 5;
// Declare the count down latch based on the number of threads you need
// to wait on
final CountDownLatch executionCompleted = new CountDownLatch(noOfThreads);
for (int i = 0; i < noOfThreads; i++)
{
new Thread()
{
#Override
public void run ()
{
System.out.println("I am executed by :" + Thread.currentThread().getName());
try
{
// Dummy sleep
Thread.sleep(3000);
// One thread has completed its job
executionCompleted.countDown();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
try
{
// Wait till the count down latch opens.In the given case till five
// times countDown method is invoked
executionCompleted.await();
System.out.println("All over");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
If you make a list of the threads, you can loop through them and .join() against each, and your loop will finish when all the threads have. I haven't tried it though.
http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join()
Create the thread object inside the first for loop.
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
// some code to run in parallel
}
});
threads[i].start();
}
And then so what everyone here is saying.
for(i = 0; i < threads.length; i++)
threads[i].join();
You can do it with the Object "ThreadGroup" and its parameter activeCount:
As an alternative to CountDownLatch you can also use CyclicBarrier e.g.
public class ThreadWaitEx {
static CyclicBarrier barrier = new CyclicBarrier(100, new Runnable(){
public void run(){
System.out.println("clean up job after all tasks are done.");
}
});
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new MyCallable(barrier));
t.start();
}
}
}
class MyCallable implements Runnable{
private CyclicBarrier b = null;
public MyCallable(CyclicBarrier b){
this.b = b;
}
#Override
public void run(){
try {
//do something
System.out.println(Thread.currentThread().getName()+" is waiting for barrier after completing his job.");
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
To use CyclicBarrier in this case barrier.await() should be the last statement i.e. when your thread is done with its job. CyclicBarrier can be used again with its reset() method. To quote javadocs:
A CyclicBarrier supports an optional Runnable command that is run once per barrier point, after the last thread in the party arrives, but before any threads are released. This barrier action is useful for updating shared-state before any of the parties continue.
The join() was not helpful to me. see this sample in Kotlin:
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
}
})
The result:
Thread-5|a=5
Thread-1|a=1
Thread-3|a=3
Thread-2|a=2
Thread-4|a=4
Thread-2|2*1=2
Thread-3|3*1=3
Thread-1|1*1=1
Thread-5|5*1=5
Thread-4|4*1=4
Thread-1|2*2=2
Thread-5|10*2=10
Thread-3|6*2=6
Thread-4|8*2=8
Thread-2|4*2=4
Thread-3|18*3=18
Thread-1|6*3=6
Thread-5|30*3=30
Thread-2|12*3=12
Thread-4|24*3=24
Thread-4|96*4=96
Thread-2|48*4=48
Thread-5|120*4=120
Thread-1|24*4=24
Thread-3|72*4=72
Thread-5|600*5=600
Thread-4|480*5=480
Thread-3|360*5=360
Thread-1|120*5=120
Thread-2|240*5=240
Thread-1|TaskDurationInMillis = 765
Thread-3|TaskDurationInMillis = 765
Thread-4|TaskDurationInMillis = 765
Thread-5|TaskDurationInMillis = 765
Thread-2|TaskDurationInMillis = 765
Now let me use the join() for threads:
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
t.join()
}
})
And the result:
Thread-1|a=1
Thread-1|1*1=1
Thread-1|2*2=2
Thread-1|6*3=6
Thread-1|24*4=24
Thread-1|120*5=120
Thread-1|TaskDurationInMillis = 815
Thread-2|a=2
Thread-2|2*1=2
Thread-2|4*2=4
Thread-2|12*3=12
Thread-2|48*4=48
Thread-2|240*5=240
Thread-2|TaskDurationInMillis = 1568
Thread-3|a=3
Thread-3|3*1=3
Thread-3|6*2=6
Thread-3|18*3=18
Thread-3|72*4=72
Thread-3|360*5=360
Thread-3|TaskDurationInMillis = 2323
Thread-4|a=4
Thread-4|4*1=4
Thread-4|8*2=8
Thread-4|24*3=24
Thread-4|96*4=96
Thread-4|480*5=480
Thread-4|TaskDurationInMillis = 3078
Thread-5|a=5
Thread-5|5*1=5
Thread-5|10*2=10
Thread-5|30*3=30
Thread-5|120*4=120
Thread-5|600*5=600
Thread-5|TaskDurationInMillis = 3833
As it's clear when we use the join:
The threads are running sequentially.
The first sample takes 765 Milliseconds while the second sample takes 3833 Milliseconds.
Our solution to prevent blocking other threads was creating an ArrayList:
val threads = ArrayList<Thread>()
Now when we want to start a new thread we most add it to the ArrayList:
addThreadToArray(
ThreadUtils.startNewThread(Runnable {
...
})
)
The addThreadToArray function:
#Synchronized
fun addThreadToArray(th: Thread) {
threads.add(th)
}
The startNewThread funstion:
fun startNewThread(runnable: Runnable) : Thread {
val th = Thread(runnable)
th.isDaemon = false
th.priority = Thread.MAX_PRIORITY
th.start()
return th
}
Check the completion of the threads as below everywhere it's needed:
val notAliveThreads = ArrayList<Thread>()
for (t in threads)
if (!t.isAlive)
notAliveThreads.add(t)
threads.removeAll(notAliveThreads)
if (threads.size == 0){
// The size is 0 -> there is no alive threads.
}
The problem with:
for(i = 0; i < threads.length; i++)
threads[i].join();
...is, that threads[i + 1] never can join before threads[i].
Except the "latch"ed ones, all solutions have this lack.
No one here (yet) mentioned ExecutorCompletionService, it allows to join threads/tasks according to their completion order:
public class ExecutorCompletionService<V>
extends Object
implements CompletionService<V>
A CompletionService that uses a supplied Executor to execute tasks. This class arranges that submitted tasks are, upon completion, placed on a queue accessible using take. The class is lightweight enough to be suitable for transient use when processing groups of tasks.
Usage Examples.
Suppose you have a set of solvers for a certain problem, each returning a value of some type Result, and would like to run them concurrently, processing the results of each of them that return a non-null value, in some method use(Result r). You could write this as:
void solve(Executor e, Collection<Callable<Result>> solvers) throws InterruptedException, ExecutionException {
CompletionService<Result> cs = new ExecutorCompletionService<>(e);
solvers.forEach(cs::submit);
for (int i = solvers.size(); i > 0; i--) {
Result r = cs.take().get();
if (r != null)
use(r);
}
}
Suppose instead that you would like to use the first non-null result of the set of tasks, ignoring any that encounter exceptions, and cancelling all other tasks when the first one is ready:
void solve(Executor e, Collection<Callable<Result>> solvers) throws InterruptedException {
CompletionService<Result> cs = new ExecutorCompletionService<>(e);
int n = solvers.size();
List<Future<Result>> futures = new ArrayList<>(n);
Result result = null;
try {
solvers.forEach(solver -> futures.add(cs.submit(solver)));
for (int i = n; i > 0; i--) {
try {
Result r = cs.take().get();
if (r != null) {
result = r;
break;
}
} catch (ExecutionException ignore) {}
}
} finally {
futures.forEach(future -> future.cancel(true));
}
if (result != null)
use(result);
}
Since: 1.5 (!)
Assuming use(r) (of Example 1) also asynchronous, we had a big advantage. #

Categories

Resources