Java threads - web.fhnw.ch · – the existing class should provide code for the thread ! no...
Transcript of Java threads - web.fhnw.ch · – the existing class should provide code for the thread ! no...
Java threads
Carlo U. Nicola, IMVS
With extracts from slides/publications of :
Brian Goetz and
Dominik Gruntz, IMVS
Topics
1. Thread Definition
2. Thread Synchronization
3. Condition Variables
4. Volatile
MAS HS12 2
What are threads?
MAS HS12 3
A process is an executing program that: – is memory allocated by OS
– usually does not share memory with other processes
A thread is a single sequential flow of control that: – runs in the address space of a process
– has its own program counter
– has its own stack frame
– shares code and data with other threads.
UML diagram:
java.lang.Thread
java.lang.Thread = Infrastructure (PC, Stack)
java.lang.Runnable = Code
MAS HS12 4
public class R implements Runnable {
private int nr;
public R(int nr){this.nr = nr;}
public void run() {
for(int i=0; i<10; i++) {
System.out.println(”Hello” + nr + ” ” + i);
}
}
}
...
java.lang.Thread Runnable r = new R(1);
Thread t = new Thread(r);
Runnable
run()
Thread R
run()
- run() has no parameters
- run() returns no result
- run() does not declare
any checked exception
Starting the thread
MAS HS12 5
Constructor initializes the thread object: Thread t = new Thread(r); t.start();
– calls the thread object’s run method (! turn power on)
– when run( ) returns, the thread terminates
public class Test { static void main(String[] args){ Thread t1 = new Thread(new R(1)); Thread t2 = new Thread(new R(2)); t1.start(); t2.start(); } }
Hello1 0
Hello2 0
Hello1 1
Hello2 1
Hello2 2
Hello2 3
Hello2 4
Hello2 5
Hello2 6
Hello2 7
Hello2 8
Hello2 9
Hello1 2
Hello1 3
Hello1 4
Hello1 5
Hello1 6
Hello1 7
Hello1 8
Hello1 9
Process
Exit..
Scheduling
Scheduling: – Per processor, only one thread is running at any given time – Scheduling = Allocation of CPU time to threads
Threading models: – Cooperative threading ! pseudo parallelism
# threads decide, when they should give up the processor to other threads. Example: yield(); sleep(1000);
– Pre-emptive threading ! quasi parallelism # OS interrupts threads at any time (time sliced) # no thread can unfairly hog the processor
JVM does not mandate a threading model – Java programmers must write programs for both models!
MAS HS12 6
Alternative definition of a Java thread
MAS HS12 7
Since the class Thread implements the interface Runnable, the method
run() can be implemented in subclass of Thread. Example:
public class T extends Thread { private int nr; public T(int nr) {this.nr = nr;} public void run() { for (int i=0; i<10; i++) { System.out.println(”Hello” +nr + ” ” + i); } } }
Runnable
run()
T
Thread
run()
run()
Extending Thread vs implementing Runnable
Implement Runnable in a separate class: – the existing class should provide code for the thread ! no multiple
subclassing problem
– you must implement run()
Implementing Runnable in extension of Thread – easy access to thread methods
# static methods: sleep(100); Thread.sleep(100);
# instance methods: getName(); Thread.currentThread().getName();
MAS HS12 8
Thread class
static Thread currentThread(): – returns a reference to the currently executing thread object.
static void sleep(long millis): – Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds.
static void yield(): – Causes the currently executing thread object to temporarily pause and
allow other threads to execute.
void run() void start() void join():
– Waits for this thread to die.
void join(long millis): – Waits at most millis milliseconds for this thread to die.
MAS HS12 9
Thread class join()
MAS HS12 10
public class Test1 { static void main(String[] args) { Thread t1 = new Thread(new R(1)); Thread t2 = new Thread(new R(2)); t1.start(); t2.start(); System.out.println("done"); } }
What is the program’s output?
Thread class join()
MAS HS12 11
public class Test1 { static void main(String[] args){ Thread t1 = new Thread(new R(1)); Thread t2 = new Thread(new R(2)); t1.start(); t2.start(); try { t1.join(); // waits until t1 has terminated t2.join(); // waits until t2 has terminated } catch(InterruptedException e){ } System.out.println("done"); } }
What is the program’s output?
Further methods of the Thread class
MAS HS12 12
String getName(): – Returns this thread's name.
void setName(String name) – Changes the name of this thread to be equal to the argument
name. int getPriority()
– Returns this thread's priority. void setPriority(int newPriority)
– Changes the priority of this thread. boolean isDaemon() – Tests if this thread is a daemon thread. void setDaemon(boolean on) – Marks this thread as either a daemon thread or a user thread.
boolean isAlive()
– Tests if this thread is alive.
Thread class: Deamons
MAS HS12 13
Daemon Threads
– daemon threads run in the background
– if only deamon threads are active, the process stops.
public class Test1 { static void main(String[] args){ Thread t1 = new Thread(new R(1)); Thread t2 = new Thread(new R(2)); t2.setDaemon(true); t1.start(); t2.start(); } }
What is the program’s output?
Thread states
MAS HS12 14
Example: unresponsive UI
MAS HS12 15
Button start = new Button("Start"); start.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e){ go();} } ); public void go() { while(true){ // thread sleeps for 100ms try {Thread.sleep(100);} catch (InterruptedException e){} t.setText("" + count++); } }
Solution: unresponsive UI
MAS HS12 16
Button start = new Button("Start"); start.addActionListener( new ActionListener(){ public void actionPerformed(ActionEvent e){ new Thread(UI.this).start();} } ); public void run(){ while(true){ // thread sleeps for 100ms try {Thread.sleep(100);} catch (InterruptedException e){} t.setText("" + count++); } }
Quiz
MAS HS12 17
class C { int x = 0, y = 0; void a() { x = 3; y = 4; } int b() { int z = y; z = z + x; return z; } }
One thread calls method a() on an instance of C One thread calls method b() on the same instance.
Question: what results can be returned by b() ?
Demo: Adder
MAS HS12 18
class TTest { static double x = 0.0; public static void add(double val){x = x + val;} public static void main(String[] args){ class TestThread extends Thread { private double val; TestThread(double val){this.val = val;} public void run(){ for(int i=0; i<1000; i++){ add(+val); add(-val); } } }
Demo: Adder cont.
MAS HS12 19
TestThread t1 = new TestThread(120); TestThread t2 = new TestThread(60); TestThread t3 = new TestThread(20); TestThread t4 = new TestThread(55.5); t1.start(); t3.start(); t2.start(); t4.start(); try { t1.join(); t2.join(); t3.join(); t4.join(); } catch(InterruptedException e){ } System.out.println(x); } }
MAS HS12 20
An important definition (Brian Goetz):
A class is thread safe if it behaves always in the same manner (i.e. correctly)
when accessed from multiple threads, regardless of the scheduling or
interleaving of the execution of these threads by the runtime environment
and with no additional synchronization on the part of the calling code.
Remember: Stateless objects (immutable classes) do not have fields and
they do not reference fields from other classes therefore they
are always thread safe.
Threads and shared resources
MAS HS12 21
class Counter { private final int count; public Counter() { count = 0; } public void increment() { count++; } public void decrement() { count--; } public int getValue() { return count; } } class IncThread extends Thread { private final Counter c; public IncThread(Counter p_c) { c = p_c; } public void run() { while (true) { c.increment(); System.err.println ("Running inc thread: " + currentThread() + " / Value: " + c.getValue()); } } }
Example: Yarn with increment …
MAS HS12 22
class DecThread extends Thread { private final Counter c; public DecThread(Counter p_c) { c = p_c; } public void run() { while (true) { c.decrement(); System.err.println("Running dec thread: " + currentThread() + " / Value: " + c.getValue()); } } } public class Yarn { public static void main(String args[]) { Counter c = new Counter(); IncThread ithread = new IncThread(c); DecThread dthread = new DecThread(c); ithread.start(); dthread.start(); }}
Example: Yarn with decrement …
MAS HS12 23
Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running inc thread: Thread[Thread-0,5,main] / Value: 2 Running inc thread: Thread[Thread-0,5,main] / Value: 3 Running inc thread: Thread[Thread-0,5,main] / Value: 4 … Running inc thread: Thread[Thread-0,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running dec thread: Thread[Thread-1,5,main] / Value: 60 … Running dec thread: Thread[Thread-1,5,main] / Value: 1 Running dec thread: Thread[Thread-1,5,main] / Value: 0 Running dec thread: Thread[Thread-1,5,main] / Value: -1 Running inc thread: Thread[Thread-0,5,main] / Value: -1 Running inc thread: Thread[Thread-0,5,main] / Value: 0 Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running inc thread: Thread[Thread-0,5,main] / Value: 2 …
Why such a mess? A shared resource
(in our case the Counter c) is accessed
without any order by several threads!
Our small program is not thread safe.
What can we do?
(1) Do not share state variables across threads.
(2) Make state variable immutable.
(3) Use synchronization whenever you access state variables.
Output of Yarn
Any race conditions? Yes!
MAS HS12 24
class IncThread extends Thread { private final Counter c; public IncThread (Counter p_c) { c = p_c; } public void run() { while (true) { c.increment(); System.err.println ("Running inc thread: " + currentThread() + " / Value: " + c.getValue()); } } }
We have always thread unsafe applications when we use compound
operations like:
(1) Read-Modify-Write (RMW)
(2) Check-Then-Act (CTA)
that are not atomic! Atomic means that RMW and CTA are executed from
start to finish by only one thread at a time.
MAS HS12 25
public void run () { while (true) { synchronized (c) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + " / Value: " + c.getValue ()); } } }
Synchronized blocks:
– Every object contains a single lock
– A lock is taken when synchronized section is entered
– If the lock is not available, thread enters a waiting queue
– If the lock is returned any (longest waiting?) thread is resumed
How to synchronize?
synchronized
MAS HS12 26
On instance methods:
– often a method is synchronized on “this”:
public void push(int x){synchronized(this){……}} – short form:
public synchronized void push(int x){……} On class methods (static)
– A lock is also associated with each class, this lock is different from
the locks of the instances:
public static synchronized void foo(){……} similar to: class C { public static void foo(){synchronized(C.class){…}} }
Monitors
MAS HS12 27
Data protection:
– A synchronized lock does not protect data but it only synchronizes
threads
– Data can still be manipulated by direct access # declare data as private
– Data can still be accessed by unsynchronized threads # synchronize all methods which can access critical data
sleep:
– sleep() does not release ownership of any lock
Java does not provide monitors, but monitors can be implemented
with Java
Example: Copy machine
MAS HS12 28
class CopyMachine { public synchronized void makeCopies( Document d, int nCopies){ // only one thread at a time Original org = scanOriginal(d); for(int i=0; i<n; i++) { Paper p = getPaper(); copy(org, p); } } public void loadPaper (Paper[] p) { // multiple threads can access this putPaper(p) } }
Problem: How can we intelligently synchronize the access to the paper drawer?
Fine-grained access
MAS HS12 29
class CopyMachine { private Object paperLock = new Object(); public synchronized void makeCopies( Document d, int nCopies){ // only one thread at a time Original org = scanOriginal(d); for(int i=0; i<n; i++) { Paper p = getPaper(); copy(org, p); } } public void loadPaper (Paper[] p) { synchronized(paperLock){ putPaper(p) } } }
One lock at the object level (this) may be too coarse:
– use dummy objects as simple locks