I have a strange behavior I cannot explain.
Please have a look at this minimal example:
public class ParallelStreamProgressMonitor
{
public static void main(String[] args)
{
List<Integer> belege = IntStream.range(1, 100).boxed().collect(Collectors.toList());
final ProgressMonitor pm = new ProgressMonitor(null, "Initialmessage", "Initial Note", 0, belege.size());
pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0);
pm.setMaximum(belege.size());
pm.setNote("Now I am working");
AtomicInteger counter = new AtomicInteger();
belege.stream().parallel().forEach(b ->
{
System.out.println(b);
pm.setProgress(counter.getAndIncrement());
try
{
//something time consuming ...
Thread.sleep(1000);
}
catch (InterruptedException e)
{
// ignore
}
});
}
}
When executing this, you'd normally expect that a ProgressMonitor will come up and show the progress of the execution.
But this is how it really looks like:
It seems that for every parallel stream executions there is one ProgressMonitor instance extra showing up.
Is there a reason for this? How can I achieve that only one dialog shows up and shows the progress?
Consider Swing's Threading Policy:
In general Swing is not thread safe. All Swing components and related classes, unless otherwise documented, must be accessed on the event dispatching thread.
This implies that you have to study ProgressMonitor
’s documentation to find out whether “unless otherwise documented” applies, but since there’s no other threading policy, there’s nothing to cite here.
One way to perform an action in the Event Dispatch Thread is to encapsulate it in a Runnable
and use invokeLater(Runnable)
, but when doing it for sending different progress states from an unknown number of worker threads they may arrive in the wrong order and it would also be quite inefficient. Since you already have an AtomicInteger
, the better option is to use a Swing Timer
:
public class ParallelStreamProgressMonitor
{
public static void main(String[] args)
{
List<Integer> belege
= IntStream.range(1, 100).boxed().collect(Collectors.toList());
final ProgressMonitor pm = new ProgressMonitor(
null, "Initialmessage", "Initial Note", 0, belege.size());
pm.setMillisToDecideToPopup(0);
pm.setMillisToPopup(0);
pm.setMaximum(belege.size());
pm.setNote("Now I am working");
AtomicInteger counter = new AtomicInteger();
Timer timer = new Timer(250, ev -> pm.setProgress(counter.get()));
timer.start();
belege.stream().parallel().forEach(b ->
{
System.out.println(b);
counter.getAndIncrement();
//simulate something time consuming ...
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(1000));
});
timer.stop();
}
}