A while back we added some code to our application to detect and attempt to recover from a Swing EDT deadlock, so the user could at least save their files (it would be best to not have a deadlock, but...). In Java 1.6, this is easy. Detect that the EDT has been blocked for a sufficient amount of time, and then call this from a background thread:
EventQueue newQ = new EventQueue();
Toolkit.getDefaultToolkit().getSystemEventQueue().push(newQ);
New UI events will be processed on a new EventQueue/EDT, and the user can save their work.
In Java 8, this does not work because the implementation of EventQueue.push has been changed to copy the (blocked) EventDispatchThread from the old queue to a new one.
It's still not very good, but it works.
initDispatchThread
does not need to be manually invoked, as the EventQueue does this automatically whendispatchThread
is null.If the old thread is not stopped and it unblocks later, everything goes crazy. I suppose then we have two threads processing the Queue and nothing here is build for thread-safety thus it all breaks down.
I'm still looking for a better solution to do this.
Another idea i had is to create my own EventQueue and replace the original one with it using
EventQueue.push(newQueue)
, but looking into the code of EventQueue it can be extended, but not modified in the way neccessary. And rewriting it looks also problematic to me - there is a lot of sophisticated stuff happening there, which i don't want to mess with.This solution is not very beautiful, but it works. And it works without reflection and
setAccessible(true)
.I use one immplementation detail of the
push()
method to copy the newly created Thread fromnewEventQueue1
tonewEventQueue2
, which inherited everything from the originalsystemEventQueue
.After the new Thread is started and the Queue is set up the old thread NEEEDS to be terminated. If not so - in case it unblocks it will continue to process the queue and then it gets messy. The system is not ready to be processed by two threads in parallel.
Of course, I can always do something a little evil:
This starts a new EventDispatchThread, allowing use of the application UI. I was able to save data as if I were a user. I'm not sure of what downsides there might be. Maybe there's a less scary way of restarting a blocked EDT?