Hi,
I'm running into a ConcurrentModificationException that seems to hint at a fundamental problem in CefApp.dispose(). Though it's entirely possible that our code is not calling dispose() in the expected fashion.
Basically, CefApp.dispose() loops over all the CefClients in it's clients_ collection, calling CefClient.dispose() on each one. Downstream from this call I see native code triggering calls to CefClient.onBeforeClose() on a separate thread. CefClient.onBeforeClose() eventually triggers a call to CefApp.clientWasDisposed(), which attempts to call remove() on our clients_ collection. What I'm seeing is that on our call into CefApp.dispose(), we are sometimes still looping over our CefClients at the time the native call to CefClient.onBeforeClose happens on a different thread, resulting in a ConcurrentModificationException.
If I only have one or two clients I don't see this happen, but if I have more than 4 or 5 I see it happen pretty frequently. I feel like having 4 clients open in an application isn't really a corner case, which is why I suspect we're not calling the code properly, otherwise someone else would've hit this issue a long time ago.
Here's what our application shutdown logic looks like today:
1. call CefApp.dispose()
2. after dispose() finishes, for each CefClient we have, loop over it's CefBrowsers and call cefClient.onBeforeClose(cefBrowser) for each one
3. We have a CefAppHandler registered that calls System.exit() when the CefAppState is changed to TERMINATED. So once 2 finishes, this gets triggered.
Prior to adding step 2 we found that CefApp.shutdown() was never being triggered, because presumably CefApp.clientWasDisposed() wasn't being called. In general, it feels like sometimes native code triggers a call to CefClient.onBeforeClose() and sometimes it doesn't. When it doesn't we have to do it ourselves (step 2 above), and when it does, we get a ConcurrentModificationException because it happens before our call to CefApp.dispose() returns.
So, I guess my real question is what's the proper way to shutdown a JCEF application? If what we're doing is correct, I suspect there may be a bug in CefApp.dispose().
Many thanks,
Aaron
p.s. - to clarify, I'm seeing the ConcurrentModificationException occurring irrespective of our "step 2" above. I stepped through in the debugger and saw the Swing thread still looping over CefClients as part of the CefApp.dispose() call while a separate thread called CefClient.onBeforeClose().