Unless my diagnostics are incorrect then there is not synchronization and any non-atomic operations on shared data in VM are not thread-safe.
But even if you don't trust my diagnostics one can arrive at the same conclusion analytically because it's easy to block a Notify() thread by calling something like menu or dialog code. Yet even though that thread blocks the audio keeps working. Therefore ProcessSample() MUST asynchronously interrupt Notify() if they share the same process (which they do).
Fortunately in practice simple modules don't crash because they use the linear flow model I mentioned earlier where only primitive data is used and only UI threads write and ProcessSample() only reads shared data.
But as borkman correctly states operations on longs and doubles (even assignment) are not guaranteed to be atomic in the Java Virtual Machine and Get/GetValue use doubles so there is the postential for a thread switch to occur between the two 32 bit chunks. However in CA's code with a bit of luck these variables are marked with the volatile keyword so writes to them will be atomic.
However even if not it's statistically very unlikely ithat you'll ever split the 64 bits in two and if/when it does happen it's just going to create "noise" in the double's value. Noise that is likey to be filtered out by SmoothValue or any other filtering/slew limiting so it will result in a slight glitch or maybe some freakish behaviour like a button press being ignored once in a hundred presses for no apparent reason.
Now there is debate about whether double assignments actually are atomic or not in practice given that virtually everybody is now using 64 bit architecture. My understanding is that a JVM can handle doubles atomically but it's not guaranteed to. You need to use the voltatile keyword to explicitly mark doubles to be sure...
https://docs.oracle.com/javase/specs/jl ... l#jls-17.7
One possibility is that early in a Votlage Module session the bytecode is being interpreted and double assignment is non-atomic but once HotSpot does its JIT compilation they do become atomic.
To pass a fragile data structure such as an ArraList from a Notify() thread to ProcessSample() one must use some synchronization technique. Now as reference assignment is guaranteed to be atomic one simple way to do this is to use atomic pointers as I mentioned previously. Here one has two separate objects. One that can be safely modified by a Notify() thread and another that is in effect immutable that's read by ProcessSample(). When your Notify() thread is done and the object is stable you can then do an atomic refernce assignment that changes the object seen by ProcessSample() in a safe manner without having to pay the performance penalty of a lock.
So to summarize. It's only when you want to do non-trivial stuff that this becomes a serious issue. Then you need to take care of thread-safety yourself. Ideas like getting the GUI Update thread to handle things safely without any explicit synchronization only appear to work they don't actually.