44
Chapter 13: Concurrency Sometimes we want to execute several parts of a program at the same time This is needed to provide GUI and for client/server programming Each of those parts is named as a thread When we program a thread, we assume that it has its own CPU If a computer has only one CPU then its time is shared between threads (time- sliced) A process is a complete program that can be run concurrently with other programs (in a multi-tasking OS) A process may have several threads

Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Embed Size (px)

Citation preview

Page 1: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Chapter 13: Concurrency● Sometimes we want to execute several parts of a

program at the same time● This is needed to provide GUI and for client/server

programming● Each of those parts is named as a thread● When we program a thread, we assume that it has

its own CPU● If a computer has only one CPU then its time is

shared between threads (time-sliced)● A process is a complete program that can be run

concurrently with other programs (in a multi-tasking OS)

● A process may have several threads

Page 2: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Notes (cont.)

● Thread programming is difficult and needs careful coding. Program is not executed serially.

● For such programming we need to know how to synchronize threads and how to have communication between them.

● Java provides mechanism to make an object (or some part of an object) be executed as a thread.

Page 3: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Motivation

● Providing responsive user interfaces●For example a quit bottom lets user stop execution of a program at any time

● Providing services to multiple clinet at the same time

●For example a web server can service multiple http requests at the same time

● Enhancing throughput● For example CPU time is not wasted when some part of program is doing exhustive IO operation

Page 4: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Defining threadspublic class SimpleThread extends Thread { private static Test monitor = new Test(); private int countDown = 5; private static int threadCount = 0; public SimpleThread() { super("" + ++threadCount); // Store the thread name start(); } public String toString() { return "#" + getName() + ": " + countDown; } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; } }

public static void main(String[] args) { for(int i = 0; i < 5; i++) new SimpleThread();

Page 5: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Defining threads (cont.)

monitor.expect(new String[] { "#1: 5", "#2: 5", "#3: 5", "#5: 5", "#1: 4", "#4: 5", "#2: 4", "#3: 4", "#5: 4", "#1: 3", "#4: 4", "#2: 3", "#3: 3", "#5: 3",

"#1: 2", "#4: 3", "#2: 2", "#3: 2", "#5: 2", "#1: 1", "#4: 2", "#2: 1", "#3: 1", "#5: 1", "#4: 1" }, Test.IGNORE_ORDER + Test.WAIT); }}

Page 6: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Yielding – letting scheduler to interrupt the thread

public class YieldingThread extends Thread { private static Test monitor = new Test(); private int countDown = 5; private static int threadCount = 0; public YieldingThread() { super("" + ++threadCount); start(); } public String toString() { return "#" + getName() + ": " + countDown; } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; yield(); } } public static void main(String[] args) { for(int i = 0; i < 5; i++) new YieldingThread();

Page 7: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Sleeping – ceasing execution for a number of milliseconds

public class SleepingThread extends Thread { private static Test monitor = new Test(); private int countDown = 5; public SleepingThread() { super("" + ++threadCount); start(); } public String toString() { return "#" + getName() + ": " + countDown; } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public static void main(String[] args) throws InterruptedException { for(int i = 0; i < 5; i++) new SleepingThread().join();

Page 8: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Prioritypublic class SimplePriorities extends Thread { private static Test monitor = new Test(); private int countDown = 5; private volatile double d = 0; // No optimization public SimplePriorities(int priority) { setPriority(priority); start(); } public String toString() { return super.toString() + ": " + countDown; } public void run() { while(true) { // An expensive, interruptable operation: for(int i = 1; i < 100000; i++) d = d + (Math.PI + Math.E) / (double)i; System.out.println(this); if(--countDown == 0) return; } } public static void main(String[] args) { new SimplePriorities(Thread.MAX_PRIORITY); for(int i = 0; i < 5; i++) new SimplePriorities(Thread.MIN_PRIORITY);

Page 9: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Priority (cont.) "Thread[Thread-3,1,main]: 2", "Thread[Thread-4,1,main]: 2", "Thread[Thread-5,1,main]: 2", "Thread[Thread-6,1,main]: 2", "Thread[Thread-4,1,main]: 1", "Thread[Thread-3,1,main]: 1", "Thread[Thread-6,1,main]: 1", "Thread[Thread-5,1,main]: 1" }, Test.IGNORE_ORDER + Test.WAIT); }}

monitor.expect(new String[] { "Thread[Thread-1,10,main]: 5", "Thread[Thread-1,10,main]: 4", "Thread[Thread-1,10,main]: 3", "Thread[Thread-1,10,main]: 2", "Thread[Thread-1,10,main]: 1", "Thread[Thread-2,1,main]: 5", "Thread[Thread-2,1,main]: 4", "Thread[Thread-2,1,main]: 3", "Thread[Thread-2,1,main]: 2", "Thread[Thread-2,1,main]: 1", "Thread[Thread-3,1,main]: 5", "Thread[Thread-4,1,main]: 5", "Thread[Thread-5,1,main]: 5", "Thread[Thread-6,1,main]: 5", "Thread[Thread-3,1,main]: 4", "Thread[Thread-4,1,main]: 4", "Thread[Thread-5,1,main]: 4", "Thread[Thread-6,1,main]: 4", "Thread[Thread-3,1,main]: 3", "Thread[Thread-4,1,main]: 3", "Thread[Thread-5,1,main]: 3", "Thread[Thread-6,1,main]: 3",

Page 10: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Daemon threads● Providing some services in background as long as program is running● When all non-daemon threads complete program execusion is terminated.

public class SimpleDaemons extends Thread { public SimpleDaemons() { setDaemon(true); // Must be called before start() start(); } public void run() { while(true) { try { sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(this); } } public static void main(String[] args) { for(int i = 0; i < 10; i++) new SimpleDaemons(); }}

Page 11: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Joining a thread

● Join is a mechanism for synchronizing threads● One thread calls join on another thread.

●The effect is that calling thread is suspended until the target thread finishes

● It is possible to specify a timeout to the join.●The effect is that calling thread is suspnded until target thread finishes or timeout period is over, whichever comes sooner

Page 12: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Joining a thread exampleclass Sleeper extends Thread { private int duration; public Sleeper(String name, int sleepTime) { super(name); duration = sleepTime; start(); } public void run() { try { sleep(duration); } catch (InterruptedException e) { System.out.println(getName() + " was interrupted. " + "isInterrupted(): " + isInterrupted()); return; } System.out.println(getName() + " has awakened"); }}

Page 13: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Joining a thread example (cont.)

class Joiner extends Thread { private Sleeper sleeper; public Joiner(String name, Sleeper sleeper) { super(name); this.sleeper = sleeper; start(); } public void run() { try { sleeper.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(getName() + " join completed"); }}

Page 14: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Joining a thread example (cont.)

public class Joining { private static Test monitor = new Test(); public static void main(String[] args) { Sleeper sleepy = new Sleeper("Sleepy", 1500), grumpy = new Sleeper("Grumpy", 1500); Joiner dopey = new Joiner("Dopey", sleepy), doc = new Joiner("Doc", grumpy); grumpy.interrupt(); monitor.expect(new String[] { "Grumpy was interrupted. isInterrupted(): false", "Doc join completed", "Sleepy has awakened", "Dopey join completed" }, Test.AT_LEAST + Test.WAIT); }}

Page 15: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Runnable interface – when a class can't inherit from thread

public class RunnableThread implements Runnable { private int countDown = 5; public String toString() { return "#" + Thread.currentThread().getName() + ": " + countDown; } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; } } public static void main(String[] args) { for(int i = 1; i <= 5; i++) new Thread(new RunnableThread(), "" + i).start(); // Output is like SimpleThread.java }}

Page 16: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

A thread as an inner class// Using a named inner class:class InnerThread1 { private int countDown = 5; private Inner inner; private class Inner extends Thread { Inner(String name) { super(name); start(); } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public String toString() { return getName() + ": " + countDown; } } public InnerThread1(String name) { inner = new Inner(name); }}

Page 17: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Using an annonymous inner class// Using an anonymous inner class:class InnerThread2 { private int countDown = 5; private Thread t; public InnerThread2(String name) { t = new Thread(name) { public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public String toString() { return getName() + ": " + countDown; } }; t.start(); }}

Page 18: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Using a named runnable implementationclass InnerRunnable1 { private int countDown = 5; private Inner inner; private class Inner implements Runnable { Thread t; Inner(String name) { t = new Thread(this, name); t.start(); } public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public String toString() { return t.getName() + ": " + countDown; } } public InnerRunnable1(String name) { inner = new Inner(name); }}

Page 19: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Using anonymous runnable

class InnerRunnable2 { private int countDown = 5; private Thread t; public InnerRunnable2(String name) { t = new Thread(new Runnable() { public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public String toString() { return Thread.currentThread().getName() + ": " + countDown; } }, name); t.start(); }}

Page 20: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

A method to run some code as threadclass ThreadMethod { private int countDown = 5; private Thread t; private String name; public ThreadMethod(String name) { this.name = name; } public void runThread() { if(t == null) { t = new Thread(name) { public void run() { while(true) { System.out.println(this); if(--countDown == 0) return; try { sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } public String toString() { return getName() + ": " + countDown; } }; t.start(); } }}

Page 21: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Creating responsive UIclass UnresponsiveUI { private volatile double d = 1; public UnresponsiveUI() throws Exception { while(d > 0) d = d + (Math.PI + Math.E) / d; System.in.read(); // Never gets here }}public class ResponsiveUI extends Thread { private static Test monitor = new Test(); private static volatile double d = 1; public ResponsiveUI() { setDaemon(true); start(); } public void run() { while(true) { d = d + (Math.PI + Math.E) / d; } } public static void main(String[] args) throws Exception { //! new UnresponsiveUI(); // Must kill this process new ResponsiveUI(); Thread.sleep(300); System.in.read(); // 'monitor' provides input System.out.println(d); // Shows progress }}

Page 22: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Improperly accessing resources

public class AlwaysEven { private int i; public void next() { i++; i++; } public int getValue() { return i; }

public static void main(String[] args) { final AlwaysEven ae = new AlwaysEven(); new Thread("Watcher") { public void run() { while(true) { int val = ae.getValue(); if(val % 2 != 0) { System.out.println(val); System.exit(0); } } } }.start(); while(true) ae.next(); }}

Page 23: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Synchronizing access to shared resources

● The problem in the previous program is that changing the value of “i” (shared resoruce) is not done as an atomic operation● Therefore in the middle of next(), it may be interrupted, leaving object in a inconsistent state● To solve this problem, access to the resource should be synchronized

Page 24: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Synchronizing access example

publicclass SynchronizedEvenGenerator implements Invariant { private int i; public synchronized void next() { i++; i++; } public synchronized int getValue() { return i; } // Not synchronized so it can run at // any time and thus be a genuine test: public InvariantState invariant() { int val = getValue(); if(val % 2 == 0) return new InvariantOK(); else return new InvariantFailure(new Integer(val)); } public static void main(String[] args) { SynchronizedEvenGenerator gen = new SynchronizedEvenGenerator(); new InvariantWatcher(gen, 4000); // 4-second timeout while(true) gen.next(); }}

Page 25: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Critical sections

● Synchronizing a method prevents access to object for full execution of the method● If a method is long then it may suspend execution of other threads for a long period● Sometimes we only need to synchronize some part of a method● This can be done by using critical sections

synchronized(syncObject) { // This code can be accessed // by only one thread at a time}

Page 26: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Critical sections exampleclass Pair { // Not thread-safe

private int x, y;

public Pair(int x, int y) { this.x = x; this.y = y; }

public Pair() {

this(0, 0);

}

public int getX() { return x; }

public int getY() { return y; }

public void incrementX() { x++; }

public void incrementY() { y++; }

public String toString() { return "x: " + x + ", y: " + y; }

}

Page 27: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Critical sections example (cont.)// Protect a Pair inside a thread-safe class:

abstract class PairManager {

protected Pair p = new Pair();

private List storage = new ArrayList();

public synchronized Pair getPair() {

// Make a copy to keep the original safe:

return new Pair(p.getX(), p.getY()); }

protected void store() { storage.add(getPair()); }

// A "template method":

public abstract void doTask();

}

Page 28: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Critical sections example (cont.)// Synchronize the entire method:

class PairManager1 extends PairManager {

public synchronized void doTask() {

p.incrementX();

p.incrementY();

store();

}

}

// Use a critical section:

class PairManager2 extends PairManager {

public void doTask() {

synchronized(this) {

p.incrementX();

p.incrementY();

}

store();

}

}

Page 29: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Making a file handling utility (cont.)

public TextFile(String fileName) throws IOException { super(Arrays.asList(read(fileName).split("\n"))); }

public void write(String fileName) throws IOException { PrintWriter out = new PrintWriter( new BufferedWriter(new FileWriter(fileName))); for(int i = 0; i < size(); i++) out.println(get(i)); out.close(); }

// Simple test: public static void main(String[] args) throws Exception { String file = read("TextFile.java"); write("test.txt", file); TextFile text = new TextFile("test.txt"); text.write("test2.txt"); }}

Page 30: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Thread states● New: The thread object has been created, but it hasn’t been

started yet, so it cannot run.

● Runnable: This means that a thread can be run when the time-slicing mechanism has CPU cycles available for the thread. Thus, the thread might or might not be running at any moment,

● Dead: The normal way for a thread to die is by returning from its run( ) method.

● Blocked: The thread could be run, but there’s something that prevents it. While a thread is in the blocked state, the scheduler will simply skip over it and not give it any CPU time. Until a thread reenters the runnable state, it won’t perform any operations.

Page 31: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Becoming blocked

● You’ve put the thread to sleep by calling sleep(milliseconds), in which case it will not be run for the specified time.

● You’ve suspended the execution of the thread with wait( ). It will not become runnable again until the thread gets the notify( ) or notifyAll( ) message. We’ll examine these in the next section.

● The thread is waiting for some I/O to complete.

● The thread is trying to call a synchronized method on another object, and that object’s lock is not available.

Page 32: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – wait() and notify()

class Order { private static int i = 0; private int count = i++; public Order() { if(count == 10) { System.out.println("Out of food, closing"); System.exit(0); } } public String toString() { return "Order " + count; }}

class WaitPerson extends Thread { private Restaurant restaurant; public WaitPerson(Restaurant r) { restaurant = r; start(); } public void run() { while(true) { while(restaurant.order == null) synchronized(this) { try { wait(); } catch(InterruptedException e) { throw new RuntimeException(e); } } System.out.println( "Waitperson got " + restaurant.order); restaurant.order = null; } }}

Page 33: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – wait() and notify() (cont.)

class WaitPerson extends Thread { private Restaurant restaurant; public WaitPerson(Restaurant r) { restaurant = r; start(); } public void run() { while(true) { while(restaurant.order == null) synchronized(this) { try { wait(); } catch(InterruptedException e) { throw new RuntimeException(e); } } System.out.println( "Waitperson got " + restaurant.order); restaurant.order = null; } }}

Page 34: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – wait() and notify() (cont.)class Chef extends Thread { private Restaurant restaurant; private WaitPerson waitPerson; public Chef(Restaurant r, WaitPerson w) { restaurant = r; waitPerson = w; start(); } public void run() { while(true) { if(restaurant.order == null) { restaurant.order = new Order(); System.out.print("Order up! "); synchronized(waitPerson) { waitPerson.notify(); } } try { sleep(100); } catch(InterruptedException e) { throw new RuntimeException(e); } } }}

Page 35: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – wait() and notify() (cont.)

public class Restaurant { private static Test monitor = new Test(); Order order; // Package access public static void main(String[] args) { Restaurant restaurant = new Restaurant(); WaitPerson waitPerson = new WaitPerson(restaurant); Chef chef = new Chef(restaurant, waitPerson); monitor.expect(new String[] { "Order up! Waitperson got Order 0", "Order up! Waitperson got Order 1", "Order up! Waitperson got Order 2", "Order up! Waitperson got Order 3", "Order up! Waitperson got Order 4", "Order up! Waitperson got Order 5", "Order up! Waitperson got Order 6", "Order up! Waitperson got Order 7", "Order up! Waitperson got Order 8", "Order up! Waitperson got Order 9", "Out of food, closing" }, Test.WAIT); }}

Page 36: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – using pipes for IO between thread

class Sender extends Thread { private Random rand = new Random(); private PipedWriter out = new PipedWriter(); public PipedWriter getPipedWriter() { return out; } public void run() { while(true) { for(char c = 'A'; c <= 'z'; c++) { try { out.write(c); sleep(rand.nextInt(500)); } catch(Exception e) { throw new RuntimeException(e); } } } }}

Page 37: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Cooperation between threads – using pipes for IO between thread (cont.)class Receiver extends Thread { private PipedReader in; public Receiver(Sender sender) throws IOException { in = new PipedReader(sender.getPipedWriter()); } public void run() { try { while(true) { // Blocks until characters are there: System.out.println("Read: " + (char)in.read()); } } catch(IOException e) { throw new RuntimeException(e); } }}

public class PipedIO { public static void main(String[] args) throws Exception { Sender sender = new Sender(); Receiver receiver = new Receiver(sender); sender.start(); receiver.start(); new Timeout(4000, "Terminated"); }}

Page 38: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Deadlock● Thread synchronization and blocking, suspends some threads from execution. This way a series of threads may be waiting for another to complete its task● However, if we have a circular waiting threads none of them can continue its execution● This is called deadlock

Page 39: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Deadlock example – dinning philosophers

● We have a number of philosophers in a room● Each philosopher is in a loop of thinking and eating● There is a round dinning table with plates full of foods ● There is a chopstick in left and right hand of each plate● For each philosopher to start eating, it must have both chopsticks in hand ● Therefore, if all philosophers at the same time get left hand chopstick, they all can't get right hand chopstick (a deadlock situation)

Page 40: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Deadlock example – dinning philosophers - code

class Chopstick { private static int counter = 0; private int number = counter++; public String toString() { return "Chopstick " + number; }}

class Philosopher extends Thread { private static Random rand = new Random(); private static int counter = 0; private int number = counter++; private Chopstick leftChopstick; private Chopstick rightChopstick; static int ponder = 0; // Package access public Philosopher(Chopstick left, Chopstick right) { leftChopstick = left; rightChopstick = right; start(); }

Page 41: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

dinning philosophers – code (cont.) public void think() { System.out.println(this + " thinking"); if(ponder > 0) try { sleep(rand.nextInt(ponder)); } catch(InterruptedException e) { throw new RuntimeException(e); } } public void eat() { synchronized(leftChopstick) { System.out.println(this + " has " + this.leftChopstick + " Waiting for " + this.rightChopstick); synchronized(rightChopstick) { System.out.println(this + " eating"); } } } public String toString() { return "Philosopher " + number; } public void run() { while(true) { think(); eat(); } }}

Page 42: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

dinning philosophers – code (cont.)

public class DiningPhilosophers { public static void main(String[] args) { if(args.length < 3) { System.err.println("usage:\n" + "java DiningPhilosophers numberOfPhilosophers " + "ponderFactor deadlock timeout\n" + "A nonzero ponderFactor will generate a random " + "sleep time during think().\n" + "If deadlock is not the string " + "'deadlock', the program will not deadlock.\n" + "A nonzero timeout will stop the program after " + "that number of seconds."); System.exit(1); } Philosopher[] new Philosopher[Integer.parseInt(args[0])]; Philosopher.ponder = Integer.parseInt(args[1]); Chopstick left = new Chopstick(), right = new Chopstick(), first = left;

Page 43: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

dinning philosophers – code (cont.)

int i = 0; while(i < philosopher.length - 1) { philosopher[i++] = new Philosopher(left, right); left = right; right = new Chopstick(); } if(args[2].equals("deadlock")) philosopher[i] = new Philosopher(left, first); else // Swapping values prevents deadlock: philosopher[i] = new Philosopher(first, left); // Optionally break out of program: if(args.length >= 4) { int delay = Integer.parseInt(args[3]); if(delay != 0) new Timeout(delay * 1000, "Timed out"); } }}

Page 44: Chapter 13: Concurrency ● Sometimes we want to execute several parts of a program at the same time ● This is needed to provide GUI and for client/server

Deadlock conditionsMutual exclusion: At least one resource used by the threads must not

be shareable. In this case, a chopstick can be used by only one philosopher at a time.

At least one process must be holding a resource and waiting to acquire a resource currently held by another process. That is, for deadlock to occur, a philosopher must be holding one chopstick and waiting for the other one.

A resource cannot be preemptively taken away from a process. All processes must only release resources as a normal event. Our philosophers are polite and they don’t grab chopsticks from other philosophers.

A circular wait must happen, whereby a process waits on a resource held by another process, which in turn is waiting on a resource held by another process, and so on, until one of the processes is waiting on a resource held by the first process