Synchronized and Monitors synchronized is a Java keyword

  • Slides: 17
Download presentation
Synchronized and Monitors

Synchronized and Monitors

synchronized is a Java keyword to denote a block of code which must be

synchronized is a Java keyword to denote a block of code which must be executed atomically (uninterrupted). It can be applied to methods: public synchronized boolean add(String s){ //synchronized method body } Or to blocks of code: // code above Object obj = new Object(); synchronized(obj){ //synchronized code } //code below

There are three methods in Object we invoke when synchronizing code: wait() (as well

There are three methods in Object we invoke when synchronizing code: wait() (as well as wait(long) and wait(long, int)) This method causes the current thread to wait until another thread invokes notify() or notify. All(). This behavior varies on the two overloaded methods which take arguments. notify() This method wakes up a single thread waiting on this object’s monitor. notify. All() This method wakes up all threads waiting on this object’s monitor. Java uses these methods internally to implement the synchronized keyword. The above methods provide a way for a thread to stop other threads from interrupting it during execution of certain blocks of code.

Not so fast… Eclipse (and other compilers) will let you get away with calling

Not so fast… Eclipse (and other compilers) will let you get away with calling these methods outside of a synchronized block. While this will compile, Java will also throw an Illegal. Monitor. State. Exception as soon as it tries to execute one of these methods. Here’s why: All objects have what is called an intrinsic lock (Also known as a monitor or monitor lock). In order to call wait(), notify(), and notify. All(), you must own an object’s intrinsic lock. Passing an argument to a synchronized block gives the current thread ownership of that object’s lock. Once you own an object’s lock, you can use it for finer thread control.

Here’s an example of some code which gets an Object’s lock : private Object

Here’s an example of some code which gets an Object’s lock : private Object my. Lock = new Object(); public boolean add(Object to. Add){ First, the current thread obtains a lock synchronized(my. Lock){ on my. Lock by passing it to a synchronized block. It is now said while(collection. Is. Full()){ to own my. Lock’s monitor. try{ While the collection is full, my. Lock. wait(); the thread which is trying }catch(Interrupted. Exception ie){} to add waits on my. Lock } //add to collection my. Lock. notify(); } } public Object remove(){ synchronized(my. Lock){ while(collection. Is. Empty()){ try{ While my. Lock is locked my. Lock. wait(); in add(), no other }catch(Interrupted. Exception ie){} thread can enter a block } which is also locked by my. Lock //remove from collection my. Lock. notify(); } }

Here’s an example of some code which uses an Object as a lock (monitor):

Here’s an example of some code which uses an Object as a lock (monitor): private Object my. Lock = new Object(); public boolean add(Object to. Add){ synchronized(my. Lock){ while(collection. Is. Full()){ try{ my. Lock. wait(); }catch(Interrupted. Exception ie){} } //add to collection my. Lock. notify(); } } public Object remove(){ synchronized(my. Lock){ while(collection. Is. Empty()){ try{ my. Lock. wait(); }catch(Interrupted. Exception ie){} } //remove from collection my. Lock. notify(); } } When the current thread calls my. Lock. wait() , it will not do anything until another thread calls my. Lock. notify(). It releases its lock on my. Lock, and when it is notified it will return to this statement and run from here.

A scenario to explain locks: There is an advanced science lab (your data structure)

A scenario to explain locks: There is an advanced science lab (your data structure) which is so dangerous that no two people should be working in it at the same time. Scientists (threads) can get access to the lab if no one else is using it. We have Scientist A and Scientist B. Scientist A makes chemicals for Scientist B. A cannot work if the lab is full of chemicals, and B cannot do any work if the lab has no chemicals. Here are the scientists: A B And here is the Lab: LAB

Scientist A needs to use the lab. Seeing it is free, he enters the

Scientist A needs to use the lab. Seeing it is free, he enters the lab and locks the door (my. Lock). He checks the logs and finds the lab is empty, so he may work. LAB X A Scientist B needs to use the lab. He finds that the door is locked, and so he must wait until he is notified that the lab is free. B LAB X

Scientist A finished making chemicals. He logs that chemicals are in the lab, and

Scientist A finished making chemicals. He logs that chemicals are in the lab, and leaves the door unlocked as he leaves. He also notifies B that the lab is now free. The Lab is Free! LAB A B Scientist B can now enter the lab. He enters and checks that the lab has chemicals. Finding that it does, he can begin to work. Note that if he found the lab had no chemicals and he could not work, he would leave, unlock the door, and wait for notification that he can use the lab. LAB B LAB X

Scientist A is back! He would like to make more chemicals. He must also

Scientist A is back! He would like to make more chemicals. He must also wait until the lab becomes free. LAB A X Scientist B will finish up, update the logs, and leave (unlocking the door on the way out). He will then notify Scientist A that the lab is free. The process will start again. The Lab is Free! LAB B A

It is important to understand that each Scientist does not keep checking back to

It is important to understand that each Scientist does not keep checking back to see if the lab is free. He simply waits until someone else lets him know it is by notifying him. It is possible for someone to disturb him while he is waiting and spur him into doing another task. The difference between notify() and notify. All() is that notify() will only notify the first Scientist who showed up after the door was locked, while notify. All() will notify every Scientist who is waiting. In this case, the Scientist (thread) with highest priority will be the first one who gets to use the lab. The Lab is Free! Tenured Professor LAB C B A In this scenario depicting a call to notify. All(), Scientist A notifies all waiting Scientists that the Lab is free, and the Tenured Professor gets to use the lab even though he was not the first Scientist in line. If only Scientists B and C were waiting, they would compete to get in the lab first. Nerd off!

Back to the code example: private Object my. Lock = new Object(); public boolean

Back to the code example: private Object my. Lock = new Object(); public boolean add(Object to. Add){ Scientist A uses add. synchronized(my. Lock){ He locks the door. He checks that he can work. while(collection. Is. Full()){ try{ If he cannot, he leaves and waits for someone to notify him he can my. Lock. wait(); }catch(Interrupted. Exception ie){} use the lab. He will resume work at this statement when he returns. } //add to collection Otherwise he does his business, and notifies my. Lock. notify(); the next waiting Scientist. } } public Object remove(){ synchronized(my. Lock){ while(collection. Is. Empty()){ try{ my. Lock. wait(); While Scientist A has }catch(Interrupted. Exception ie){} locked the door, no other Scientist can work in the } lab. //remove from collection my. Lock. notify(); } }

Here is very similar code with the synchronized keyword applied to the methods: boolean

Here is very similar code with the synchronized keyword applied to the methods: boolean available = false; public synchronized boolean add(Object to. Add){ while(collection. Is. Full()){ return false; } available=false; //add to collection available=true; } } public synchronized Object remove(){ while(available==false){ return null; } if(collection. Is. Empty()){ available=false; return null; } //remove from collection and return //the appropriate value. } } How does each thread know when to go? When does each thread wait?

In the previous slide, only one thread can modify the data structure through add()

In the previous slide, only one thread can modify the data structure through add() or remove(). We can see that this functions just like using our own explicit lock. How does Java do that? When you apply synchronized to a method, Java uses its own lock object. It uses the instance of the object the method is called on. Example: Foo f = new Foo(); f. bar(); Where bar()is a synchronized method, Java uses f as the argument to the synchronized block. This means that any number of synchronized methods in f will use the same lock. Further, it means that only one synchronized method in f can be used at a given time. An important exception to this is static methods. What happens in this case?

So why use explicit locks? synchronized provides a short-cut for locking multiple methods from

So why use explicit locks? synchronized provides a short-cut for locking multiple methods from accessing the same data structure. Using explicit locks allows greater flexibility. Because all methods with the synchronized keyword share the same monitor, only one can be called at a time. Let’s say we have a class with several sets of methods, where any method in each set can be used concurrently with any method in another set, but no method can be used concurrently with any method in the same set. If we used synchronized on the methods themselves, we would lose the property that any method can be used concurrently with a method in another set. Using several lock objects, one for each set, means we can retain both of these properties.

Some Conventions: • It is never a good idea to pass this to a

Some Conventions: • It is never a good idea to pass this to a synchronized block. Another object might be using your object’s lock! • Similarly, it is never a good idea to pass one of your variables to a synchronized block. They may be using their lock. • Create your own Object to lock on whenever you need something to pass to a synchronized block.

Overview: • The synchronized keyword denotes a block of code which must be executed

Overview: • The synchronized keyword denotes a block of code which must be executed without being interrupted (atomically). • Locks use wait(), notify(), and notify. All(). • Java implements synchronized using these methods. • Explicit Locks can also be made with these methods. • The synchronized keyword makes thread safety easy. • Explicit Locks offer greater flexibility. • Conventions