Critical Reference • An occurrence of a variable v is defined to be critical reference: a. if it is assigned to in one process and has an occurrence in another process. b. if it has an occurrence in an expression in one process and is assigned to in another. Limited Critical Reference • A program satisfies the limited-criticalreference (LCR) restriction if each statement contains at most one critical reference • Consider the first occurrence of n in nn+1. It is assigned to in process p and has (two) occurrences in process q, so it is critical by (a). • The second occurrence of n in nn+1 is critical by (b) because it appears in the expression n n+1 in p and is also assigned to in q. • Consider now the version of the statements that uses local variables. Again, the occurrences of n are critical, but the occurrences of temp are not. • Therefore, the program satisfies the LCR restriction. LCR program LCR • Concurrent programs that satisfy the LCR restriction yield the same set of behaviors whether the statements are considered atomic or are compiled to a machine architecture with atomic load and store. Volatile and Non-Atomic Variables • Volatile variables • The single statement in process q can be interleaved at any place during the execution of the statements of p. • Because of optimization during compilation, the computation in q may not use the most recent value of n. • The value of n may be maintained in a register from the assignment in p1 through the computations in p2, p3 and p4, and only actually stored back into n at statement p5. • Furthermore, the compiler may re-order p3 and 4 to take advantage of the fact that the value of n+5 needed in p3 is computed in p4. • These optimizations have no semantic effect on sequential programs, but they do in concurrent programs that use global variables, so they can cause programs to be incorrect. • Specifying a variable as volatile instructs the compiler to load and store the value of the variable at each use, rather than attempt to optimize away these loads and stores. • Concurrency may also affect computations with multiword variables. • A load or store of a full-word variable (32 bits on most computers) is accomplished atomically, but if you need to load or store longer variables (like higher precision numbers), the operation might be carried out non-atomically. • A load from another process might be interleaved between storing the lower half and the upper half of a 64-bit variable. • If the processor is not able to ensure atomicity for multiword variables, it can be implemented using a synchronization mechanism such as those to be discussed throughout the book. • However, these mechanisms can block processes, which may not be acceptable in a real-time system. Concurrency Programs • the normal execution of a program on a computer is not the best way to study concurrency. • Later in this section, we discuss the implementation of concurrency, because eventually you will wish to write concurrent programs using the constructs available in real languages, but for studying concurrency there is a better way. Concurrent Counting Algorithm The algorithm simply increments a global variable twenty times, ten times in each of two processes. CS 556 – Distributed Systems Tutorial on Java Threads Java Threads Threads • A thread is a lightweight process – a single sequential flow of execution within a program • Threads make possible the implementation of programs that seem to perform multiple tasks at the same time (e.g. multi-threaded Web servers) • A new way to think about programming Java Threads Java Threads We will cover: • How to create threads in Java Java Threads How to create Java Threads There are two ways to create a Java thread: 1. Extend the java.lang.Thread class 2. Implement the java.lang.Runnable interface Java Threads Extending the Thread class • In order to create a new thread we may subclass java.lang.Thread and customize what the thread does by overriding its empty run method. • The run method is where the action of the thread takes place. • The execution of a thread starts by calling the start method. Java Threads Example I class MyThread extends Thread { private String name, msg; } public MyThread(String name, String msg) { this.name = name; this.msg = msg; } public void run() { System.out.println(name + " starts its execution"); for (int i = 0; i < 5; i++) { System.out.println(name + " says: " + msg); try { Thread.sleep(5000); } catch (InterruptedException ie) {} } System.out.println(name + " finished execution"); } Java Threads Example I class MyThread extends Thread { private String name, msg; } public MyThread(String name, String msg) { this.name = name; this.msg = msg; } public void run() { System.out.println(name + " starts its execution"); for (int i = 0; i < 5; i++) { System.out.println(name + " says: " + msg); try { Thread.sleep(5000); } catch (InterruptedException ie) {} } System.out.println(name + " finished execution"); } Java Threads Example I class MyThread extends Thread { private String name, msg; } public MyThread(String name, String msg) { this.name = name; this.msg = msg; } public void run() { System.out.println(name + " starts its execution"); for (int i = 0; i < 5; i++) { System.out.println(name + " says: " + msg); try { Thread.sleep(5000); } catch (InterruptedException ie) {} } System.out.println(name + " finished execution"); } Java Threads Example I (cont.) public class test { public static void main(String[] args) { MyThread mt1 = new MyThread("thread1", "ping"); MyThread mt2 = new MyThread("thread2", "pong"); mt1.start(); the threads will run in parallel mt2.start(); } } Java Threads Example I (cont.) • Typical output of the previous example: thread1 thread1 thread2 thread2 thread1 thread2 thread1 thread2 thread1 thread2 thread1 thread2 thread1 thread2 starts its execution says: ping starts its execution says: pong says: ping says: pong says: ping says: pong says: ping says: pong says: ping says: pong finished execution finished execution Java Threads Implementing the Runnable interface • In order to create a new thread we may also provide a class that implements the java.lang.Runnable interface • Preffered way in case our class has to subclass some other class • A Runnable object can be wrapped up into a Thread object – Thread(Runnable target) – Thread(Runnable target, String name) • The thread’s logic is included inside the run method of the runnable object Java Threads Example II class MyClass implements Runnable { private String name; private A sharedObj; public MyClass(String name, A sharedObj) { this.name = name; this.sharedObj = sharedObj; } public void run() { System.out.println(name + " starts execution"); for (int i = 0; i < 5; i++) { System.out.println(name + " says: " + sharedObj.getValue()); try { Thread.sleep(5000); } catch (InterruptedException ie) {} } System.out.println(name + " finished execution"); } Java Threads } Example II (cont.) class A { private String value; public A(String value) { this.value = value; } public String getValue() { return value; } } shared variable public class test2 { public static void main(String[] args) { A sharedObj = new A("some value"); Thread mt1 = new Thread(new MyClass("thread1", sharedObj)); Thread mt2 = new Thread(new MyClass("thread2", sharedObj)); mt1.start(); mt2.start(); } } Java Threads Example II (cont.) • Typical output of the previous example: thread1 thread1 thread2 thread2 thread1 thread2 thread1 thread2 thread1 thread2 thread1 thread2 thread1 thread2 starts execution says: some value starts execution says: some value says: some value says: some value says: some value says: some value says: some value says: some value says: some value says: some value finished execution finished execution Java Threads start() && join() Java • Concurrency is built in to the language. – p.start() puts thread p in the ready (Enabled) queue. – p.join(), executed by main, suspends main until thread p terminates. throws • If a method is capable of causing an exception that it does not handle, it must specify this behavior so that callers of the method can guard themselves against that exception. • You do this by including a throws clause in the method’s declaration. The throw statement • throw expression ; • The type of expression must be a subtype of class Throwable. • The enclosing block statement terminates abruptly. The thrown exception may be caught by a try-catch statement. Class hierarchy (partial) • Throwable • Error – – – – – – – – – OutOfMemoryError Exception IOException RuntimeException ArithmeticException IndexOutOfBoundsException ArrayIndexOutOfBoundsException StringIndexOutOfBoundsException NegativeArraySizeException The try-catch-finally statement try body catch(E1 x1) catchBody1 catch(E2 x2) catchBody2 ... finally finallyBody try-catch with no finally Concurrent Counting Algorithm import java.lang.String; import java.lang.Thread; class Count extends Thread { //field static volatile int n; //constructor void Count() { } //method public void run() { } public static void main(String[] s0) { } } class Count extends Thread { static volatile int n = 0; public void run() { int temp; for (int i = 0; i < 10; i++) { temp = n; n = temp + 1; } } public static void main(String[] args) { Count p = new Count(); Count q = new Count(); p.start(); q.start(); try { p.join(); q.join(); } catch (InterruptedException e) { } System.out.println("The value of n is " + n); } }