Thread safe access to private field

Multi tool use
Thread safe access to private field
So I have the following scenario (can't share the actual code, but it would be something like this):
public class Test
{
private Object obj;
public void init()
{
service.registerListener(new InnerTest());
}
public void readObj()
{
// read obj here
}
private class InnerTest implements Listener
{
public synchronized void updateObj()
{
Test.this.obj = new Object();
// change the obj
}
}
}
The InnerTest
class is registered as listener in a service. That Service is running in one thread the calls to readObj()
are made from a different thread, hence my question, to ensure consistency of the obj
is it enough to make the UpdateObj()
method synchronized?
InnerTest
readObj()
obj
UpdateObj()
While you are guaranteed that only one Thread at once enters your
updateObj
method it is not locked itself. There is still a chance someone also gets hold of the Object before you are done applying changes, potentially creating a race condition. Lino's answer is one of the possible ways to assure this is not an issue.– Ben
Jul 3 at 8:13
updateObj
Yeah that's what I was afraid of, how do I solve it then?
– Stugal
Jul 3 at 8:14
1 Answer
1
I would suggest using another object as a lock to ensure that the class only blocks when the obj
is accessed:
obj
public class Test
{
private final Object lock = new Object();
private Object obj;
public void init()
{
service.registerListener(new InnerTest());
}
public void readObj()
{
synchronized(lock){
// read obj here
}
}
private class InnerTest implements Listener
{
public void updateObj()
{
synchronized(Test.this.lock){
Test.this.obj = new Object();
// change the obj
}
}
}
}
Then use that lock in all methods that need to have consistent access to obj
. In your current example the readObj
and updateObj
methods.
obj
readObj
updateObj
Also as stated in the comments, using synchronized
on the method level in your InnerTest
class, will not really work as you probably intended. That is, because synchronized methods will use a synchronized
block on the this
variable. Which just blocks your InnerTest
class. But not the outer Test
class.
synchronized
InnerTest
synchronized
this
InnerTest
Test
I would suggest expanding the answer by explaining why synchronizing on the inner class instance is not helpful.
– RealSkeptic
Jul 3 at 8:16
@RealSkeptic I didn't even think about that. I edited it into the answer, thanks.
– Lino
Jul 3 at 8:20
Great explanation! Many thanks, before I accept that answer one last question though, is there any incentive/difference in using synchronized as you described vs i.e. Reentrant lock?
– Stugal
Jul 3 at 8:22
@Stugal It really depends on the use case. Can the class be used without the
obj
or is it really dependant on it? In the first case the lock is the better choice. in the second one you'd have to block every call with synchronized methods and in the inner class use synchronized(Test.this)
as a lock. That way you'll synchronize every access that is made. And thus will have a consistent behaviour– Lino
Jul 3 at 8:24
obj
synchronized(Test.this)
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.
Possible duplicate of Java synchronized method lock on object, or method?
– kabanus
Jul 3 at 8:03