210 likes | 333 Views
CS4273: Distributed System Technologies and Programming I. Lecture 4: Java Threads and Multithread Programming. Memory. Thread1. Thread2. Thread3. Code Segment. PC. PC. PC. Multi-threading. Threads
E N D
CS4273: Distributed System Technologies and Programming I Lecture 4: Java Threads and Multithread Programming
Memory Thread1 Thread2 Thread3 Code Segment PC PC PC Multi-threading Threads • A thread is a thread of control flow of executing a piece program, similar to a process. • Multi-threading is a technique of concurrent programming, which runs multiple threads on one piece of program. • Threads are running in a pseudo-parallel fashion. • Servers and animation programs often use multiple threads.
Head Blocked Tail Dead NewBorn sleep() start() notify() wait() Running Runnable yield() States of a Thread Life Cycle • run queue: priority queue head = Thread.currentThread(); • wait queue: activated by notify() • sleep queue: Head Head Tail Tail
Methods in Thread Class run() method • run() method is the program body of a thread. A thread executes run method when it starts. You need to override this method to let the thread do your work! Methods called by threads: • sleep(ms): make the caller sleep for N milli-seconds. • yield(): make the caller non-selfish thread. The caller doesn’t mind to give out the CPU to other threads (of the same priority). • wait() : the caller blocks itself until being waken up. • notify(): wake up a thread in wait-queue (by moving the thread from wait-queue to run-queue). The caller still holds CPU after the call. • notifyAll(): wake up all threads in wait-queue.
Methods in Thread Class (Cont.) Methods called by control programs (or threads) • start(): start the thread. It places the thread to the tail of run-queue. • setPriority(Thread.MAX_PRIORITY - 2). • isAlive(): check if a thread is still executing run method. • currentThread(): return the current running thread.
Example of a thread program public class mythread extends JApplet implements Runnable { ………. public void start() { if (runner == null) { runner = new Thread(this); runner.start(); } } public void stop() { // N.B. thread.stop method was deprecated! runner = null; } public void run() { Thread thisThread = Thread.currentThread(); // N.B. if “runner’ is null, it won’t do anything while (runner == thisThread) { thisThread.sleep(t); repaint(); ……… }
Thread Creation There are two ways to create threads: • extend the Thread class to define your thread-class and then construct objects out of your thread-class. • use the Runnable interface and implement the run method of the interface.
process Dong Thread Ding Thread OS Example of extending Thread class class BellThread extends Thread{ String Sound; BellThread (String Sound ) { this.Sound = Sound; } public void run(){ while(true){ System.out.println (Sound + " "); try{sleep(20); } catch(Exception e){ return; } } } public static void main(String[] args){ new BellThread(“Ding”).start(); new BellThread(“Dong”).start(); } }
public class threadSwitch extends JApplet { int threadID = 0, star = 0, hash = 0; public void init() { StarThread runner1 = new StarThread(); runner1.start(); HashThread runner2 = new HashThread(); runner2.start(); } public void paint(Graphics g) { super.paint(g); switch(threadID) { case 1: g.drawString("*", star*10, 50); break; case 2: g.drawString("#", hash*10, 100); } } class StarThread extends Thread { public void run() { while (true){ threadID = 1; if (star >= 50 ) star = 0; else star++; repaint(); } }} class HashThread extends Thread { public void run() { while (true){ threadID = 2; if (hash >= 50 ) hash = 0; else hash++; repaint(); } }} Example of Thread Switching
Runnable Interface • In addition to extending Thread class, an application often needs to extend from another class, e.g., Applet. But Java doesn’t allow multiple inheritance. Runnable interface is for this purpose. • Runnable interface has only one method run(). You need to implement the run method. • Thread class constructor creates threads out of Runnable objects. Thread has two constructors: public Thread (Runnable target); the constructed thread object uses target’s run method! public Thread(Runnable target, String name); the save as above, but the new thread object has a name.
class BellRunnable implements Runnable { BellRunnable(String sound){ this.sound = sound; } public void run() { for(int i=1;i<=100;i++){ System.out.println(sound + " "); try{Thread.sleep(20); } catch (Exception e){ return;} } } public static void main(String[] args) { BellRunnable Ding = new BellRunnable(“Ding”); Thread DingThread = new Thread(Ding); DingThread.start(); BellRunnable Dong = new BellRunnable(“Dong”); new Thread(Dong).start(); } Example of Threads using Runnable Interface
Applets Implement Runnable Interface of Threads • Runnable interface has only one method run, you can implement the Runnable interface in any class by implementing the run method. • It is most often used together with Applet class. class ThreadApplet extends JApplet implements Runnable { private Thread runner; …… public void start() { if (runner == null) { runner = new Thread (this); // run of this class runner.start (); } } public void run() { // thread-code comes here …… } }
Thread Control: stop a thread Methods “stop”, “suspend” and “resume” for thread control were deprecated due to un-safety. Stop a thread: add the following codes: • set the thread pointer runner to “null” when you want to stop it: …… runner1 = null; …… • add the following code at the beginning of run() of the thread: public void run() Thread thisThread = Thread.currentThread(); while (runner1 == thisThread) { code-of-runner; } } • N.B. The following two simple methods don’t work: • Only set “runner1 = null” without 2nd part, it cannot stop the execution of runner. • Simplify the 2nd part as below, it won’t work either: • public void run() { • while (runner1!= null) { code-of-runner;} • }
Suspend and Resume a thread • suspend a thread: use a boolean var to indicate suspending the thread and the thread blocks itself by “wait()” in run method. • resume a thread: use “notify()” to resume the thread. • use a boolean var. • boolean runnerSuspended; • public synchronized void actionPerformed (ActionEvent e) { • switch (id) { • case SUSPEND: • runnerSuspended = true; break; • case RESUME: • runnerSuspended = false; • notifyAll(); • } • use the following code in run(). • public void run() { • while (runnerSuspended) • wait(); • code-of-runner;} • }
public class threadControl extends JApplet implements Runnable, ActionListener { public void run() { thisThread = Thread.currentThread(); while (faster == thisThread) { try { synchronized(this) { while (fastSuspended) wait(); Thread.sleep(20); } catch (InterruptedException e) {} fast++; repaint(); } while (slower == thisThread) { try { synchronized(this) { while (slowSuspended) wait(); Thread.sleep(40); } catch (InterruptedException e) {} slow++; repaint(); } public synchronizedvoid actionPerformed (Event e) { if (e.getSource() == fsus) fastSuspended = true; else if (e.getSource() == fres) { fastSuspended = false; notifyAll(); } else if (e.getSource() == fstp) faster = null; ……………… Example of using wait/notify for suspend/resume
Thread1 …. Thread2 Thread n Bank Concurrent accesses may cause inconsistency class unsynchBankTest { public static void main (String [] args) { Bank b = new Bank (); for (int i = 1; i <= Ntrans; i++) new Trans (b).start(); }//concurrent threads } class Bank { …… public void transfer ( int from, int to, int amnt) { …… accounts[from] -= amnt; accounts[to] += amnt; } …… } class Transaction extends Thread { public Trans (Bank b) { bank = b; } public void run () { while (true) { int from = (Bank.Nacct - 1)* Math.random(); // random numbers for to and amnt; bank.transfer ( from, to, amnt); } } load r0, acct[to] add r0, amnt store r0, acct[to]
synchronized Method for access shared objects • When multiple threads access shared object concurrently, a monitor is required to guarantee each data access operation is atomic (non-interruptable). • Java provides a modifier “synchronized” for methods which requires mutual exclusion. When a method is declared as synchronized, the monitor ensures that at any time no more than one thread is active in the monitor (i.e. accesses the object). • When there is a possibility for two threads to modify a data object in a method, declare the method (or the code-segment) as synchronized, which makes you free of mutual exclusion problem.
Example of synchronized Methods class unsynchBankTest { public static void main (String [] args) { Bank b = new Bank (); for (int i = 1; i <= Ntrans; i++) new Trans (b).start(); } } class Bank { public synchronized void transfer ( int from, to, amnt) { …… accounts[from] -= amnt; // it’s safe now! accounts[to] += amnt; } …… } class Trans extends Thread { public void run () { while (true) { int from = (Bank.Nacct - 1)* Math.random(); // random numbers for to and amnt; bank.transfer ( from, to, amnt); } }}
Put Get Boy Monkey Box Thread Coordination • Threads often need to coordinate with each other to get a job done, such as the Producer-Consumer problem. • The coordination among threads can be achieved by wait and notify methods. When a thread cannot proceed further and waits for the change of a state, it calls wait() to block itself; when a thread changes a state which may unblock others, it calls notify(). • In Java, there is only one wait-queue, a FIFO queue, for each application. If more than one thread waiting, notify wakes up the head of wait-queue. Threads cannot wait() on specific events. Therefore, notifyAll() is often used to make sure the right thread is waken up.
class Box { boolean banana = false; //no banana synchronized void get() { while (!banana) // ? not use if wait(); // wait for banana System.out.println("take banana away”); banana = false; // no more banana notifyAll(); //notify box is empty } synchronized void put() { while (banana) wait(); // wait for box empty System.out.println(“put banana in”); banana = true; notifyAll(); // notify banana is ready } Put Get Boy Monkey Box Example of Threads Coordination
class Monkey extends Thread { Monkey(Box box) { this.box = box; } public void run() { while(true){ box.get(); } } class Boy extends Thread { Boy (Box box) { this.box = box; } public void run() { while(true){ box.put(); } } class MonkeyEatBanana { public static void main(String args[]) { Box box = new Box(); new Monkey (box).start(); new Boy (box).start(); } } Summary of producer-consumer problem: define a class for the share objects, with methods (synchronized if necessary) for accessing the objects. define classes for producer threads and consumer threads, using the methods on the shared objects to access them. define a main routine which instantiates shared objects and threads, and starts the threads. Example of Threads Coordination (Cont.)