In the book "Java Concurrency in Practice" the following code is attached:
public class Counter {
private long value = 0;
public synchronized long getValue() {
return value;
}
public synchronized void increment() {
++value;
}
}
Here is the value field with type long, as well as synchronized read and increment methods.
Do I understand correctly that the synchronization of the read method is needed only for the long and double types, because they are not atomic? And if the field value is of type int, synchronization of the read method will be unnecessary?
You need to synchronize the getValue method.
In Java, the synchronized keyword gives you both visibility and atomicity guarantees. As a rule of thumb, you should remember that the compiler developers and CPU vendors are free to do optimizations such as memory reordering or caching variables in registers as long as the behavior of the optimized program remains unchanged in a single-threaded environment.
Now let's see what happens when different threads call the getValue and increment methods, and the getValue is no longer synchronized. From the perspective of JVM, any thread that only reads the value and never updates it through the increment method is effectively always reading the same constant value. So inside the reader thread, JVM might choose to save the variable in a register and never read it from memory again!
As the comments have suggested, the synchronized keyword can be removed by changing the type of value from an int to AtomicInteger. But even if you don't want to use an AtomicInteger, you can rewrite your class like this:
public class Counter {
private volatile int value = 0;
public int getValue() {
return value;
}
public synchronized void increment() {
++value;
}
}
The volatile keyword will ensure visibility, and the reads no longer require any locking. I suggest checking these references to learn more about Java Memory Model:
https://jenkov.com/tutorials/java-concurrency/index.html
https://docs.oracle.com/javase/specs/jls/se17/html/jls-17.html
Related
Java Code:
public class IncreaseTest {
public static int value = 0;
public synchronized int increment() {
return value++;
}
}
Is method increment() thread-safe? Do I have to add the modifier keyword volatile as follows:
public static volatile int value = 0;
This code is not thread-safe. The instance method will synchronize on an instance, if you have multiple instances they will not use the same monitor and therefor the updates can interleave.
You either need to remove the static from the value field or add static to the increment() method.
Also, as you have made value public, there is the additional problem that value can be changed or read outside of this method without using synchronisation which could result in reading old values.
So changing your code to the following will make it thread-safe:
public class IncreaseTest {
private int value = 0;
public synchronized int increment() {
return value++;
}
}
You should probably use atomicvars
If you are using this method in two threads then you do need the volatile keyword. Without it, another thread may not get the most up to date value. (C#)
I do not think this is thread safe since the static variable is public and can be accessed by other threads in a non-thread safe manner. In order to be thread safe you must declare the variable as follows:
public static volatile int value;
Now value being volatile, will be accessed in a synchronized block.
... without additional synchronization ? The Tree class below is meant to be accessed by multiple threads (it is a singleton but not implemented via an enum)
class Tree {
private volatile Node root;
Tree() {
root = new Node();
// the threads are spawned _after_ the tree is constructed
}
private final class Node {
short numOfKeys;
}
}
Will updates to the numOfKeys field be visible to reader threads without any explicit synchronization (notice that both readers and writers have to acquire an instance of ReentrantReadWriteLock - same instance for each node - but barring that) ? If not would making numOfKeys volatile suffice ?
Is changing the root as simple as root = new Node() (only a writer thread would change the root, apart from the main thread which calls the Tree constructor)
Related:
multiple fields: volatile or AtomicReference?
Is volatile enough for changing reference to a list?
Are mutable fields in a POJO object threadsafe if stored in a concurrentHashMap?
Using volatile keyword with mutable object
EDIT: interested in post Java 5 semantics
No.
Placing a reference to an object in a volatile field does not affect the object itself in any way.
Once you load the reference to the object from the volatile field, you have an object no different from any other object, and the volatility has no further effect.
The are two question. Let's start with the second.
Assigning newly constructed objects to volatile variables works nicely. Every thread, that reads the volatile variable, will see a fully constructed object. There is no need for further synchronization. This pattern is usually seen in combination with immutable types.
class Tree {
private volatile Node node;
public void update() {
node = new Node(...);
}
public Node get() {
return node;
}
}
Regarding the first question. You can use volatile variables to synchronize access to non-volatile variable. The following listing shows an example. Imagine that the two variables are initialized as shown, and that the two methods are executed concurrently. It is guaranteed, that if the second thread sees the update to foo, it will also see the update to bar.
volatile int foo = 0;
int bar = 0;
void thread1() {
bar = 1;
foo = 1; // write to volatile variable
}
void thread2() {
if (foo == 1) { // read from volatile variable
int r = bar; // r == 1
}
}
However, your example is different. The reading and writing might look as follows. In contrast to the above example, both threads read from the volatile variable. However, read operations on volatile variables do not synchronize with each other.
void thread1() {
Node temp = root; // read from volatile variable
temp.numOfKeys = 1;
}
void thread2() {
Node temp = root; // read from volatile variable
int r = temp.numOfKeys;
}
In other words: If thread A writes to a volatile variable x and thread B reads the value written to x, then after the read operation, thread B will see all write operations of thread A, that occurred before the write to x. But without a write operation to a volatile variable, there is no effect on updates to other variables.
That sounds more complicated than it actually is. Actually, there is only one rule to consider, which you can find in JLS8 §17.4.5:
[..] If all sequentially consistent executions are free of data races, [..] then all executions of the program will appear to be sequentially consistent.
Simply put, a data race exists if two threads can access the same variable at the same time, at least one operation is a write operation, and the variable is non-volatile. Data races can be eliminated by declaring shared variables as volatile. Without data races, there is no problem with visibility of updates.
This honestly compiles and runs in Java 7
Just what the question says - while it is technically legal to do so, if you call synchronized on some method variable, does it actually achieve anything? Or is it, because method variables exist within their own little world, going to fail to achieve anything worthwhile?
eg:
public int getX(){
Integer k = 12;
synchronized (k) {
System.out.println("meow");
}
return x;
}
You're asking the wrong question. Whether the variable is local is irrelevant, as shown in the following example:
class Test {
private Map<String, String> map = new HashMap<>();
public void put(String key, String value) {
Map<String, String> localMap = this.map;
synchronized (localMap) {
localMap.put(key, value);
}
}
}
The local reference is actually necessary if there's a possibility that the field could be replaced while you're in the synchronized block.
So the real question is whether you should ever lock on a private value, that is, an object not available to other threads. You may think your example demonstrates such a case, but per the JLS, the autoboxed Integer 12 is cached, meaning you're actually synchronizing on a global value.
Now, assuming you have a local value that's actually private to its thread, there's generally no point in synchronizing on it, and I think some analyzers will warn you if you try. However, see here and here for a possible exception.
say I have the following two classes.
public class Foo {
private volatile Integer x = 0;
private volatile boolean istrue = false;
public void setInt(int x) {
this.x = x;
}
public void setBoolean(boolean istrue) {
this.istrue = istrue;
}
public Integer getInt() {
return x;
}
}
vs
public class Bar {
private volatile AtomicInteger x = 0;
private volatile AtomicBoolean istrue = false;
public void setInt(int x) {
this.x.set(x);
}
public void setBoolean(boolean istrue) {
this.istrue.set(istrue);
}
public Integer getInt() {
return this.x.get();
}
}
Assume multiple threads can access Foo or Bar. Are both classes thread safe? what is the difference between the two classes really?
In the current example you have single assignment statements in the methods. I think you need to come up with a better example. Because the assignment will be executed in a single instruction. Which makes both the implementation thread safe. Even though, it is possible that, two different threads see different values of the int when they access them, because by the time, other thread can potentially reset (set) to a different value.
Check this out: What is thread Safe in java?
Both classes are thread safe as written. The difference between use of a volatile variable and the java.util.concurrent.atomic classes is that the atomic classes permit more complex operations, such as compare and set, to be performed atomically. With just direct access to a volatile variable, there could be a thread context switch between the compare and the set, so you can't rely on the result of the compare still being valid when the set is done.
Both classes are thread safe. But that is not your issue here.
Foo: reads and writes to the fields are atomic. But more complex operations such as i++ are not. i++ translates to i = i + 1, which decomposes to a read and a write, so there could a thread context switch in between making the entire operation not atomic.
Bar: the volatile makes the access to the Atomic fields themselves atomic, so you can reassign the fields with new references in an atomic ways. The operations on the fields like compareAndSet or inc however are atomic. Question is, do you need atomic write access to the fields or just atomicity on the operations? As the AtomicXXX type are just containers for for values, you typically don't reassign the variable, but reassign values, which is atomic.
So this should be sufficient:
private final AtomicInteger x = new AtomicInteger(0);
private final AtomicBoolean istrue = new AtomicBoolean(false);
... without additional synchronization ? The Tree class below is meant to be accessed by multiple threads (it is a singleton but not implemented via an enum)
class Tree {
private volatile Node root;
Tree() {
root = new Node();
// the threads are spawned _after_ the tree is constructed
}
private final class Node {
short numOfKeys;
}
}
Will updates to the numOfKeys field be visible to reader threads without any explicit synchronization (notice that both readers and writers have to acquire an instance of ReentrantReadWriteLock - same instance for each node - but barring that) ? If not would making numOfKeys volatile suffice ?
Is changing the root as simple as root = new Node() (only a writer thread would change the root, apart from the main thread which calls the Tree constructor)
Related:
multiple fields: volatile or AtomicReference?
Is volatile enough for changing reference to a list?
Are mutable fields in a POJO object threadsafe if stored in a concurrentHashMap?
Using volatile keyword with mutable object
EDIT: interested in post Java 5 semantics
No.
Placing a reference to an object in a volatile field does not affect the object itself in any way.
Once you load the reference to the object from the volatile field, you have an object no different from any other object, and the volatility has no further effect.
The are two question. Let's start with the second.
Assigning newly constructed objects to volatile variables works nicely. Every thread, that reads the volatile variable, will see a fully constructed object. There is no need for further synchronization. This pattern is usually seen in combination with immutable types.
class Tree {
private volatile Node node;
public void update() {
node = new Node(...);
}
public Node get() {
return node;
}
}
Regarding the first question. You can use volatile variables to synchronize access to non-volatile variable. The following listing shows an example. Imagine that the two variables are initialized as shown, and that the two methods are executed concurrently. It is guaranteed, that if the second thread sees the update to foo, it will also see the update to bar.
volatile int foo = 0;
int bar = 0;
void thread1() {
bar = 1;
foo = 1; // write to volatile variable
}
void thread2() {
if (foo == 1) { // read from volatile variable
int r = bar; // r == 1
}
}
However, your example is different. The reading and writing might look as follows. In contrast to the above example, both threads read from the volatile variable. However, read operations on volatile variables do not synchronize with each other.
void thread1() {
Node temp = root; // read from volatile variable
temp.numOfKeys = 1;
}
void thread2() {
Node temp = root; // read from volatile variable
int r = temp.numOfKeys;
}
In other words: If thread A writes to a volatile variable x and thread B reads the value written to x, then after the read operation, thread B will see all write operations of thread A, that occurred before the write to x. But without a write operation to a volatile variable, there is no effect on updates to other variables.
That sounds more complicated than it actually is. Actually, there is only one rule to consider, which you can find in JLS8 §17.4.5:
[..] If all sequentially consistent executions are free of data races, [..] then all executions of the program will appear to be sequentially consistent.
Simply put, a data race exists if two threads can access the same variable at the same time, at least one operation is a write operation, and the variable is non-volatile. Data races can be eliminated by declaring shared variables as volatile. Without data races, there is no problem with visibility of updates.