-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
java.util.ConcurrentModificationException:, even when using stately's concurrent classes 👀 #105
Comments
|
Any more context here? Version, what it's doing, etc? |
Version: ConcurrentMutableList -> ImmutableList
from kotlinx.collections.immutable |
lmk if anything more is needed form my end |
It shouldn't make a difference to the issue, but I would bump up the Stately version when you get a chance. |
Yeah, will do, but wont resolve this issue I believe as u said as well. to note: all traces are coming from ConcurrentMutableIterator.next() |
OK, poking around for a bit now. See how it goes... |
Just ran this: class MiscTest {
@Test
fun testImmutableConversion(){
val l = ConcurrentMutableList<SomeData>()
repeat(20){l.add(SomeData("arst $it"))}
val il = l.toImmutableList()
println(il)
}
}
data class SomeData(val s: String) That works. Will dig through your comments in more detail to see if I can find a good repro. |
Above Snippet is not concurrent right 👀 and being accessed and modifed across multiple threads 👀 |
I actually thought about it after sending this. The problem isn't complicated. Rather obvious looking at it now. I'll have to look at the iterator contract here and think through this a bit. |
This fails, no concurrency needed. Just changing the underlying list. fun testImmutableConversion(){
val l = ConcurrentMutableList<SomeData>()
repeat(20){l.add(SomeData("arst $it"))}
val iter = l.iterator()
iter.next()
l.add(SomeData("Hello"))
iter.next()
val il = l.toImmutableList()
println(il)
} The "simple" answer would be to copy the list and return an iterator to that. Obviously, that means making a whole new list, which isn't great. Also, the returned iterator should be a |
The function above works for iOS, but not JVM (in a single-threaded context only). The plot thickens. |
In some of my use-cases, above is a deal-breaker since list is too extensive and copying will hurt performance, since same operation runs multiple times in some scenarios. |
putting a synchronised lock on list rather than iterator in below shown method would be the simple solution I believe, will have to test, but not at console as of now. |
Not sure what you mean about that. Example code would be good. The issue in my sample code is that any change to the underlying list will "break" the iterator, even in the same thread, so the synchronization doesn't matter. That's JVM-only. On iOS, changes to the underlying list don't break the iterator. For your case, the "simple" solution would be to provide a synchronized method that takes a lambda block, which would allow the creation of the immutable list to happen atomically. Creating and holding onto an iterator, where the delegate may change after the iterator is created, is where this goes off the rails (again, JVM only, although I'm not sure how the native implementations interpret changes to the underlying collection). |
One famous lib is using stately under the hood, so the issue is apparent that it indeed happens on JVM only, can reproduce it on Android and Desktop but not on iOS Stacktrace
|
@kpgalligan yeah I recently tried fixing some concurrent modification exceptions some people were experiencing with kamel by moving from As @FunkyMuse pointed out some people are still experiencing |
The Stately's implementation does not work properly on JVM targets causing ConcurrentModificationException touchlab/Stately#105 Kamel-Media#75
We fixed this issue by using the JDK ConcurrentHashMap on JVM, however a fix would be great either way |
#112 is also related |
Yeah, a fix would definitely be needed for other platforms. |
This is still an issue for both This test verifies it
^^ exception is thrown If you use KTor |
This part of the library needs some attention. Honestly, I had assumed there would be better KMP options popping up, so the implementations were fairly simple. Wrapping mutable collections with synchronize/mutex. The eventual intention was to deprecate this if a much better one emerged (or maybe wrap/delegate to the "better" implementation). With that specifically, I'd need to dig into how iterator is created. After a quick look, |
https://youtrack.jetbrains.com/issue/KT-62423 could this help? It's on the new roadmap |
The text was updated successfully, but these errors were encountered: