A method can be considered thread-safe if simultaneous calls from multiple threads will not create a situation, where any memory space is written by one thread, and simultaneously written/read by another thread at the same time.
This example shows a function that if called by multiple threads can cause issues:
void doThreadNonsense(int input) {
this.myValue = input;
if (this.myValue > 9000) System.out.println("It's over 9000!");
}
Because here a value is first written, then read by multiple threads, and it could happen that Thread A writes a 5, then Thread B writes a 9000, and then Thread A outputs the sentence, because the value is now > 9000, despite the input of 5.
With however just a minor change this function becomes thread-safe:
void doThreadNonsense(int input) {
this.myValue = input;
if (input > 9000) System.out.println("It's over 9000!");
}
Now the value is only written by multiple threads, but since writing an int happens atomically on any 32-bit (or higher) machine, myValue
is only written by one thread or another, but never by both at the same time. This example shows how closely you need to check what your code is doing to figure out whether or not it is thread-safe.
If you take a static method it can - as above - also be not thread-safe:
static int myValue;
static void doThreadNonsense(int input) {
myValue = input;
if (myValue > 9000) System.out.println("It's over 9000!");
}
However in most cases static functions do not write on static variables (this isn't considered clean code by OOP design patterns), and if you don't access anything outside the scope of the method, the code is automatically thread-safe, because all used memory locations are local to the current thread only.
static void doThreadNonsense(int input) {
if (input> 9000) System.out.println("It's over 9000!");
}
So your book should have said: "Static methods that follow the clean code paradigm tend to be thread-safe."
This is however not at all helpful, and completely misses the point why something is thread-safe and other things are not. Take the following example, that is surprisingly (to some) thread-safe, despite that it violates many of the "clean threading" rules:
static final int[][] matrix = new int[N][M];
static void fillMatrixColumn(final int n) {
for (int m = 0; m < M; ++m) {
matrix[n][m] = calculateValue(n, m);
}
}
public static void main(String[] args)() {
IntStream.range(0, N)
.parallel()
.forEach(this::fillMatrixColumn);
printMatrix(matrix);
}
No synchronized, no locking, but a lot of happy writing from multiple threads to the same data structure. This is still thread-safe, because at no point two threads are simultaneously writing to/reading from the same memory location.
x=1;
and you have static methodstatic void increment(){x++}
then you can still face problem with race condition. Static just means that method is invoked on class rather than on instance. If you synchronize it it just means you synchronized it onYourClass.class
literal rather thanthis
instance. – Suction