ConcurrentModificationException in CefApp.dispose()

Having problems with building or using the JCEF Java binding? Ask your questions here.

ConcurrentModificationException in CefApp.dispose()

Postby Aaron » Fri Dec 18, 2015 10:22 am

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().
Aaron
Newbie
 
Posts: 8
Joined: Fri Dec 18, 2015 9:53 am

Re: ConcurrentModificationException in CefApp.dispose()

Postby magreenblatt » Fri Dec 18, 2015 10:50 am

CefApp.dispose() should iterate over a copy of the clients_ collection. Please create an issue in the JCEF issue tracker. A pull request to fix the problem is welcome.
magreenblatt
Site Admin
 
Posts: 12408
Joined: Fri May 29, 2009 6:57 pm

Re: ConcurrentModificationException in CefApp.dispose()

Postby Aaron » Fri Dec 18, 2015 11:04 am

Aaron
Newbie
 
Posts: 8
Joined: Fri Dec 18, 2015 9:53 am


Return to JCEF Forum

Who is online

Users browsing this forum: No registered users and 52 guests