Li Tak Sing (Lecture 3) COMPS311F 1
Flexible synchronization with locks Synchronized methods and statement blocks: Advantages: Relatively easy to use and understand Once a thread has entered the method or the statement block, no other thread is allowed to enter until the first threads has finished with the method. You can imagine that there is an implicit locking action at the beginning of the method and an implicit unlocking action at the end of the method. Some people also refer to the lock and unlock actions as acquiring a lock and releasing a lock respectively. 2
Flexible synchronization with locks Disadvantages: However, the implicit locking and unlocking with the use of the synchronized keyword may not be adequate for the creation of advanced multi-threaded programs. For example, you cannot specify the maximum time you want to wait to acquire a lock. You cannot perform lock and unlock actions on the same resource in two different methods. 3
Locks Java provides the features of explicit locking and unlocking with the class Lock. A lock is an instance of the Lock interface, which declares the methods for acquiring and releasing locks: void lock(); //Acquires the lock void unlock(); //Releases the lock Condition newCondition(); // Condition A condition presents a physical condition that a thread has to wait if it is not ok to proceed. For example, if you are using a fixed size buffer, a condition represents the case when it is full. The other condition represents the case when it is empty. 4
ReentrantLock The ReentrantLock is a concrete implmentation of Lock. There are two constructors: ReentrantLock(); ReentrantLock(boolean fair); The second constructor allows the setting of the fairness policy. If it is true, then threads waiting for longer period will have higher priority in acquiring the lock. Otherwise, the waiting time is not used in selecting the one to go ahead with the lock. The first constructor is the same as the second one with fair equals to false. 5
Fairness Programs using fair locks accessed by many threads may have poorer overall performance than those using the default setting, but have smaller variances in times to obtain locks and prevent starvation. 6
An example using synchronized methods public class Account { private int balance; synchronized public int balance() {return balance;} synchronized public void setBalance(int b) { balance=b;} The above example is one that uses synchronized method. Now, we can change it to one that uses Lock. 7
An example using locks public class Account { private int balance; private ReentrantLock lock=new ReentrantLock(); public int balance() { try { lock.lock(); return balance; } finally { lock.unlock(); } 8
An example using locks(cont.) public void setBalance(int b) { lock.lock(); balance=b; lock.unlock();} 9
Condition A thread can specify what to do under a certain condition. Conditions are objects created by invoking the newCondition() method on a Lock object. Condition cond=lock.newCondition(); Once a condition is created, you can use its await(), signal(), and signalAll() methods for thread communications. void await(); //Causes the current thread to wait until the condition is signaled. void signal(); //Wakes up one waiting thread. void signalAll(); //Wakes up all waiting threads. 10
Fixed size buffer example public class Buffer { private ReentrantLock lock = new ReentrantLock(); private Condition full = lock.newCondition(); private Condition empty = lock.newCondition(); private int data[] = new int[10]; private int no = 0; 11
public void put(int i) { lock.lock(); try { while (no == 10) { try { full.await(); } catch (Exception e) { } data[no++]=i; empty.signal(); } finally { lock.unlock(); } 12
public int get() { lock.lock(); try { while (no==0) {try {empty.await();} catch (Exception e) {}} full.signal(); return data[--no]; } finally { lock.unlock(); } } 13
Avoiding deadlocks Sometimes two or more threads need to acquire the locks on several shared objects. This could cause a deadlock, in which each thread has the lock on one of the objects and is waiting for the lock on the other objects. 14
Avoiding deadlocks Deadlock is easily avoided by using a simple technique known as resource ordering. With this technique, you assign an order to all the objects whose locks must be acquired and ensure that each thread acquires the locks in that order. 15
A case study: ProgressBarDemo We will demonstrate a program which find all the prime numbers under A progress bar will be used to show the progress. The program can be accessed at 010/build/classes/ProgressBar.html There are two threads in the programs: A thread for finding the prime numbers. A thread for setting the value of the progress bar. 16
Attributes of ProgressBar You can get the source code at: 0/src/ProgressBar.java We are using a JApplet so that we can demonstrate it over the Web. ProgressBar has the following attributes: int no; // this is the current integer being processed int max; //this is the maximum integer to be processed. JProgressBar; //the progressBar Vector primes; //found primes 17
Thread that find prime numbers th = new Thread() { public void run() { for (no = 2; no < max; no++) { int i; for (i = 0; i < primes.size(); i++) { if (no % primes.elementAt(i) == 0) { break; } 18
Thread that find prime numbers if (i == primes.size()) { primes.add(no); if (primes.size() % 10 == 0) { area.append("\n"); } area.append(no + " "); } }; 19
Thread that update the progress bar Thread th = new Thread() { public void run() { try { do { bar.setValue(no); Thread.sleep(100); ProgressBar.this.repaint(); } while (no<max); } catch (InterruptedException e) { } }; 20
Growing circles example In this example, when the user clicks on the window of the program, a circle of size 0 is created at that point. Then, the radius of the circle increases at a rate of 10 per second. When the circle touches the border of the window, it will disappear. 21
Growing circles example You can try the program at: 010/build/classes/GrowingCircle.html The source can be found at 010/src/GrowingCircle.java 22
Inner classes of GrowingCircle It has two inner classes: Circle: this class represent a circle. It is a subclass of thread. The thread will increase the radius of the circle by 10 every second. MyPanel: this is the drawing panel. It also have a thread which will repaint itself 10 times a second. 23
Attributes of GrowingCircle MyPanel panel; //the drawing panel Vector circles; //all created circles. 24
The inner class Circle The declaration of the class: private class Circle extends Thread The attributes: int x, y; //x,y coordinates of the circle int radius; //radius of the circle 25
The constructor of Circle Circle(int x, int y) { this.x = x; this.y = y; radius = 0; synchronized (circles) { circles.add(this); } start(); } 26
The run method of Circle public void run() { try { while (true) { radius += 1; int height = panel.getHeight(); int width = panel.getWidth(); if (y + radius > height || y - radius width || x - radius < 0) { synchronized (circles) { circles.remove(this); } 27
The run method of Circle } Thread.sleep(100); } } catch (InterruptedException e) { } 28
The inner class MyPanel The declaration: private class MyPanel extends JPanel { 29
The constructor of MyPanel public MyPanel() { Thread th = new Thread() { public void run() { try { while (true) { repaint(); Thread.sleep(100); } } catch (InterruptedException e) { } }; th.start(); } 30
The mouseClicked method of the mouse listener private void panelMouseClicked(java.awt.event.MouseEvent evt) { Circle c = new Circle(evt.getX(), evt.getY()); panel.repaint(); } 31