Download presentation
Presentation is loading. Please wait.
Published byAnnabel Janel Evans Modified over 9 years ago
1
Synchronized and Monitors
2
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
3
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 notifyAll(). 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. notifyAll() 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.
4
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 IllegalMonitorStateException 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 notifyAll(), 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. Not so fast…
5
Here’s an example of some code which gets an Object ’s lock : private Object myLock = new Object(); public boolean add(Object toAdd){ synchronized(myLock){ while(collectionIsFull()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //add to collection myLock.notify(); } public Object remove(){ synchronized(myLock){ while(collectionIsEmpty()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //remove from collection myLock.notify(); } While the collection is full, the thread which is trying to add waits on myL o ck First, the current thread obtains a lock on myLock by passing it to a synchronized block. It is now said to own myLock’s monitor. While myLock is locked in add(), no other thread can enter a block which is also locked by myLock
6
Here’s an example of some code which uses an Object as a lock (monitor): private Object myLock = new Object(); public boolean add(Object toAdd){ synchronized(myLock){ while(collectionIsFull()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //add to collection myLock.notify(); } public Object remove(){ synchronized(myLock){ while(collectionIsEmpty()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //remove from collection myLock.notify(); } When the current thread calls myLock.wait(), it will not do anything until another thread calls myLock.notify(). It releases its lock on myLock, and when it is notified it will return to this statement and run from here.
7
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: AB And here is the Lab: LAB
8
Scientist A needs to use the lab. Seeing it is free, he enters the lab and locks the door ( myLock ). He checks the logs and finds the lab is empty, so he may work. ALAB X 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. BLAB X
9
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. LABAB The Lab is Free! 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 X B
10
Scientist A is back! He would like to make more chemicals. He must also wait until the lab becomes free. 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. LABAB The Lab is Free! LAB X A
11
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 notifyAll() is that notify() will only notify the first Scientist who showed up after the door was locked, while notifyAll() 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. LABBA The Lab is Free! C Tenured Professor In this scenario depicting a call to notifyAll(), 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!
12
Back to the code example: private Object myLock = new Object(); public boolean add(Object toAdd){ synchronized(myLock){ while(collectionIsFull()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //add to collection myLock.notify(); } public Object remove(){ synchronized(myLock){ while(collectionIsEmpty()){ try{ myLock.wait(); }catch(InterruptedException ie){} } //remove from collection myLock.notify(); } Scientist A uses add. If he cannot, he leaves and waits for someone to notify him he can use the lab. He will resume work at this statement when he returns. He locks the door. He checks that he can work. Otherwise he does his business, and notifies the next waiting Scientist. While Scientist A has locked the door, no other Scientist can work in the lab.
13
Here is very similar code with the synchronized keyword applied to the methods: boolean available = false; public synchronized boolean add(Object toAdd){ while(collectionIsFull()){ return false; } available=false; //add to collection available=true; } public synchronized Object remove(){ while(available==false){ return null; } if(collectionIsEmpty()){ 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?
14
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?
15
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.
16
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.
17
Overview: The synchronized keyword denotes a block of code which must be executed without being interrupted (atomically). Locks use wait(), notify(), and notifyAll(). 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
Similar presentations
© 2024 SlidePlayer.com Inc.
All rights reserved.