Distributed Systems 2 Java Threads Simon Razniewski Faculty
Distributed Systems 2. Java Threads Simon Razniewski Faculty of Computer Science Free University of Bozen-Bolzano A. Y. 2014/2015
Why processes and threads • Several actions within a program – send and receive at the same time – reaction to user input while doing expensive steps (e. g. network communications, calculations, disk fetching) • Examples: – Browser – Skype – Music/video streaming
Process • What is a process? • The unit of computation inside an Operating System • A running program with its data and resources – Code (text) of the program – Data: global variables – Program Counter – CPU registers – Stack: parameters, local variables – Resources: open files, network connections, I/O, … • JVM runs as a single process
Process • What is a process? • The unit of computation inside an Operating System • A running program with its data and resources – Code (text) of the program – Data: global variables – Program Counter – CPU registers – Stack: parameters, local variables – Resources: open files, network connections, I/O, … • JVM runs as a single process
Process States Active process assign CPU creation ready running termination revoke CPU init wait for event terminated blocked • Multitasking system multiple running processes • Single processor one active process – Time sharing, context switch
Thread • Lightweight process: smallest unit of computation that can be scheduled in an O. S. • Shares code and data with other associated threads – Task: set of threads that refer to the same code and data – Process = task with (at least) a single thread! • Task taken as synonym of process • It is a single control-flow within a process • Multithreading like Multitasking • Execution of Java program: JVM creates a thread that executes the main method – Other threads can be dynamically created
Thread: Features • Memory sharing: threads share variables – No reserved memory for data and heap: all threads in a process share the same address space • Private stack and program counter • Low context switch cost – No need to handle code&data – Much more performing than for processes • But… privacy/synchronization issues: threads of the same task can modify each other’s data
Single vs Multithreaded Processes
Java Thread: Big Picture Process Code Static variables Memory Thread 3 Stack 3 local var. , methods PC 3 Thread 1 Stack 1 local var. , methods Thread 2 PC 1 Stack 2 local var. , methods PC 2
Implementation • java. lang. Thread class • Provides the functionalities for a thread • With new(), the thread is created but is still not active • start() activates the thread • start() calls run(), empty method – Extend Thread and override run() in order to implement a thread!
Simple Skeleton class Simple. Thread extends Thread { public void Simple. Thread() { <constructor> } public void run() { <behavior of each instance of Simple. Thread> } } public class Simple. Main { public static void main (string[] args) { Thread t 1=new Simple. Thread(); t 1. start(); //Thread t 1 activated … don’t call run() directly! … //HOW MANY THREADS HERE? } }
A Thread not Thread • Is it possible to define a JAVA thread that does not extend Thread? – JAVA does not support multiple inheritance • Interface Runnable: a class denoting instances that can be run by a thread • How-to – Implement Runnable and its run() method – Create a new object of this class – Create a new Thread passing the object as parameter of the constructor – start() thread
Simple Skeleton class Simple. Runnable extends My. Class implements Runnable { public void run() { <behavior here…> } } public class Another. Simple. Main { public static void main(String args[]){ Simple. Runnable r = new Simple. Runnable(); Thread t = new Thread(r); t. start(); } }
Thread Lifecycle • New Thread – Thread created with new – Still inactive • Runnable = executable (could be in execution) • Not runnable – Cannot be currently scheduled for the execution • Dead – Thread has autonomously finished its execution (end of run()) – stop() method invoked on it
Not Runnable – Why? • Waiting for I/O operation to terminate • Trying to access to synchronized object/monitor queued • One of these methods has been invoked on it – sleep() – wait() – suspend() • Deprecated because prone to deadlock • We will discuss these cases in detail…
Stopping a Thread • Idea: stop the execution of a thread • stop() is deprecated because unsafe – We will see the notion of (un)locking – Basically, stop() causes the thread to immediately release all resources (unexpectedly) – Objects protected by the lock could be in an inconsistent state, and now accessed by other threads • In general, google “Java Thread Primitive Deprecation”
How to Stop a Thread • Using a recurring pattern (we will re-use it later on) private Thread myself; public void stop() { //user-defined! myself = null; } public void run() { Thread this. Thread = Thread. current. Thread(); while (myself == this. Thread) { <behavior here…> //RECHECK CONDITION IF THE CODE IS LARGE } }
A Shared Counter • Parallel. Counter – increment() increments the counter – decrement() decrements the counter • Counting. Thread – Parameters: • String name • Int times – Execution: increments or decrements the counter for times
What Happens? Incrementor i 1 = new Counting. Thread("A", 5000000); Incrementor i 2 = new Counting. Thread("B", 5000000); i 1. start(); i 2. start(); while (!i 1. has. Finished || !i 2. has. Finished) {} System. out. println(counter); What is the final value of the counter (when both i 1 and i 2 have finished)?
Counter static void increment() { counter++; } Byte code cur counter cur + 1
Counter static void increment() { counter++; } Byte code cur counter cur + 1 What if we have a context switch here? Remember: counter is shared, cur is local
Counter static void increment() { int cur. Val = counter; Thread. yield(); counter = cur. Val+1; }
The Problem • Threads share the same address space • Common resources: objects can be manipulated by multiple threads at the same time • Interference we need synchronization • Access control mechanisms: to define who and when can correctly access to a resource – No deadlock: situation in which every thread is stuck – No livelock: situation in which threads continuously execute without terminating – No starvation: we must guarantee that all threads can have the possibility of accessing the resource sooner or later
Mutual Exclusion • Operations on a shared objects by different threads cannot overlap in time • No ordering constraint • Critical section: instructions that deal with the object change • Critical sections of the same class cannot overlap • At most one critical section of a class can be executed at a given time
Semaphores (Dijkstra) • Non-negative integers indicating number of parallel accesses allowed • manipulated through atomic operations: signal (V) increment wait (P) decrement • Read semaphore: when value=0, wait causes the thread to wait until the value becomes positive – Passive wait inside a queue – FCFS strategy to avoid starvation • Binary semaphores: mutex
Mutual Exclusion with Semaphores Semaphore s = new Semaphore(1); Thread 1 Thread 2 … s. wait(); <critical section> s. signal(); … N. B. : THIS IS NOT JAVA CODE • This kind of semaphore is a lock
Limits of Semaphores • Low-level programming construct • Easy to introduce errors: deadlock/livelock – Debugging concurrent programs is extremely difficult • Examples in the mutex case – Inverting wait and signal makes it possible to multiple access to the critical section – Using wait twice causes a deadlock Monitor for Objects (Hoare)
Monitor (Abstract Model) • Protects the data of a shared structure/resource – Data (state of the monitor) are persistent and cannot be accessed directly • Object’s data attributes – Public/Entry methods: unique entry point that can modify the state
Monitor Protection Levels • Level 1: mutual exclusion – Public methods are always mutually exclusive: at most one thread can be active inside the monitor (lock) – If another thread tries to access one of the public methods waits into an entry queue – Automatically enforced at the language level • Level 2: regulates the order in which threads can access the resource – When an entry operation is called, it first checks a synchronization condition (that induces an ordering) – Condition not met thread waits, monitor is freed – Suspension managed by the programmer through a condition variable
Condition • Special variable type condition cond; • Represents a queue containing waiting threads • Monitor’s operations manipulate conditions through two operations – wait(cond) – signal(cond)
Signal and Wait • Effect of wait(cond) – Thread is suspended and inserted into cond’s queue – Monitor is freed – The thread will restart the execution after wait(cond), guaranteeing mutual exclusion • Effect of signal(cond) – Reactivates one thread waiting in cond’s queue – Has no effect if cond’s queue is empty
Monitor Queues Monitor Condition queue (C 1) Entry queue Condition queue (C 2) active thread. . . Condition queue (Cn)
Signal Semantics • Execution of signal operation – Signaling thread Q (executes signal(cond)) – Signaled thread P (extracted from cond’s queue) • Both Q and P could execute… who has priority? – Signal and wait: Q halts and P continues • Blocking condition variables – Signal and continue: Q continues, P is notified and waits • Nonblocking condition variables
Signal Semantics: Schema cond. signal_and_wait() cond. signal_and_continue() entry queue condition queue cond. wait() monitor free in execution cond. signal_and_wait() cond. signal_and_continue() NO Call monitor free? YES
Signal and Wait • Signaling thread: Q, signaled thread: P • Q is inserted into the entry queue – Or a second signal queue with higher priority than the entry queue • P is activated and occupies the monitor – No other process can change the condition – Hence P can continue the execution of the method – P restarts after the cond. wait()instruction that blocked it
Signal and Continue (Java) • Signaling thread: Q, signaled thread: P • Q continues (monitor still locked) • P is moved from cond’s queue to the entry queue – Other processes can enter the monitor between Q and P First instruction to be executed by P when it will be selected: re-test the synch. condition! – Pattern: while(!synch_cond) cond. wait(); <access to resource>
Example: Bounded Mailbox • Shared mailbox with capacity N • Monitor: circular message buffer (of size N) • Two entry operations to be executed in isolation – void send(Message m) Cannot be accomplished if the buffer is full – Message receive() Cannot be accomplished if the buffer is empty Producer Thread Consumer Thread
monitor circular_buffer{ messagge buffer[N]; int occupied=0; int head=0; int bottom=0; condition not_full; condition not_empty; public void receive(messagge m){ /*proc. entry -> mutually exclusive */ if (occupied==N) not_full. wait; buffer[code]=m; head=(head + 1)%N; occupied++; not_empty. signal; } public messagge send(){ /*proc. entry -> mutually exclusive */ messagge m; if (occupied == 0) not_empty. wait; m=buffer[head]; bottom=(bottom + 1)%N; occupied--; not_full. signal; return m; } }
Synchronization in Java • Global environment (shared data): threads interact/interfere by operating on shared objects – Competition: synchronized methods, locks – Cooperation: semaphores and wait-notify, conditions • Package java. util. concurrent
Basic Monitor in Java • JVM associates a lock to every object – States whether the object is free/occupied – Entry set queue for suspended threads • Critical sections can be identified with the keyword synchronized – Synchronized methods – Synchronized sections in the code
Synchronized Section • Compiler manages a synchronized section – Adding a prologue for acquiring the object’s lock • Lock free thread can execute the critical section • Lock busy thread suspended into the entry set queue of the object – Adding an epilogue for releasing the lock • No suspended thread lock released • Else lock maintained and assigned to one of the suspended threads
Synchronized Block synchronized(this) { <code> } • <code> is a critical section for object this • Mutual exclusion is guaranteed for this w. r. t. – Other executions of the same block – Other synchronized blocks for the same object <Object mutex. Lock = …> … public void M( ) { <non-critical section>; synchronized (this){<critical section>; } <non-critical section>; }
Thread-Safe Counter static synchronized void increment() { counter++; } Byte code <lock acquisition or suspension> cur counter cur + 1 <lock release or reassignment> • Synchronization is related to this (Counter object) • Mutual exclusion ensured for all synchronized methods – E. g. also dec() method for Counter
Wait Set • In addition to the entry set, each object is associated to another queue: wait set • Special methods – wait(): insertion in the wait set – notify()/ notify. All(): extraction from the wait set – Can be invoked only by the thread owning the object’s lock • Can be used only in a synchronized section
Wait and Notify(All) • wait(): calling thread – Releases the lock – Is suspended in the wait set queue – N. B. : method throws Interrupted. Exception • notify(): one thread is selected from the wait set and moved into the entry set • notify. All(): all threads in the wait set are moved into the entry set Policy: signal and continue!
Example: Bounded Mailbox • void send(Message m) – Synchronized – Cyclic test (mailbox full wait()) – After message insertion notify all • Message receive() – Synchronized – Cyclic test (mailbox empty wait()) – After message extraction notify all • Is this efficient? Producer Thread Consumer Thread
Limitations of the Basic Monitor • One queue for mutual exclusion (entry set) • Only one queue for synchronizing threads on an object (wait set) Conditions and Semaphors (from Java 5)
Java Semaphores • Java (from 5. 0) also explicitly supports semaphores (java. util. concurrent. Semaphore) • Constructor: takes – Permits (no. ): number of permits initially granted – Fairness (yes/no): if true, suspended threads will acquire the resource in the order they asked for it • Basic methods – acquire() wait – release() signal • Other useful methods (see Java. Doc)
Example: Bounded Mailbox • How to realize it without a monitor, but only semaphores? • How many semaphores? • How are they initialized? Producer Thread Consumer Thread
Other Useful Methods • sleep(long ms) – Suspends thread for the specified amount of time • interrupt() – Triggers an event that causes the interruption of thread • interrupted() is. Interrupted() – Check whether the current thread has been interrupted • join() – Waits for the termination of the specified thread • is. Alive() – true if thread has been started and has not yet terminated its execution • yield() – Forces thread to release CPU • Other useful methods: Java. Doc of Thread class – E. g. Thread. get. Current. Thread() returns the currently active thread
On Deprecated Methods • stop() forces thread termination – All resources (e. g. locks) are instantaneously freed – If the thread was doing an “atomic” operation, the object’s state could be left in an inconsistent state – The object can be now accessed by other thread Should not be used • suspend() blocks a thread until resume() is invoked – Resources are not freed (e. g. locks are maintained) – If the thread has acquired a mutually exclusive resource (monitor), the resource is blocked Should not be used • In general, follow the “Java Thread Primitive Deprecation” guide (part of Java SE Documentation)
Thread-safe Datastructures • Common data structures not thread-safe – e. g. Linked. List • Synchronized data structures – Blocking. Queue – Concurrent. Map – Copy. On. Write. Array. List
On Priorities • Threads have two methods for priorities – set. Priority(int v) v∈[MIN_PRIORITY, MAX_PRIORITY] – get. Priority() • Java suggested best practice: – Among runnable threads, choose the ones of higher priority – Round robin over threads of the same priority – Interrupt thread if a thread of higher priority is runnable • Some JVM implementations: delegate threads’ scheduling to O. S. behavior depends on JVM + OS Use with care
Take home • Java threads: – extend Thread – implement Runnable • Synchronization an issue – Java provides techniques • synchronized classes/methods/code snippets • semaphores • Synchronized data structures
- Slides: 54