I've written a tiny `SingleElementCache<T>` ...
# server
r
I've written a tiny
SingleElementCache<T>
class based on
AtomicReference
. Wondering if anyone can see any issues with it?
SingleElementCache.kt.cpp
And my tests so far:
SingleElementCacheSpec.groovy.cpp
j
its not quite the question you are asking, but this is the same functionality as Guava Suppliers.memoize() and that synchronizes so that you don't get the supplier called concurrently, so maybe easier to use. The implementation is only a few lines.
a
Because @Rob Elliot used an atomic reference I believe the performance guarantees and thread concurrency would far outperform the synchronized solution, though synchronize is obviously the simple safe path for a util library like guava. I would have thought google would have a favored a no lock, no synch implementation though as that is a big tenet of Google's data structure engineering in the past (at least when I've dealt with Google engineering quite a long time ago). The code for this looks pretty good to me (without having done any testing). You keep the logic inside the atomic guaranteed functions as I understand them and always fully replace the value so I believe you are in the clear. If you find out otherwise, I would love to know why as I'm certainly not an expert on the atomic classes. Side story...Google used to have an "easter egg" that specifically advertised their job applications to developers that searched for non-locking concurrent data structures.
r
@James Richardson it looks like I'd have to handle the invalidation by replacing it? Perhaps storing it in a volatile field? I'm always a bit wary of introducing guava if I can avoid it...
Just for fun, a Read/Write lock implementation - unlike the first it should only call the loader once per invalidation. I'm a bit more worried about the one, the double checked locking seems too clever by half, I wouldn't be at all surprised if it's subtly broken. Some (very ropey & naive) micro benchmarking suggests they perform very similarly.
a
I would take the atomic implementation over this any day haha but very interesting.
j
i guess my point was only that if you had doubts about your implementation you could use the guava one. it is well tested and fine. you don't need to use the library, just copy the code, its about 10 lines. sure - it may or may not be the absolute fastest under all conditions, but usually (not always!) the performance of a system wont be constrained by something like this.
a
Totally agree @James Richardson though copying code vs using a library can introduce licensing issues depending on the project and the license. On somewhat of a counter that I've seen in some of my Kotlin server projects, because we use coroutines heavily for request handling and database in particular, a synchronize occurring in common code can hit much more heavily becuase many more tasks are executing "concurrently" on a single thread/core. This means you can end up with a lot more total tasks held up and waits than in a traditional system in my past where a synchronize was default. If something is or is going to become a common framework or ubiquitous method, I'll do the extra work to avoid things like synchronize if its not bad, such as this, with an atomic reference, but if its not a server or not a very common method and the logic is more complex to handle without it I would use synchronize. Just my general perspective of course and nothing is 100%.