I am reading "java concurrency in practice", and the author says: "A program that consists entirely of thread-safe classes may not be thread-safe". How is this possible? I don't seem to understand, can someone provide an example?
How is it possible for a program to contain exclusively thread-safe classes, but not be thread-safe?
-
For example: `if (safeDictionary.ContainsKey(x)) { y = safeDictionary[x]; ... }` is not thread-safe even if dictionary itself is thread-safe. – Evk May 10 '18 at 06:32
-
2Here is a great Java-related example: [Why is Java Vector class considered obsolete or deprecated?](https://stackoverflow.com/questions/1386275/why-is-java-vector-class-considered-obsolete-or-deprecated) – user4581301 May 10 '18 at 06:33
2 Answers
An example would be individual methods on a class that are thread safe, but they are not atomic if you invoke more than one. E.g.
if (!threadSafeCollection.contains(thing)) {
threadSafeCollection.add(thing);
}
This may yield incorrect results if another thread adds to the collection between the contains
and add
invocations in this thread.

- 137,514
- 11
- 162
- 243
-
But how can they be thread-safe if they aren't atomic? In my understanding if a method that's subject to multi-threaded access performs non-atomic operations, then it isn't thread-safe. – Coder-Man May 10 '18 at 06:39
-
@POrekhov depends on how you define thread-safe. Usually this extends only as far as a single operation. You are guaranteed that no-one will delete while you are inserting, but you need extra protection if you have to insert twice. – user4581301 May 10 '18 at 06:41
-
@POrekhov _"But how can they be thread-safe if they aren't atomic?"_ Simply, e.g., by employing a mutex internally. However, this mutex is unlocked between operations in Andy's example, that's the point. – Daniel Langr May 10 '18 at 06:43
-
`contains` is threadsafe in itself. `add` is threadsafe in itself. But two threads trying to add `17` can still both add `17` to the collection, because both check if 17 is in the collection (it's not), then both call `add`, making 17 appear twice. To solve the problem you need an `addIfNotContains` function that does both the checking and adding in a way that is threadsafe. – Mats Petersson May 10 '18 at 06:43
-
@POrekhov people mean different things by "thread safety". But in the case of, say, Java `Vector`, individual calls to `add` are "thread safe" by some definition because there is no interference between the threads when updating internal state. `Vector` is thread-safe with respect to its own invariants, not necessarily yours. – Andy Turner May 10 '18 at 06:43
-
One can argue that after introducing given code - program does not "consists entirely of thread-safe classes" any more. – Evk May 10 '18 at 06:45
-
Of course, there is an almost infinite number of combinations of these sort of things, where an object's operatons are in themselves threadsafe, but if you combine things, it goes wrong. Consider `pos = threadSafeCollection.find(X); if (pos != NOT_FOUND_VALUE) threadSafeCollection.removeAtPos(pos);` - two threads remove the same value (e.g 17), finds it at position 5, then both remove what's at position 5. – Mats Petersson May 10 '18 at 06:47
-
Guys, I think that since this method that contains the if statement isn't thread-safe, then the class that contains this method isn't thread-safe either, and hence it's impossible for a program that contains all thread-safe classes to not be thread-safe. Clearly in this example there's at least 1 class that isn't thread-safe. Maybe a library can be thread-safe, but that doesn't guarantee that regardless of how you use it in your program, your program will remain thread-safe. – Coder-Man May 10 '18 at 06:48
-
@Evk: Most programs contain more than JUST code in classes. At the very least, you typically have a `main` function [or similar] that does some creation of classes, etc. – Mats Petersson May 10 '18 at 06:49
-
@POrekhov It's not the code of that thread-safe class method. It's a code that uses that class. – Daniel Langr May 10 '18 at 06:50
-
-
1@POrekhov: Somewhere, you need the program to DO something witn your classes. That code will ALSO need to consider thread-safety of it's operations. – Mats Petersson May 10 '18 at 06:51
-
@MatsPetersson well I don't know java, but I expect that in this sense it's similar to C#, so main is static method of some class anyway. I expect there is no such thing as method which does not belong to any class. So I'd say statement in question is quite vague. Though I believe author of this statement really meant situations as described in this answer. – Evk May 10 '18 at 06:52
-
@Evk Yes, it's clearly dependent on what you language constructs used. I'm a C++ programmer, I picked this up on the C++ tag that was originally on the question. In C++, `main` is a standalone function. Many other languages do allow a mixture of free-standing functions and member functions. – Mats Petersson May 10 '18 at 07:09
-
@MatsPetersson that's true, though statement in question is from the book named "Java concurrency in practice". – Evk May 10 '18 at 07:12
-
@Evk You could ALSO interpret the question to mean "we have a bunch of pre-defined classes that are internally thread-safe, does that guarantee that all code using these classes will automatically be thread-safe", and again, the answer isn't (necessarily) yes. – Mats Petersson May 11 '18 at 06:15
To add a bit more clarity around this question.
From JCIP (statement 1):
Is a thread safe program one that is constructed entirely of thread safe classes? Not necessarily, a program that consists entirely of thread safe classes may not be thread safe, and a thread safe program may contain classes that are not thread safe. PP 17
And what does B Goetz define as thread-safe? (statement 2)
A class is thread safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code. PP 18
My interpretation of these two statements together makes sense if we interpret statement 1 to mean that the class making the calls to entirely thread safe classes is itself not counted as part of the set of classes in the program. Then one can construct a program with check-then-act problems, an operation that should be atomic but is not, for example, in the answer by Andy Turner above.