问题
I have a java class as below
class User {
String name;
String phone;
public String getName() {
return name;
}
public String getPhone() {
return phone;
}
}
The way this class is used is, for every thread 1 object of this User class is created. Now since there is one copy of object for every thread, can i call this class as thread safe?
Do I need to synchronize these methods?
回答1:
The way you presented it, if each thread has its one copy, then it can be called thread-safe, as maximum of accessing threads is one.
Another thing - if you declare your fields as private
and create the instance of that class as final
, then it's immutable (final User user = new User(...)
). There are no setters, so the object cannot be modified as well as it cannot change its reference. If you wanted to keep the immutability, you would have to make setters return a new instance of this object with changed fields.
@markspace noticed, that better approach would be to declare fields as final, because if you use the previous one and make User
a member of some class, it won't work (unless final).
回答2:
For a class to be thread safe, no matter how many threads are accessing it, its invariants and post-conditions should hold true.
For this class, although there are no write methods, you still need to synchronise the reads. This is because the compiler can cache the state variables (in this case name
and phone
) for each thread (remember each thread has its own set of registers). Thus, if one thread updates the value of any of the state variables, the other thread may not see it and it may read a stale value.
A very easy way do avoid this would be to make the state variables volatile
. It's a weak synchronisation primitive though, and does not provide atomic behaviour like synchronised
does.
Here's the proper way to make this class thread safe:
class User {
GuardedBy("this")String name;
GuardedBy("this")String phone;
public synchronised String getName() {
return name;
}
public synchronised String getPhone() {
return phone;
}
}
Note: Each state variable can use a different lock, depending upon your requirements. I have assumed that somehow both of these variables participate in an invariant together.
Weak synchronisation:
class User {
volatile String name;
volatile String phone;
public String getName() {
return name;
}
public String getPhone() {
return phone;
}
}
For synchronised
methods, every time a thread invokes them, it flushes its cache and reads the latest value from memory, and every time it exists a synchronised
method, it puts the latest values of the variables in memory.
Stale reads can be even more dangerous with 64b
double
and long
, as writes and reads to these data type in Java is not atomic, and can be done in 2 32b
operations. This can lead to some very bad consequences.
Edit: Just saw that each thread will have its own copy of the object. In that case, no synchronisation is needed.
回答3:
Thread Safe Class means that every changes (getting/setting values) into your POJO
class are made Thread Safely
.
It can be achieved by synchronization mechanism.
The general solution is to use keyword synchronized
on the methods or even on your any private logically used object for this purpose.
This keyword just locks the object and you are guaranteed that only one thread will be available to access this method at any given time.
But the best practice (optimized solution) is to reduce code critical section and don't always use synchronized
for an easy/"fast" solution.
来源:https://stackoverflow.com/questions/55134811/how-to-make-java-class-thread-safe