1

Alright, so explaining this situation is somewhat complex. It actually isn't as risque as it seems.

I'm writing a concurrency package which does two things, and it used to work perfectly on JDK 6. The first thing it does is provide a better Future interface which allows callback when the task completes, using event listeners. "But you can use FutureTask's done() for that!" you might say. The problem is that done() is called immediately when a task is cancelled, while the task might still be doing stuff in its call() method. Also, cancelling makes it impossible to retrieve partial results. So my own package fixes these issues by extending on the existing packages (including a new thread pool, but most of the implementation is reused there).

Part of my progress monitor solution

The second thing the package does is solve a common GUI problem. Let's say the user clicks "Save" to save an image. If the image is huge, it would be nice to display a progress monitor instead of freezing the interface. But if the document is small, then the sudden flash of a progress monitor confuses users. And we cannot have a minimum popup time - this slows the workflow down. My solution compromises between these two. The effect is that the EDT "freezes" for the time the task takes to complete, or, if it takes longer than say 1 second, displays a progress monitor with a minimum popup time. The effect is rather elegant. This, too, worked perfectly in JDK6, and even worked with several threads.

THE PROBLEM: In JDK7, the freezing part above now gets a subtle bug. A critical assumption of my code is that the Runnable passed to SwingUtilities.invokeLater() will not run concurrently with other event dispatch thread stuff. So the EDT can't be processing button clicks, accelerators, other events, etc, while the Runnable runs. (This is exploited to stop all input during the freezing) But this seems to have changed in JDK7. In my debugging I noticed the Runnable might be running while the button pressing code is still running! This quickly causes a deadlock due to later stuff. Due to an implementation mistake, nevermind.

Abusing the EDT like this is risky, but back in the day it was the only thing that worked. Some suggested using a GlassPane to intercept events. But it can't intercepts accelerators. Everything else I tried at the time was also limited in this way.

My question is now if anyone sees a better way to do this. If you think my Future problem can be solved in a better way, do tell. And most importantly, if you can see a way to solve the GUI problem above, or stop the input, or guarantee the critical assumption I need on JDK, or suggest a long-term solution - all are extremely appreciated. Thanks!

Community
  • 1
  • 1
bombax
  • 1,189
  • 8
  • 26
  • `SwingUtilities.invokeXxx` executes the `Runnable` within the context of the Event Dispatching Thread, so I can't see how, when a `Runnable` is being executed you could possibly be executing other code within the context of the EDT, as the `Runnable` will block the EDT until it is completed. This doesn't prevent events from being stacked, just processed. You could consider using a `JXLayer` or (`JLayer` in Java 7) to disable/block portions of your UI instead... – MadProgrammer Dec 12 '13 at 19:38
  • Okay, will look into JLayer. In the meantime, let me whip up a snippet to show you this effect. – bombax Dec 12 '13 at 19:39
  • ACH! This had nothing to do with Java versions. It was due to a subtle implementation mistake. Regardless, I might look into JLayer as a more robust way to do what I want. I'll leave the question open for the first part of the question. Thanks! – bombax Dec 12 '13 at 20:02
  • [I don't believe](http://stackoverflow.com/q/8099098/714968), for better help sooner post an SSCCE, short, runnable, compilable, caused by a.m. issues, [or there](http://stackoverflow.com/a/7036206/714968), .... etc – mKorbel Dec 12 '13 at 20:05
  • 1
    Just so you know, we had a deadlock issue when we first tested Java 7 with our app, which occurred at Swing.invokeLater. But after I re-wrote the code for that section, it now works. – MadProgrammer Dec 12 '13 at 20:09

1 Answers1

1

Is the first part of the question related to a better usage of Future?

... done() is called immediately when a task is cancelled, while the task might still be doing stuff in its call() method.

Did you check Thread.interrupted() manually in your call() method?

We know for the source code of FutureTask.cancel(), it just calls Thread.interrupt(), which means only a boolean flag that stands for the interrupted status of the thread will be set to true. No InterruptedException will be thrown unless Thread.sleep(),.wait() or .join() is called because the latter 3 they do check the flag and make a response.

A sample is here, please read the accepted answer.

Also, cancelling makes it impossible to retrieve partial results.

Yes. You may leak the partial result to a Hashmap outside the task. Or straightforward, init the result as a final variable outside, then use it inside(call() & done()). Actually I have ever saved the percentage field into a KV store before.

Community
  • 1
  • 1
Anderson
  • 2,496
  • 1
  • 27
  • 41