Reputation: 1128
I wrote the following method to run multiple threads in parallel and when all threads are complete I want to trigger some further action. I've attached a propertyChangeListener to each object that runs in its own thread and each of those objects fires a property changed event when its thread completes. So on each of those events I increment a count and compare it to the size of the list of objects. Once they are equal I know all threads are finished. However, this seems like a bit of a hash up and I'm quite new to multi-threading, so I thought I'd ask what others think of my approach and whether there are more elegant or robust approaches. Thanks.
private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt) {
count = 0;
List<SpeciesSelection> specSelList = new ArrayList<>();
for (String str : fileList) {
// TODO RUN THE FILES
if (!str.equals("")) {
String[] args = {str};
//run solution
SpeciesSelection specSel = new SpeciesSelection(args, true);
specSelList.add(specSel);// add the thread to the list so we can check for all threads to be finished.
// Create listener to listen for specSel finished
specSel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
// TODO do something
count++;
if (count == specSelList.size())
{
System.out.println("Finished all threads");
}
}
});
Thread t = new Thread(specSel);
t.start();
}
}
}
Upvotes: 0
Views: 1488
Reputation: 1128
Using the advice given, I altered my code as follows:
private void jButtonRunSubsetsActionPerformed(java.awt.event.ActionEvent evt) {
List<SpeciesSelection> specSelList = new ArrayList<>();
new Thread() {
@Override
public void run() {
try {
int numberFiles = fileList.size();
CountDownLatch latch = new CountDownLatch(numberFiles);
for (String str : fileList) {
// TODO RUN THE FILES
if (!str.equals("")) {
String[] args = {str};
//run solution
SpeciesSelection specSel = new SpeciesSelection(args, true);
specSelList.add(specSel);// add the thread to the list so we can check for all threads to be finished.
// Create listener to listen for specSel finished
specSel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
latch.countDown();
}
});
Thread t = new Thread(specSel);
t.start();
}
}
latch.await();
System.out.println("Finished all threads");
} catch (InterruptedException ex) {
Logger.getLogger(SpecSelGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}.start();
}
I used the CountDownLatch as suggested but also ran the multiple processes inside an additional anonymous thread so that I could call latch.await() without freezing up the main thread/GUI responsiveness.
Upvotes: 0
Reputation: 131346
Rather than using an int
counter and check its value use CountDownLatch
that is designed to.
CountDownLatch count = new CountDownLatch(nbRequiredCount);
count.await();
The await()
doesn't return while the counter is not to 0
.
and decrement it in threads :
public void propertyChange(PropertyChangeEvent evt) {
// TODO do something
count.countDown();
}
Upvotes: 2
Reputation: 9786
You can use the class CountDownLatch
like this:
CountDownLatch latch = new CountDownLatch(N);
where N
is the number of threads you launch. You pass around this object and call the latch.countDown()
each time a thread finishes. Once they are all done, the latch will release control to the parent thread.
Upvotes: 0