Java Threads 2x2
Java Threads 2x2
Welcome!
Class mechanics:
Class participation (35%)
Homework and programming projects Paper presentation during the semester Discussion of papers during class
Design
Some tasks can be divided up naturally
How do we program these systems? What do the programs mean? How can be reason about such programs?
The Plan
Get our feet wet with threading in Java
Project due Wed, Jan 31
Next time go over advanced threading idioms in Java Then back to the basics
Memory consistency models Programming models and language design Transactions Analysis
CMSC 838F: Programming Language Techniques for Concucurrent and Distributed Systems
Java Threads
Computation Abstractions
Processes (e.g., JVMs) t4 t2 t2 p1 t3 p2 CPU 1 t1 t5 p3 p4 CPU 2 Threads
t1
t1
foo() { x }
foo() { x }
A computer
7
Implementation View
esp esp eip eip esp eip
Implementation view: its a program counter and a stack. The heap and static area are shared among all threads All programs have at least one thread (main)
Tradeoffs
Threads can increase performance
Parallelism on multiprocessors Concurrency of computation and I/O
Programming Threads
Threads are available in many languages
C, C++, Objective Caml, Java, SmallTalk
In many languages (e.g., C and C++), threads are a platform specific add-on
Not part of the language specification
Java Threads
Every application has at least one thread
The main thread, started by the JVM to run the applications main() method
Thread Creation
execution (time) main thread thread starts
thread join
13
14
15
16
18
20
22
Concurrency
A concurrent program is one that has multiple threads that may be active at the same time
Might run on one CPU
The CPU alternates between running different threads The scheduler takes care of the details Switching between threads might happen at any time
23
p2 threads:
p1 threads:
25
p2 threads:
p1 threads:
26
28
cnt = 0
Start: both threads ready to run. Each will increment the global cnt.
29
30
cnt = 1
y=0
y=1
T1 finishes. T2 executes, grabbing the global counter value into its own y.
31
32
y=0
y=1
T2 executes, storing its incremented cnt value into the global counter.
33
34
cnt = 0
Start: both threads ready to run. Each will increment the global count.
35
36
cnt = 1
y=0
y=0
T1 is preempted. T2 executes, grabbing the global counter value into its own y.
y=0
37
38
What Happened?
Different schedules led to different outcomes
Shared state cnt = 1 This is a data race or race condition
y=0
y=0
T2 completes. T1 executes again, storing the incremented original counter value (1) rather than what the incremented updated value would have been (2)!
Question
If instead of
int y = cnt; cnt = y+1;
Question
If you run a program with a race condition, will you always get an unexpected result?
No! It depends on the scheduler, i.e., which JVM youre running, and on the other threads/processes/etc, that are running on the same CPU
We had written
cnt++;
41
42
Synchronization
Refers to mechanisms allowing a programmer to control the execution order of some operations across different threads in a concurrent program. Different languages have adopted different mechanisms to allow the programmer to synchronize threads. Java has several mechanisms; we'll look at locks first.
43
44
Applying Synchronization
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
Shared state
cnt = 0
Applying Synchronization
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
Applying Synchronization
cnt = 0
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
cnt = 0
T1 is preempted. T2 attempts to acquire the lock but fails because its held by T1, so it blocks
48
47
Applying Synchronization
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
Applying Synchronization
cnt = 1
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
cnt = 1
49
50
Applying Synchronization
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
Applying Synchronization
cnt = 1
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
cnt = 1
51
52
Applying Synchronization
int cnt = 0; t1.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); } t2.run() { lock.lock(); int y = cnt; cnt = y + 1; lock.unlock(); }
y=1
Threads may be interrupted after the while but before the assignment x = 1
Both may think they hold the lock!
Deadlock
Deadlock occurs when no thread can run because all threads are waiting for a lock
No thread running, so no thread can ever release a lock to enable another thread to run
Lock l = new ReentrantLock(); Lock m = new ReentrantLock(); Thread 1 l.lock(); m.lock(); ... m.unlock(); l.unlock(); Thread 2 m.lock(); l.lock(); ... l.unlock(); m.unlock();
57
Deadlock (contd)
Some schedules work fine
Thread 1 runs to completion, then thread 2
Deadlock!
Thread 1 is trying to acquire m Thread 2 is trying to acquire l And neither can, because the other thread has it
58
Wait Graphs
T1
T2
T2
T1 holds lock on l T2 holds lock on m T1 is trying to acquire a lock on m T2 is trying to acquire a lock on l
59 60
Synchronized
This pattern is really common
Acquire lock, do something, release lock under any circumstances after were done
Even if exception was raised etc.
Example
static Object o = new Object(); void f() throws Exception { synchronized (o) { FileInputStream f = new FileInputStream("file.txt"); // Do something with f f.close(); } }
Obtains the lock associated with obj Executes body Release lock when scope is exited
Even in cases of exception or method return
63
Discussion
object o os lock
Data race?
No, threads acquire locks on the same object before they access shared data
Synchronized Methods
Marking method as synchronized same as synchronizing on this in body of the method
The following two programs are the same
class C { int cnt; void inc() { synchronized (this) { cnt++; } } }
69
Data race?
No, both acquire same lock
70
Thread Scheduling
When multiple threads share a CPU...
When should the current thread stop running? What thread should run next?
Threads are de-scheduled whenever they block (e.g., on a lock or on I/O) or go to sleep
71 72
Thread Lifecycle
While a thread executes, it goes through a number of different phases
New: created but not yet started Runnable: is running, or can run on a free CPU Blocked: waiting for I/O or on a lock Sleeping: paused for a user-specified interval Terminated: completed
Daemon Threads
void setDaemon(boolean on)
Marks thread as a daemon thread Must be set before thread started
Key Ideas
Multiple threads can run simultaneously
Either truly in parallel on a multiprocessor Or can be scheduled on a single processor
A running thread can be pre-empted at any time
By default, thread acquires status of thread that spawned it Program execution terminates when no threads running except daemons
Producer/Consumer Design
Suppose we are communicating with a shared variable
E.g., some kind of a buffer holding messages
One thread produces input to the buffer One thread consumes data from the buffer How do we implement this?
Use condition variables
Condition ...
Adds this thread to wait set for lock Blocks the thread
wait set
80
Producer/Consumer Example
Lock lock = new ReentrantLock(); Condition ready = lock.newCondition(); boolean valueReady = false; Object value; void produce(Object o) { lock.lock(); while (valueReady) ready.await(); value = o; valueReady = true; ready.signalAll(); lock.unlock(); } Object consume() { lock.lock(); while (!valueReady) ready.await(); Object o = value; valueReady = false; ready.signalAll(); lock.unlock(); }
81
82
o.notifyAll()
Must hold lock associated with o Resumes all threads on locks wait set Those threads must reacquire lock before continuing
(This is part of the function; you dont need to do it explicitly)
89
90
InterruptedException
Exception thrown if interrupted on certain ops
wait, await, sleep, join, and lockInterruptibly Also thrown if call one of these with interrupt flag set
91
92