490 likes | 826 Views
Concurrent Programming. Multithreading. Multiprocessing Using Multiple Processors. Multiprogramming (Batch) Switch and execute different jobs simultaneously, to improve CPU utilization. Multitasking (Interactive)
E N D
Concurrent Programming Multithreading java8Threads
Multiprocessing • Using Multiple Processors. • Multiprogramming (Batch) • Switch and execute different jobs simultaneously, to improve CPU utilization. • Multitasking (Interactive) • Perform more than one task at a time for each user, to improve response time. • Multithreading • Threads in a user task (process) can share code, data, and system resources, and access them concurrently. Each thread has a separate program counter, registers, and a run-time stack. java8Threads
Threads • A single sequential flow of control (of execution of expressions and statements) is called a thread. • A thread independently executes Java code, but may share address space with others. (cf. Process) • In Java, class/instance variables, and array components are shareable among threads; local variables and formal parameters are not. java8Threads
Multithreading is general, convenient, & efficient paradigm for implementing interactive systems. • Independent/cooperating input/processing/display activities. • In single-threaded systems, each application is responsible for interleaving these activities through polling or interrupts. • In multi-threaded systems, these activities are interleaved using a general time-slicingexternal to the application. java8Threads
Multithreading on uni-processor • Cons: Thread scheduling overheads. • Pros: • Concurrency necessary for natural description and fair execution of applications involving shared resources. Multithreaded systems reduce programmer burden by factoring out scheduling. • Improves resource utilization as it incorporates demand-based scheduling and prevents starvation. • Improves responsiveness in interactive systems by assigning priorities to threads and using preemption. • Enables flexible control of one thread from another thread. (E.g., stop, suspend, resume etc.) java8Threads
Further Multi-threading Examples • In multimedia applications (e.g., playing audio and/or video concurrently). • Performing I/O concurrently with scrolling a document (e.g., downloading imagewith a separate“controller” thread). • Periodic updating of the screen with data acquired in real-time (e.g., Sports Ticker, Stock Quotes, Advertisements, etc.). java8Threads
Java Primitives and Examples java8Threads
Mutual exclusion construct is based on Hoare’s monitor. • synchronized methods in a class cannot be run concurrently on behalf of different threads. • Recursive call or Calls to synchronized methods permitted in the same thread. • synchronized statement locks an object. • “Object” is an instance of a class (incl.classClass). • To synchronize “producers” and “consumers” Hoare uses wait/signal on condition variables. • wait() / notify() / notifyAll() etc. enable threads to communicate/regulate each other’s progress. java8Threads
Creating and Running Threads • Define subclass of classThread. Override run() method. • public voidrun(){ } • Create an instance of the subclass, and invoke start() on it. Now run() method executes in an independent thread. • Threads can also be created from an instance of a class implementing the interfaceRunnable. • Required when the class is defined by extension. java8Threads
Example using classThread classEchoextendsThread { public void run() { while (true) System.out.println(“ABC”); } public static void main (String[] args) { newEcho() . start(); newEcho() . start(); } } java8Threads
> javac Echo.java > java Echo Windows 1 ABC 1 ABC 1 ABC 1 ABC 2 ABC 2 ABC 2 ABC 2 ABC 2 ABC 1 ABC 1 ABC 2 ABC 2 ABC 2 ABC 1 ABC . . . with yield() in both OS 1 ABC 2 ABC 2 ABC 2 ABC 1 ABC 1 ABC 2 ABC 2 ABC 2 ABC 2 ABC 2 ABC 1 ABC 1 ABC 1 ABC ... Solaris 1 ABC 2 ABC 1 ABC 2ABC 1 ABC 2 ABC 1ABC 2 ABC 1 ABC 2 ABC ... 1 ABC 1 ABC 1 ABC 1 ABC 1 ABC 1 ABC 1 ABC 1 ABC 1 ABC ... java8Threads
Example using interfaceRunnable classEchoimplements Runnable { public void run() { try { while (true) { Thread.sleep(10); System.out.println(“ABC”); } } catch (InterruptedException e) { return; } } public static void main (String[] args) { Runnabler = newEcho(); newThread(r) . start(); } } java8Threads
Example of Sharing class Shared{ privateintcnt = 0; void print(String Id) { synchronized (this){ System.out.print(Id + “:” + cnt ); System.out.println( “-” + ++cnt); } } } class Shared{ privateintcnt = 0; synchronized void print(String Id) { System.out.print(Id + “:” + cnt ); System.out.println( “-” + ++cnt); } } java8Threads
Threads sharing an object classSharingThreadextendsThread{ private static Shareds = new Shared(); StringId; SharingThread (String Name) { Id = Name; start();} publicvoid run () { while (true) { s.print(Id); } } public static void main (String [] args) { newSharingThread(“A”) ; newSharingThread(“B”) ; } } java8Threads
Motivation for Mutual Exclusion Concurrent Access Mutual Exclusion with yield() A:368-369 A:369-370 B:370-371 A:370-372 A:372-373 A:373-374 A:374-375 B:371-376 B:376-377 B:377-378 B:378-379 B:379A:375-381 A:381-382 A:382-383 A:383-384 -380 A:693-694 A:694-695 A:695-696 B:696-697 B:697-698 B:698-699 B:699-700 B:700-701 B:701-702 A:702-703 A:703-704 A:704-705 A:705-706 ... A:828-829 B:829-830 B:830-831 A:831-832 B:832-833 A:833-834 B:834-835 A:835-836 B:836-837 B:837-838 A:838-839 B:839-840 … java8Threads
Interaction of Language Features run() method case study java8Threads
Subclassing : Access Control class Thread { ... public void run() { } } class SubThread extends Thread { public void run() { ... } // ILLEGAL // void run() { ... } } • Otherwise, run() can be invoked on a SubThread instance via (its reference in) a Thread variable (due to dynamic binding) in another package. L11Threads
Subclassing : Exception class Thread { ... public void run() { } } class SubThread extends Thread { public void run() { ... } // ILLEGAL // public void run() throws InterruptedException{ // sleep(1000); } } • Otherwise,run() invoked on a SubThread instance via a Thread variable (by dynamic binding) can violate the contract that run() of class Thread does not throw any exception. L11Threads
Synchronized • It is illegal to use synchronized for constructors and for method declarations in interfaces. • Can abstract methods besynchronized? • A synchronized method can override or be overridden by a non-synchronized method. However, this does not alter “synchronized”-status of the overridden method accessible using super. • The locks are released whensynchronizedstatements andsynchronizedmethod invocationscomplete abruptly bythrowing anexception. java8Threads
Synchronized Methods • When two threads invoke synchronizedinstance (static) methods simultaneously on the same object, only one thread is permitted exclusive access to the instance (static) fields of the object (class). • When two threads invokesynchronizedinstance methods simultaneously on the same object, the static fields of the class are not locked. • A thread can access fields of an object using a non-synchronizedmethodeven when the object is locked by another thread executing asynchronizedmethod. java8Threads
Methods in classObject • public final voidwait()throwsInterruptedException {...} • Current thread is suspended (after atomically releasing the lock on this) until some other thread invokes notify() or notifyAll() or interrupts. • public final voidnotify(){...} • Notifies exactly one thread waiting on this object for a condition to change. The awakened thread cannot proceed until this thread relinquishes the lock. • public final voidnotifyAll(){...} • Notifies all the threads waiting on this object. These methods must be invoked insidesynchronized codeor else IllegalMonitorStateException will be thrown. java8Threads
Simplified Bounded-Buffer Problem java8Threads
Simplistic 1-Cell Buffer class Buffer { Object x; // synchronized public void put (Object _x, String id) { System.out.println( "Done << " + id + " puts " + _x); x = _x; } // synchronized public Object get (String id) { System.out.println( "Done >> " + id + " gets " + x); return x; } } java8Threads
class Producer extends Thread { private Random r = new Random(); Buffer b; String id; public Producer(Buffer _b, String _id) { b = _b; id = _id; } public void run () { int delay; Integer ir; try { while (true) { delay = Math.abs(r.nextInt() % 1999) + 50; sleep(delay); ir = new Integer(delay); System.out.println("Ready << "+id+" puts "+ ir); b.put(ir, id); } }catch (Exception e){System.out.println("Exception$ " + e);}; } } java8Threads
class Consumer extends Thread { private Random r = new Random(); Buffer b; String id; public Consumer(Buffer _b, String _id) { b = _b; id = _id; } public void run () { int delay; Integer ir = null; try { while (true) { delay = Math.abs(r.nextInt() % 1999) + 50; sleep(delay); System.out.println("Ready >> " + id + " gets "); ir = (Integer) b.get(id); } } catch (Exception e) {System.out.println("Exception$ " + e);}; } } java8Threads
Producer-Consumer : Bounded Buffer public class PCB { public static void main(String[] args) { Buffer b = new Buffer(); new Consumer(b,"C1") . start(); new Producer(b,"P1") . start(); try {Thread.sleep(1000); } catch (Exception e){}; new Consumer(b,"C2") . start(); new Producer(b,"P2") . start(); } } java8Threads
Unfettered Run Ready >> C1 gets Ready << P2 puts 493 Done >> C1 gets null Done << P2 puts 493 Ready << P1 puts 1591 Done << P1 puts 1591 Ready << P1 puts 488 Done << P1 puts 488 Ready >> C2 gets Done >> C2 gets 488 Ready >> C1 gets Done >> C1 gets 488 Ready >> C2 gets Done >> C2 gets 488 Ready << P1 puts 745 Done << P1 puts 745 ... (transient stability?!) ... Ready << P2 puts 815 Done << P2 puts 815 Ready >> C2 gets Done >> C2 gets 815 Ready << P1 puts 1223 Done << P1 puts 1223 Ready >> C1 gets Done >> C1 gets 1223 Ready << P2 puts 403 Done << P2 puts 403 Ready >> C2 gets Done >> C2 gets 403 ... java8Threads
Concurrency control : class Buffer class Buffer { Object x; boolean empty = true; public synchronized void put (Object _x, String id) throws Exception { ...} public synchronized Object get (String id) throws Exception { ... } } • Two producers (consumers) cannot put(get) two items in (from) the same buffer slot simultaneously. • A consumer (producer) is not permitted to get (put) an item from (into) buffer if empty (full). java8Threads
public synchronized void put (Object _x, String id) throws Exception { while (!empty) wait(); empty = ! empty; System.out.println("Done << "+id+" puts "+ _x); x = _x; notifyAll(); } • Note that if-then cannot replace while because notifyAll, due to a consumer, can wake up two waiting producers, and only one producer will find the buffer empty. (“race condition”) java8Threads
public synchronized Object get (String id) throws Exception { while (empty) wait(); empty = ! empty; System.out.println("Done >> "+id+" gets "+x); notifyAll(); return x; } • Note that notify cannot always be used inplace of notifyAll because a consumer may be woken up. • while required because notifyAll due to a producer does not guarantee that wait ing consumers will find a buffer element to read. java8Threads
Synchonization and Mutual Exclusion Ready >> C2 gets Ready >> C1 gets Ready << P1 puts 1672 Done << P1 puts 1672 Done >> C2 gets 1672 Ready << P2 puts 774 Done << P2 puts 774 Done >> C1 gets 774 Ready << P1 puts 168 Done << P1 puts 168 Ready >> C1 gets Done >> C1 gets 168 Ready << P2 puts 1263 Done << P2 puts 1263 Ready >> C1 gets Done >> C1 gets 1263 … ... Ready << P1 puts 622 Done << P1 puts 622 Ready >> C1 gets Done >> C1 gets 622 Ready >> C2 gets Ready << P2 puts 1447 Done << P2 puts 1447 Done >> C2 gets 1447 Ready << P2 puts 96 Done << P2 puts 96 Ready << P2 puts 95 Ready >> C1 gets Done >> C1 gets 96 Done << P2 puts 95 ... java8Threads
Bounded-Buffer Problem java8Threads
Bounded Buffer classQueue { private int c, front = 0, rear = 0, count = 0; private int[] q; Queue(int capacity) { c = capacity; q = new int [c]; } public synchronized void insert (int i) throwsInterruptedException{ … } public synchronized int delete () throwsInterruptedException{ … } } java8Threads
public synchronized void insert (int i) throwsInterruptedException{ while (count == c) wait(); q[rear] = i; rear = (++rear) % c; count++; notifyAll(); } public synchronized int delete () throwsInterruptedException{ while (count == 0) wait(); --count; notifyAll(); int t = front; front = (++front) % c; return q[t]; } java8Threads
Producer classProducerThreadextendsThread{ privateString Id; privateQueue buf; private int init; ProducerThread(String Name,Queue q,int i) { Id = Name; buf = q; init = i; } public void run() { … } } java8Threads
public void run() { try{ while (true) { sleep(10); System.out.println("Produced by " + Id + " " + init); buf.insert(init++); } }catch (InterruptedException e) { System.exit(0); } } java8Threads
Consumer classConsumerThreadextendsThread{ privateString Id; privateQueue buf; ConsumerThread (String Name, Queue q ) { Id = Name; buf = q; } public void run() { … } } java8Threads
public void run() { try{ while (true) { sleep( (new java.util.Random()).nextInt() % 19 ); System.out.println("Consumed by " + Id + buf.delete()); } } catch (InterruptedException e) { System.exit(0); } } java8Threads
Driver Program public classTestBuffer{ staticQueue buffer = newQueue(11); public static void main (String [] args) { ProducerThread p1 = newProducerThread("P1:", buffer, 0); ProducerThread p2 = newProducerThread("P2:", buffer, 10000); ConsumerThread c1 = newConsumerThread("C1:", buffer); ConsumerThread c2 = newConsumerThread("C2:", buffer); p1.start(); p2.start(); c1.start(); c2.start(); } } java8Threads
Priority, Blocking, Scheduling + Semantic subtleties java8Threads
Thread Priority • Range : MIN_PRIORITY ... NORM_PRIORITY ... MAX_PRIORITY • A thread inherits its creator’s priority. It can be inspected (changed) at any time using getPriority (setPriority). • Generally, the continuously running part of an application should run in a lower-priority thread, while the thread dealing with rarer events such as user input should have higher-priority. • When a thread dies, its object does not go away, so its state can still be accessed. java8Threads
Thread States java8Threads
Blocked Thread • A thread is blocked (that is, it is not runnable) if it is: • sleeping. • suspended. • waiting. • executing a “blocked” method. • “blocked” for I/O. • Java neither detects nor prevents deadlocks. • Other Methods: • yield(), join(), etc. java8Threads
Thread Scheduling • Java runs a non-blocked (runnable) highest-priority thread. • A thread can be preempted by a higher prioritythread that becomes runnable. • The scheduler may however choose to run lower priority thread, to avoid starvation. • The same (highest) priority threads are run in round-robin fashion. java8Threads
JVM on Windows uses time-slicing to schedule same priority threads. (“Fair policy”) • JVM on Solaris chooses one of the same priority threads to run until the thread voluntarily relinquishes the CPU (by sleeping, yielding, or exiting), or until a higher priority thread preempts it. java8Threads
Kinds of Thread • User and Daemon. • Each application starts off as a user thread (main()). • A thread’s status can be inspected (changed to daemonbefore starting it ) using getDaemon() (setDaemon(true)). • Threads inherituser/daemon status from their creator. • An application runs until all user threads have completed. When the last user thread completes, any remaining daemon threads are stopped. • To make the application exit when the original thread dies, mark all the created threads daemon. java8Threads
Example: Non-determinism classSample { int a = 1, b = 2; voidh() { a = b + 10; } voidt() { b = a + 100;} } If two different threads concurrently execute h() and t(), then • If h() and t() are synchronized, then the post condition is: • ( a = 12 Ù b = 112 ) Ú ( b = 101 Ù a = 111 ) • If h() and t() are notsynchronized, then: (“non-exhaustive”) • If all vars written back: ...Ú ( a = 12 Ù b = 101) • If all vars not written back: ( a = 1 Ù b = 2 ) Ú ( a = 12 Ù b = 2 ) Ú( a = 1 Ù b = 101 ) Ú ... java8Threads
Example: Out-of-order writes classSimple { int a = 1, b = 2; voidsynchronizedt() { a = 3; b = 4; } voidf() { System.out.println(a + “ ” + b); } } • assign a (use a) precedesassign b (use b) in t() (f()). • t()synchronized, so both a and b written back finally. • f()notsynchronized, so its actions interleaved with t()’s. • No restrictions on the order of reads / writes of different variables from memory. • f(): read(a), t(): write(a), t(): write(b), f(): read(b); • Finally: a = 3 and b = 4. • Printed: 1 4 java8Threads