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? 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: MAS HS12 3
java.lang.thread java.lang.thread = Infrastructure (PC, Stack) java.lang.runnable = Code Runnable run() 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); Thread R run() - run() has no parameters - run() returns no result - run() does not declare any checked exception MAS HS12 4
Starting the thread 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.. MAS HS12 5
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 Since the class Thread implements the interface Runnable, the method run() can be implemented in subclass of Thread. Runnable Example: run() 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); Thread run() T run() MAS HS12 7
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() 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? MAS HS12 10
Thread class join() 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? MAS HS12 11
Further methods of the Thread class 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. MAS HS12 12
Thread class: Deamons 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? MAS HS12 13
Thread states MAS HS12 14
Example: unresponsive UI 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++); MAS HS12 15
Solution: unresponsive UI 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++); MAS HS12 16
Quiz 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()? MAS HS12 17
Demo: Adder 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); MAS HS12 18
Demo: Adder cont. 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 19
Threads and shared resources 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. MAS HS12 20
Example: Yarn with increment 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()); MAS HS12 21
Example: Yarn with decrement 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(); MAS HS12 22
Output of Yarn 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. MAS HS12 23
Any race conditions? Yes! 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 24
How to synchronize? 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 public void run () { while (true) { synchronized (c) { c.increment (); System.err.println ("Running inc thread: " + currentthread () + " / Value: " + c.getvalue ()); MAS HS12 25
synchronized 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){ MAS HS12 26
Monitors 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 MAS HS12 27
Example: Copy machine 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? MAS HS12 28
Fine-grained access One lock at the object level (this) may be too coarse: use dummy objects as simple locks 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) MAS HS12 29