Synchronization of non-final field
First of all, I encourage you to really try hard to deal with concurrency issues on a higher level of abstraction, i.e. solving it using classes from java.util.concurrent such as ExecutorServices, Callables, Futures etc.
That being said, there's nothing wrong with synchronizing on a non-final field per se. You just need to keep in mind that if the object reference changes, the same section of code may be run in parallel. I.e., if one thread runs the code in the synchronized block and someone calls setO(...)
, another thread can run the same synchronized block on the same instance concurrently.
Synchronize on the object which you need exclusive access to (or, better yet, an object dedicated to guarding it).
Java - synchronization on non-final field
You're absolutely right. The moment newObject
is exposed to other threads as the new value of someObject
, those other threads are now using a completely different mutex, and so can be executing the "mutually exclusive" code concurrently.
A common solution is to just provide a different mutex and synchronize on that:
private final Object someObjectMutex = new Object();
The right way to synchronize on non-final object in Java
You can simplify your locking strategy:
class MyClass {
private final Object lock = new Object();
private Channel channel = null;
public void setChannel() {
// other code can go here
synchronized (lock) {
channel = new Channel();
// setup channel
}
// other code can go here
}
public void unsetChannel() {
// other code can go here
synchronized (lock) {
channel.close();
channel = null;
}
// other code can go here
}
public boolean isSet() {
synchronized (lock) {
if (channel == null) {
return false;
}
return channel.isActive();
}
}
}
In effect, the lock
object protects any access to the channel variable.
Edited to show where other code that does not interact with channel
might live outside of the locks.
How do I suppress warning Synchronization on a non-final field
For Intellij, put this annotation on the class that has the warnings
@SuppressWarnings("SynchronizeOnNonFinalField")
This lead me to the tag to use for suppression and trial and error lead me to put it on the class instead of on the field or synchronized statement. :-P
When a lock holds a non-final object, can the object's reference still be changed by another thread?
But could a synchronized object's reference also be changed by another thread B while thread A holds the lock for the same object?
If you mean "could another thread change the value of the myTable
variable, the answer is "absolutely"... assuming there's a code path that would allow that. It's a private variable, so you should be able to find all the code that can change the value.
Holding a lock just stops another thread from acquiring the same lock. It doesn't have any effect on what code can access which variables, in itself.
As a side-note, it's important to differentiate between an object, a variable, and the value of the variable (which is a reference, not an object). So there's no such thing as a "final object" - only variables (and classes and methods) can be final. Likewise there's no such thing as a "synchronized object", and you can't change an "object's reference" - you can change the value of a variable so that it's a reference to a different object. Making these distinctions clear in your mind may help you when thinking about what's going on here.
Final variable and synchronized block in java
Basically it just means you can't change the value. For instance variables, you have to assign any final variables once (and only once) in the constructor (or with a variable initializer). Synchronization is a pretty orthogonal concept.
The primary reason for making a local variable final is so you can use it in an anonymous inner class... this has nothing to do with being in a synchronized block.
Final variables are useful for immutable classes, admittedly - and immutability makes life easier in a multi-threaded environment - but that's the only relationship between the two that I can think of...
EDIT: Wildwezyr's comment makes sense in terms of not changing the variable on which you are synchronizing. That would be dangerous, for the reasons he's given. Is that what you meant by "variable in synchronized block"?
Related Topics
Running Multiple Launch Configurations at Once
Eclipse Windowbuilder, Overlapping JPAnels
Spring MVC - How to Return Simple String as JSON in Rest Controller
How to Find Out the Currently Logged-In User in Spring Boot
What Code Folding Plugins Work on Eclipse 3.6
Load Resource from Anywhere in Classpath
Updating Version Numbers of Modules in a Multi-Module Maven Project
Should I Use String.Isempty() or "".Equals(String)
Java Serialization with Non Serializable Parts
Create a New Line in Java's Filewriter
Graphics Rendering in Title Bar
Spring Cache @Cacheable - Not Working While Calling from Another Method of the Same Bean
Stand-Alone Java Code Formatter/Beautifier/Pretty Printer
Why Does Eclipse Complain About @Override on Interface Methods