Java foxtrot Worker produce deadlock when use with invokeLater - java

We are using foxtrot package for stop freeze the swing application.
But in this below code it make a deadlock.
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import foxtrot.Task;
import foxtrot.Worker;
public class FoxtrotExample extends JFrame {
public static void main(String[] args) {
FoxtrotExample example = new FoxtrotExample();
example.setVisible(true);
}
boolean st = true;
public FoxtrotExample() {
super("Foxtrot Example");
final JButton button = new JButton("Take a nap !");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("Start..");
button.setText("Sleeping...");
String text = null;
try {
text = (String) Worker.post(new Task() {
public Object run() throws Exception {
System.out.println("Inside Worker 1");
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
try {
System.out.println("Inside invokeLater");
Worker.post(new Task() {
#Override
public Object run()
throws Exception {
System.out.println("Inside Worker 2");
st = false;
return null;
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
});
while (st) {
System.out.println("Inside the loop..");
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
return "Slept !";
}
});
} catch (Exception x) {
}
button.setText(text);
System.out.println("Finished.....");
}
});
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
Container c = getContentPane();
c.setLayout(new GridBagLayout());
c.add(button);
setSize(300, 200);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension size = getSize();
int x = (screen.width - size.width) >> 1;
int y = (screen.height - size.height) >> 1;
setLocation(x, y);
}
}
If use ConcurrentWorker this will work fine.Can any one explane this.
I am bit confuse how EDT behave here ?

This is the result of my program.
Start 1st worker
In the loop
Start invoke later
In the loop
In the loop
In the loop
In the loop
......
It start the 1st worker.Then part of the code is in invokeLater.So request is enqued in the event queue and start the loop.Later execute the invokeLater but not execute the 2nd worker because first worker still doing some work.Since worker are ruining one after another and it runs on a single worker queue 2nd worker cannot execute and deadlock comes.
Thanks to MadProgrammer i understood this.Hope this is correct.

Related

Progress Bar value is not updating [duplicate]

I have made a very simple code to show it here, i have a button that should show a JDialog to check the progress status, i am using the invoke late to go through EDT and my loop isn't in the run method, so why isn't my bar updating ?
here is the code
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class JBarEx extends JFrame {
private JTextField progStatus = new JTextField("Undefined");
private JButton dialogBtn = new JButton("Show Progression dialog");
final JDialog dlg = new JDialog((JFrame) null, "prog Title", false);
final JProgressBar dpb = new JProgressBar(0, 100);
public JBarEx() {
JPanel pan = new JPanel();
dialogBtn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
showProgress();
}
});
progStatus.setEditable(false);
pan.add(progStatus);
pan.add(dialogBtn);
setContentPane(pan);
this.setSize(200, 100);
setVisible(true);
}
public void showProgress() {
dlg.add(BorderLayout.CENTER, dpb);
dlg.add(BorderLayout.NORTH, new JLabel("prog message"));
dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dlg.setSize(300, 75);
dlg.setLocationRelativeTo(null);
dlg.setVisible(true);
for (int i = 0; i < 100; i++) {
final int ii = i;
try {
Thread.sleep(25);
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
updateBar(ii);
}
});
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void updateBar(int newValue) {
dpb.setValue(newValue);
}
public static void main(String[] args) {
JBarEx jbx = new JBarEx();
}
}
Your showProgress method is being executed within the context of the Event Dispatching Thread. The EDT is responsible for, amongst other things, processing paint requests. This means that so long as your for-loop is executing, the EDT can not process any new paint requests (or handle the invokeLater events either) as it is blocking the EDT.
While there are any number of possible ways to solve the problem, based on your code example, the simplest would be to use a SwingWorker.
It has the capacity to allow your to execute the long running task the a background thread (freeing up the EDT), but also allows you means for publishing updates (if required) so that they can be processed in the EDT and also provides handy progress notification.
For example...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class SwingWorkerProgress {
public static void main(String[] args) {
new SwingWorkerProgress();
}
public SwingWorkerProgress() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pbProgress;
private JButton start;
public TestPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
pbProgress = new JProgressBar();
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(4, 4, 4, 4);
gbc.gridx = 0;
gbc.gridy = 0;
add(pbProgress, gbc);
start = new JButton("Start");
gbc.gridy++;
add(start, gbc);
start.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start.setEnabled(false);
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pbProgress.setValue(progress);
repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
start.setEnabled(true);
break;
}
}
}
});
pw.execute();
}
});
}
}
public class ProgressWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
for (int i = 0; i < 100; i++) {
setProgress(i);
try {
Thread.sleep(25);
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
}
Check out Concurrency in Swing for more details
Even if you fix the loop as others have pointed out, you'd still block the event dispatch thread. The for loop is run in showProgress() which is called from an event listener. The updates are pushed to the event queue, but that does not get processed until the loop has completed.
Use a Swing Timer instead. Something like this:
Timer timer = new Timer(25, new ActionListener() {
private int position;
#Override
public void actionPerformed(ActionEvent e) {
position++;
if (position < lastPosition) {
updateBar(position);
} else {
((Timer) e.getSource).stop();
}
}
});
timer.start();
where lastPosition would be the state where you want the progress bar to stop.
Unrelated to that bug, but a bug still, you should not create swing components outside the event dispatch thread. It's best to do it right from the start:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JBarEx jbx = new JBarEx();
}
});
}
for (int i = 0; i < 0; i++) {
You will never enter this code so will never call the updateBar(..) method
i needs to be greater than 0 in this case. If it is 1 then updateBar will be called once, if 2 then updateBar will be called twice etc
Also rather than doing
Thread.sleep(25);
take a look at java executors as these will help with your scheduling and remove the need for the sleep

SwingWorker not updating on long process

I'm using SwingWorker and
It perfectly updates JProgressBar WHEN the process is not too heavy (for example "Trames" list containing 62 elements)
It doesn't update JProgressBar when the process is heavy (I tested with 100k elements, it'll finally works with 2M+ elems)
Below my ProgressWorker class
#Override
protected Object doInBackground() throws Exception {
// TODO Auto-generated method stub
// here process i skipped
for (Trame t : trames) {
float progress = (float)FileRW.tramescounter/FileRW.maxtrames;
progress = progress*100;
int p = (int) progress;
setProgress(p);
System.out.println(getProgress()+"+p"+" ---- progress"+p+" ---- double"+progress);
Thread.sleep(25);
FileRW.tramescounter++;
// here process i skipped
}
// here process i skipped
return null;
}
Besides, my controller class:
ProgressWorker pw = new ProgressWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
Vue.bar.setValue(progress);
Vue.bar.repaint();
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
Vue.lastButton.setEnabled(true);
if (Vue.check.isSelected()) {
if (Desktop.isDesktopSupported()) {
Desktop desktop = Desktop.getDesktop();
try {
desktop.open(new File(Constants.FICHIER_LOG2));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Vue.filesInDirectory = null;
Vue.fileLabel.setText(Constants.PAN1_LABEL);
break;
default:
break;
}
}
}
});
pw.execute();
There's a runnable example (based on your out-of-context code) which works, so my guess is, it's not the SwingWorker which is at fault, but some part of the code you're not sharing.
Consider providing a Minimal, Complete, and Verifiable example which demonstrates your problem, until you do, this is about all the help we can possible give you
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import static javax.swing.SwingWorker.StateValue.DONE;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JProgressBar pb = new JProgressBar(0, 100);
public TestPane() {
setLayout(new GridBagLayout());
add(pb);
BadWorker pw = new BadWorker();
pw.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
String name = evt.getPropertyName();
if (name.equals("progress")) {
int progress = (int) evt.getNewValue();
pb.setValue(progress);
} else if (name.equals("state")) {
SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
switch (state) {
case DONE:
System.out.println("All done where");
break;
}
}
}
});
pw.execute();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}
}
public class BadWorker extends SwingWorker<Object, Object> {
#Override
protected Object doInBackground() throws Exception {
int count = 0;
int max = 10000;
do {
count++;
float progress = (float) count / max;
progress = progress * 100;
int p = (int) progress;
setProgress(p);
System.out.println(getProgress() + "+p" + " ---- progress" + p + " ---- double" + progress);
Thread.sleep(5);
// here process i skipped
} while (getProgress() < 100);
// here process i skipped
return null;
}
}
}
Ok nevermind the problem wasn't the one I expected
Just inside the first part of code I skipped I wrote
Vue.bar.setMaximum(trames.size());
Further,
float progress = (float)FileRW.tramescounter/FileRW.maxtrames;
progress = progress*100;
int p = (int) progress;
setProgress(p);
And in controller class
Vue.bar.setValue(progress);
But progress value set in ProgressWorker is from 0 to 100
My max ProgressBar value was 100K but the 0 < progression value <100,
It was normal that it didn't progress

this.notifyAll(); is not working in java code

This is a part of my java code, in this code there are labels which are counting numbers from 0 up to so on, I want to stop labels to count when I click the button 1st time, and I want to restart the labels to count again when I click the button 2nd time, the problem is that the labels are not restarting there counting when I am clicking the button 2nd time, so please tell how should I notify all the labels to restart there counting???
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
public class Main implements ActionListener {
JButton button = new JButton("Click");
JFrame frame = new JFrame();
boolean wait=false;
public static void main(String arg[]) {
new Main();
}
public Main() {
frame.setLayout(new FlowLayout());
frame.getContentPane().setBackground(Color.BLACK);
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
button.addActionListener(this);
frame.add(button);
frame.setVisible(true);
new Producer().execute();
}
public class Producer extends SwingWorker<Void, Void> {
public Void doInBackground() {
for(int infinite=0; infinite!=-1; infinite++) {
new Counter().execute();
try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}
}
return null;
}
}
public class Counter extends SwingWorker<Void, Void> {
JLabel label = new JLabel();
public Counter() {
label.setForeground(Color.WHITE);
frame.add(label);
}
public Void doInBackground() {
synchronized (this) {
for(int i=0; i!=-1; i++) {
if(wait==true)
try {this.wait();} catch(Exception exp) {exp.printStackTrace();}
label.setText(""+i);
try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}
}
}
return null;
}
}
public void actionPerformed(ActionEvent clicked) {
if(wait==false)
wait=true;
else if(wait==true) {
synchronized (this) {
this.notifyAll();
}
}
}
}
I don't see a place where you ever reset wait to false. Try this and see if it gets you unstuck:
public void actionPerformed(ActionEvent clicked) {
if(wait==false) {
wait=true;
} else {
wait=false;
synchronized (this) {
this.notifyAll();
}
}
}

Java Event-Dispatch Thread example program hangs

I have read this article on the EDT (Event Dispatch Thread) javaworld.com which shows how to correctly setup a Swing GUI on the EDT and put long running tasks which modify the GUI inside Runnables.
It all makes sense however the example program (I pasted below) where the only modification I made is a Thread.sleep(6000) to simulate a long lag makes the interface irresponsive for some seconds.
Am I missing something?
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
public class ViewPage
{
public static void main(String[] args)
{
Runnable r;
r = new Runnable()
{
#Override
public void run()
{
final JFrame frame = new JFrame("View Page");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.add(new JLabel("Enter URL"));
final JTextField txtURL = new JTextField(40);
panel.add(txtURL);
frame.getContentPane().add(panel, BorderLayout.NORTH);
final JTextArea txtHTML = new JTextArea(10, 40);
frame.getContentPane().add(new JScrollPane(txtHTML),
BorderLayout.CENTER);
ActionListener al;
al = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
txtURL.setEnabled(false);
Runnable worker = new Runnable()
{
public void run()
{
InputStream is = null;
try
{
URL url = new URL(txtURL.getText());
is = url.openStream();
final StringBuilder sb;
sb = new StringBuilder();
int b;
while ((b = is.read()) != -1)
{
sb.append((char) b);
}
Runnable r = new Runnable()
{
public void run()
{
try
{
Thread.sleep(6000);
}
catch (InterruptedException ex)
{
Logger.getLogger(ViewPage.class.getName()).log(Level.SEVERE, null, ex);
}
txtHTML.setText(sb.toString());
txtURL.setEnabled(true);
}
};
try
{
EventQueue.invokeAndWait(r);
}
catch (InterruptedException ie)
{
}
catch (InvocationTargetException ite)
{
}
}
catch (final IOException ioe)
{
Runnable r = new Runnable()
{
public void run()
{
txtHTML.setText(ioe.getMessage());
txtURL.setEnabled(true);
}
};
try
{
EventQueue.invokeAndWait(r);
}
catch (InterruptedException ie)
{
}
catch (InvocationTargetException ite)
{
}
}
finally
{
Runnable r = new Runnable()
{
public void run()
{
txtHTML.setCaretPosition(0);
txtURL.setEnabled(true);
}
};
try
{
EventQueue.invokeAndWait(r);
}
catch (InterruptedException ie)
{
}
catch (InvocationTargetException ite)
{
}
if (is != null)
{
try
{
is.close();
}
catch (IOException ioe)
{
}
}
}
}
};
new Thread(worker).start();
}
};
txtURL.addActionListener(al);
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(r);
}
}
Am I missing something?
Yes.
Runnable is just an interface not another thread.
Here with this line you are wrapping the call to execute later in the Event Dispatch Thread.
EventQueue.invokeLater(r); // you can use SwingUtilities.invokeLater(r) too
Then you call
Thread.sleep(6000);
This is executed in EDT and make irresponsive the gui until finish.
For long task you should use another threads or SwingWorker and for short task with some repetitions SwingTimer.
Read about Concurrency in Swing

Future result update UI as soon as they arrive

I have JList using DefaultListModel to update the strings in list in UI , returned by a class as shown
class ResponseGiver implements Callable<Future>{
int i;
//Constructor to initialize i
String call(){
...............
...............
return i;
}
and i have other class that will update the results obtained from above
class Viewer {
ExecutorService es = new Executors.newFixedThreadPool(10);
List<Future<String>> futures = new ArrayList<Future<String>>();
for(int i =0;i<10;i++)
{
futures.add(new ResponseGiver(i));
}
for(Future<String> x : futures) //loop 2nd will be called 10 times
{
String p = x.get();
//update GUI with p
}
Now the question is, suppose in loop 2nd , in the 5th loop, the get() function takes some time say 10 seconds, and during the mean time, the other futures from 6th to 10th have their result ready.
So my screen would wait for 5th result, even 6th to 10th are ready.
I want my screen to be updated as soon as any of the 10 futures return the result.
Using the standard API, you can use a ExecutorCompletionService. It allows submitting Callable instances and returns Future objects, just like a normal ExecutorService. But it additionally allows obtaining the Future objects in the order in which they are finished: Using the ExecutorCompletionService#take() method. This method blocks until a new Future is available. You can imagine this as the Futures being placed into a blocking queue.
You can start a thread that consumes these Future objects from the completion service. The result of such a Future may then be used to update the GUI. (Note that this update, in turn, has to be done on the Event Dispatch Thread again, using SwingUtilities.invokeLater).
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ExecutorCompletionServiceTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
JButton button = new JButton("Run");
f.getContentPane().add(button, BorderLayout.NORTH);
final DefaultListModel<String> listModel = new DefaultListModel<String>();
JList<String> list = new JList<String>(listModel);
f.getContentPane().add(new JScrollPane(list), BorderLayout.CENTER);
final Callback callback = new Callback()
{
#Override
public void call(final String result)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
listModel.addElement(result);
}
});
}
};
button.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
createTasks(callback);
}
});
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
interface Callback
{
void call(String result);
}
private static Random random = new Random(0);
static class ResponseGiver implements Callable<String>
{
private int i;
ResponseGiver(int i)
{
this.i = i;
}
#Override
public String call()
{
int delayMS = 250 + random.nextInt(500);
// Simulate a longer delay for task 5
if (i == 5)
{
delayMS += 3000;
}
try
{
System.out.println("For "+i+" waiting "+delayMS+" ms");
Thread.sleep(delayMS);
System.out.println("For "+i+" waiting "+delayMS+" ms DONE");
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
return String.valueOf(i);
}
}
private static void createTasks(final Callback callback)
{
ExecutorService executorService = Executors.newFixedThreadPool(10);
final CompletionService<String> executorCompletionService =
new ExecutorCompletionService<String>(executorService);
final int n = 10;
for (int i = 0; i < 10; i++)
{
executorCompletionService.submit(new ResponseGiver(i));
}
Thread thread = new Thread(new Runnable()
{
#Override
public void run()
{
processResults(executorCompletionService, n, callback);
}
});
thread.start();
}
private static void processResults(
CompletionService<String> completionService, int n, Callback callback)
{
for (int i = 0; i < n; i++)
{
try
{
Future<String> future = completionService.take();
String result = future.get();
if (result != null)
{
callback.call(result);
}
System.out.println("Processed "+(i+1)+" of "+n+" results");
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
catch (ExecutionException e)
{
e.printStackTrace();
}
}
}
}
Just use ListenableFuture from guava. It's much more convenient.

Categories