问题
I was studying a clojure lib when I noticed that a mutable field was annotated with ^:unsynchronized-mutable. Mutable is mutable, but I had no idea what the unsynchronized part meant, so I read the docs, which contain:
Note well that mutable fields are extremely difficult to use correctly, and are present only to facilitate the building of higher level constructs, such as Clojure's reference types, in Clojure itself. They are for experts only - if the semantics and implications of :volatile-mutable or :unsynchronized-mutable are not immediately apparent to you, you should not be using them.
I couldn't get the nuance: is it saying that in practice it doesn't matter which mutability annotation I choose, or that people should just forget about using mutable types altogether?
And, for the sake of curiosity, in a lower level of abstraction, what is the semantic difference between them?
Thanks!
回答1:
Well, it's not saying that "people" should forget about using mutable types. It's saying that any person using them should know the difference between unsynchronized and volatile (and implying that this is not a Clojure-specific issue, since otherwise it would be explained in the docstring). I don't know offhand of a single definitive explanation, but you should understand the java memory model, and about threading and synchronization in general, before using Clojure's mutable deftype fields.
I don't have a definitive reference at hand, but Wikipedia seems like it has a useful article on the topic (nb I found it just now, and have only skimmed it).
回答2:
These are java constructs, which is why you'll not see them referenced anywhere in the clojure documentation except 'don't use this'.
Reads and writes are atomic for all variables declared 'volatile'.
Unsynchronized fields are regular Java mutable fields.
See https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html
Practically speaking, it means that if you have a data structure, when multiple threads access the data for read or write volatile targets will always be consistent; that is, you will always get a data object that is from either completely before, or completely after an operation on that data.
I'm sorry if that doesn't make 100% sense; the semantics are complex; have a read of this if you want a deeper understanding: When exactly do you use the volatile keyword in Java?
tldr;
Volatile is slightly less performant than unsynchronized; but it gives better cross thread data guarantees.
Avoid them both if you can, but if you need to use one, you probably want :volatile-mutable
回答3:
It is saying that if you don't understand the difference between :volatile-mutable
and :unsynchronized-mutable
you should use Clojure's reference types rather than directly using mutable fields.
These two kinds of mutability have different strategies for guaranteeing consistency between threads for shared mutable data, and this results in different performance of read / write operations. Sometimes you can get better performance by fine tuning for usage of a specific kind of mutability. You can get weird and hard to understand bugs if you use them naively.
来源:https://stackoverflow.com/questions/21127636/what-are-the-semantic-implications-of-volatile-mutable-versus-unsynchronized-m