How to synchronize or lock variables in Java?

Let me use this small and simple example:

class Sample { private String msg = null; public void newmsg(String x){ msg = x; } public String getmsg(){ String temp = msg; msg = null; return temp; } } 

Suppose the newmsg() function is called by other threads that I do not have access to.

I want to use the synchonize method to ensure that the msg string is used by only one function at a time. In other words, the newmsg() function cannot work simultaneously with getmsg() .

+63
java synchronization
May 02 '11 at 20:02
source share
6 answers

This is 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; } } } 

Please note that I did not synchronize or synchronize the methods themselves on this . I strongly believe that it is a good idea to get only locks on objects that only your code has access to, unless you intentionally open the lock. This makes it much easier to make sure that nothing else is going to acquire locks in a different order for your code, etc.

+149
May 2 '11 at 20:05
source share
— -

For this functionality, you better not use lock at all. Try 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 are required, and the code is simpler IMHO. In any case, it uses a standard design that does what you want.

+48
May 2 '11 at 20:11
source share

Starting with Java 1.5, it is always a good idea to consider the java.util.concurrent package. This is a modern locking mechanism in Java right now. The synchronization mechanism is heavier than the java.util.concurrent classes.

An example would look something like this:

 import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Sample { private final Lock lock = new ReentrantLock(); private String message = null; public void newmsg(String msg) { lock.lock(); try { message = msg; } finally { lock.unlock(); } } public String getmsg() { lock.lock(); try { String temp = message; message = null; return temp; } finally { lock.unlock(); } } } 
+7
May 2 '11 at 20:24
source share

In this simple example, you can simply put synchronized as a modifier after public in both method signatures.

More complex scenarios require other things.

+2
May 2 '11 at 20:04
source share

Use the synchronized .

 class sample { private String msg=null; public synchronized void newmsg(String x){ msg=x; } public synchronized string getmsg(){ String temp=msg; msg=null; return msg; } } 

Using the synchronized for methods will require threads to get the lock on the sample instance. That way, if any one thread is in newmsg() , no other thread will be able to lock the instance of sample , even if it tried to call getmsg() .

On the other hand, using synchronized methods can become a bottleneck if your methods perform lengthy operations - all threads, even if they want to call other methods on this object that may alternate, still have to wait.

IMO, in your simple example, it's okay to use synchronized methods, since you actually have two methods that should not be interleaved. However, under various circumstances, it may make more sense to synchronize the lock object, as shown in Joh Skeet's answer.

+1
May 2 '11 at 20:05
source share

If in another case, you are synchronizing the collection, rather than the string, perhaps you are iterating over the collection and worried about mutating it, Java 5 suggests:

0
Jan 17 '14 at 3:10
source share



All Articles