Let me use this small and simple sample:
class Sample { private String msg = null; public void newmsg(String x){ msg = x; } public String getmsg(){ String temp = msg; msg = null; return temp; } }
Let's assume the function newmsg()
is called by other threads that I don't have access to.
I want to use the synchonize method to guarantee that the string msg
is only used by one function per time. In other words, function newmsg()
cannot run at the same time as getmsg()
.
To make this code properly synchronized in Java you need to either make both method static or nonstatic or use java synchronized block instead of java synchronized method. By the way, this is one of the common mistake Java developers make while synchronizing their code.
Major difference between lock and synchronized: with locks, you can release and acquire the locks in any order. with synchronized, you can release the locks only in the order it was acquired.
When we use a synchronized block, Java internally uses a monitor, also known as monitor lock or intrinsic lock, to provide synchronization. These monitors are bound to an object; therefore, all synchronized blocks of the same object can have only one thread executing them at the same time.
When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
That's pretty easy:
class Sample { private String message = null; private final Object lock = new Object(); public void newMessage(String x) { synchronized (lock) { message = x; } } public String getMessage() { synchronized (lock) { String temp = message; message = null; return temp; } } }
Note that I didn't either make the methods themselves synchronized or synchronize on this
. I firmly believe that it's a good idea to only acquire locks on objects which only your code has access to, unless you're deliberately exposing the lock. It makes it a lot easier to reassure yourself that nothing else is going to acquire locks in a different order to your code, etc.
For this functionality you are better off not using a lock at all. Try an AtomicReference.
public class Sample { private final AtomicReference<String> msg = new AtomicReference<String>(); public void setMsg(String x) { msg.set(x); } public String getMsg() { return msg.getAndSet(null); } }
No locks required and the code is simpler IMHO. In any case, it uses a standard construct which does what you want.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With