1 / 76

COMP201 Java Programming Part III: Advanced Features

COMP201 Java Programming Part III: Advanced Features. Topic 12: Multithreading Volume II,Chapter 1. Outline. Introduction : Why and what Basics: creating and running threads Issues Thread states Thread scheduling Synchronization Suspending and stopping threads Threads and Swing.

moiram
Télécharger la présentation

COMP201 Java Programming Part III: Advanced Features

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1

  2. Outline • Introduction: Why and what • Basics: creating and running threads • Issues • Thread states • Thread scheduling • Synchronization • Suspending and stopping threads • Threads and Swing

  3. Introduction • Consider the program Bounce.java • Desired effects • If the Start button is clicked, a ball starts to bounce. • If the button is clicked again, a second ball starts to bounce and so on. • If the Close button is clicked, the windows closes and the program terminates • Classes • Ball • BallPanel extends JPanel • BounceFrame extends JFrame • Bounce

  4. Introduction • Classes • Ball • public Ellipe2D getShape() Gets the shape of the ball at its current position • public void move() • Moves the ball to the next position, reversing direction if it hits one of the edges • class BallPanel extends JPanel • Keeps a list of balls = new ArrayList<Ball>(); • public void add(Ball b) • Add a ball to the Panel. • public void paintComponent(Graphics g) • Draw all balls at their current positions

  5. Introduction • Classes class BounceFrame extends JFrame • Set up GUI and listeners • When the Close button is clicked this method is called, public void actionPerformed(ActionEvent evt) { System.exit(0); } • When the Start Button is clicked, this method is called public void actionPerformed(ActionEvent evt) { addBall(); //Creates and adds a bouncing ball to the panel // and make it bounce 1,000 times. }

  6. Introduction public void addBall() { try { Ball ball = new Ball(); panel.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(panel.getBounds()); panel.paint(panel.getGraphics()); Thread.sleep(DELAY); } } catch (InterruptedException e) {} } Note: sleep is a static method that puts the currently running thread to sleep. It throws InterruptedException when interrupted.

  7. Introduction • However • Cannot start a second ball before the current ball finishes bouncing • Cannot terminate program before the current ball finishes bouncing • Actually, won’t even work if repaint() is used (as it should be) instead of paint.

  8. Introduction • Why? • There is a single thread of control. • Actions are executed one by one. • Cannot execute next action before current action finishes • Implications in general: • Cannot do anything else while waiting data from the net. • Cannot stop downloading even though you know, after seeing part of the download, that you don’t want the download any more • Solution: Multithreading

  9. Introduction • A multithreaded program has multiple threads of control • OS runs one thread a short period of time, then switches to another, and so on • To user, threads appear to run simultaneously. An illusion. • Nonetheless, makes it easier for user to interact with program

  10. Introduction • In our example, we need more than one thread: • One thread to listen for button clicks • One thread to bounce each ball //BounceThread.java

  11. Outline • Introduction: Why and what • Basics: creating and running threads • Issues • Thread states • Thread scheduling • Synchronization • Suspending and stopping threads • Threads and Swing

  12. Creating and Running Threads • How to create and run new threads (from the current thread)? 1. Write a class that implements the interface java.lang.Runnable class MyRunnable implements Runnable { public void run(){ task code }} • Construct an object of your class: Runnable r = new MyRunnable(); 3. Construct a Thread object from the Runnable: Thread t = new Thread(r); 4. Start the thread: t.start(); Don’t call run, it just executes the task in the same thread, no new thread is started.

  13. Creating and Running Threads class BallRunnable implements Runnable { …… public void run() { try { for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } }catch (InterruptedException e){} } private Ball ball; private Component component; …} //BounceThread.java

  14. Invoke the addball() when “Start” button is clicked addButton(buttonPanel, "Start",new ActionListener() { public void actionPerformed(ActionEvent event) { addBall();} }); public void addBall() { Ball b = new Ball(); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.start(); } private BallPanel panel;

  15. Outline • Introduction: Why and what • Basics: creating and running threads • Issues • Thread states • Thread scheduling • Synchronization • Suspending and stopping threads • Threads and Swing

  16. Thread States Four states for threads: new, runnable, blocked, dead sleep blocked done sleeping new suspend resume start wait runnable notify Wait for lock Lock available block on I/O runexits stop dead I/O complete Note: suspend, resume,stop deprecated.

  17. new start runnable Thread States • When a thread has just been created using the newoperator, it is in the newstate. • Once start method is invoked (which calls the run method), the thread becomes runnable. • A runnable thread might not be running. • There can be many runnable threads. But only one of them can be running at any time point. • OS decides which thread to run. More on this later.

  18. Thread States • A runnable thread enters the blocked state when • The thread is currently running and methodThread.sleepis called • suspend method of the thread is called. (deprecated) • The thread calls thewaitmethod. • The thread tries to lock an object locked by another thread. • The thread calls an operation that is blocked on i/o. sleep blocked suspend wait runnable A blocked thread cannot be running Wait for lock block on I/O

  19. Thread States • A blocked reenters runnable state when • It has slept the specified amount of time. • resume method of the thread is called. (deprecated) • Another method calls notifyornotifyAll • Object lock released by another thread • I/O completed. blocked done sleeping resume runnable notify Lock available I/O complete

  20. Thread States • A runnable thread enters the dead state when • Its run method exits. Natural death. • stop method of the thread is called. (deprecated) • An exception is thrown but not caught. runnable runexits stop dead

  21. Thread States • Finding out states of threads • Method isAlive allows you to find out whether a thread is alive or dead. • This method returns true if the thread is runnable or blocked, • false if the thread is still new and not yet runnable or if the thread is dead • No way to find out whether an alive thread is running, runnable, or blocked.

  22. Outline • Introduction: Why and what • Basics: creating and running threads • Issues • Thread states • Thread scheduling • Synchronization • Suspending and stopping threads • Threads and Swing

  23. Thread Scheduling • At any time, there might be many runnable threads. But only one of them is actually running. • The thread scheduler decides which runnable thread to run. • Questions: • When does the thread scheduler kick in and pick a thread to run? • How does the thread scheduler select among the runnable threads? • A not-so-precise answer: • A running Java thread will continue to run until • It calls yield method, or • It ceases to be runnable (dead or blocked), or • Another thread with higher priority moves out of blocked state • Then the thread scheduler kicks in and picks another thread with the highest priority to run

  24. Thread Scheduling • Two different thread implementations • “Native thread” implementation (e.g. Windows): Performs time-slicing. Interrupts the running thread periodically to give other threads a chance to run. • “Green thread” implementation (e.g. Solaris) Does not perform time-slicing. It keeps a running thread active until a higher-priority thread awakes and takes control.

  25. Thread Scheduling • The answer on slide 23 is precise for the green thread implementation. • For the native thread implementation, the precise answer is • A running Java thread will continue to run until • It calls yield method, or • It ceases to be runnable (dead or blocked), or • Another thread with higher priority moves out of blocked state, or • It is pre-emptied by OS (time-slicing). • Then the thread scheduler kicks in and picks another thread with the highest priority to run

  26. Thread Scheduling • Priority of individual threads • Can be increased or decreased using setPriority • Java have 10 priority levels (constants of Thread class) MIN_PRIORITY = 1; NORMAL_PRIORITY = 5; MAX_PRIORITY = 10 • A thread inherits priority from its parent thread, the one that creates it. • Note • Some OS has fewer. E.g. Windows NT has 7. • JVM maps Java priority levels to priority level of the underlying OS.

  27. Thread Scheduling • Example: BounceExpress.java • Two kinds of balls: black and red. • Red ball threads have higher priority and hence get more chance to run. The effect is that red balls appear to be moving faster.

  28. Thread Scheduling • The addBall method public void addBall(int priority, Color color) { for (int i = 0; i< 300; i++){ Ball b = new Ball( color); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.setPriority(priority);// priority set here t.start(); try { Thread.sleep(1); }catch(InterruptedException exception){}; } }

  29. Thread Scheduling • Buttons and listeners addButton(buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent evt) { addBall(Thread.NORM_PRIORITY - 2, Color.black); }}); addButton(buttonPanel, "Express", new ActionListener() { public void actionPerformed(ActionEvent evt) { addBall(Thread.NORM_PRIORITY + 2, Color.red); } });

  30. Thread Scheduling • Question 1: • Consider the case when there are 1 black ball and 1 red ball. • When the red-ball thread goes to sleep, there is only one other thread, the black-ball thread. • Hence the black-ball thread must be chosen. • Implication: • black ball takes one move, red ball takes one move, black ball takes one move, and so on. • The two balls should be of the same speed. • Well, this is not the case. Why? • There is another thread! What is it? What role does it play? • When event dispatch thread pauses, the red-ball thread already wake up from sleep and hence picked by scheduler over back-ball thread.

  31. Thread Scheduling • Question 2: • If we change sleeping to 50 or running the program on a faster cpu, red balls are not faster any more. • Why? • In order for the red-ball thread to be picked more often than the black-ball thread, it must “meet” the scheduler more often. • When event dispatch thread pauses, the red-ball thread is still sleeping, just as the black-ball thread.

  32. sleepvs. yield • In BallRunnable, sleep is called to give other thread a chance to run. • Another way is to call yield. class BallRunnable implements Runnable{ public BallRunnable(Ball aBall, Component aComponent) { ball = aBall; component = aComponent; } public void run() // codes for new thread { for ( int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.yield(); } }}

  33. sleepvs. yield • There is a big difference • Calling sleep put the current running thread into the blocked state • Calling yield does not put the calling thread, t1, into the blocked state • It merely let the scheduler kick in and pick another thread to run. • It might happen that the t1 is select to run again. This happens when t1 has a higher priority than all other runnable threads.

  34. Thread Scheduling • Cooperating vs. Selfish threads: • A cooperating thread gives others a chance to run • Calling sleep: pause for the specified period of time • Calling yield: pause temporarily. Scheduler kicks in. • A selfish thread does none of this. • Effects of selfish threads are system-dependent: • Green thread: A selfish thread can consume all the CPU time. • Native thread: A selfish thread doesn’t post a big problem.

  35. Thread Scheduling public void run() { try {for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); if (ball.getSelfish()) { // busy wait for 5 milliseconds long t = System.currentTimeMillis(); while (System.currentTimeMillis()<t + 5) ; } else Thread.sleep(DELAY); }catch (InterruptedException exception){} } //BounceSelfish.java

  36. Thread Scheduling • Question 3: • The balls some times jump. • Why? • Event dispatch thread doesn’t get the time to run. Paint events accumulate.

  37. Outline • Introduction: Why and what • Basics: creating and running threads • Issues • Thread states • Thread scheduling • Synchronization • Suspending and stopping threads • Threads and Swing

  38. Synchronization • The Synchronization problem: Two different threads modify the same object atthe same time, leading to corrupted object. Such a situation is called race condition. • An analog: • You and your partner are finishing a group project and starting to write the project report. • The report is kept at a centralized location. • You open the report and edit it • Your partner opens the report and edits it • You save the edits. • Your partner saves his edits, • Your edits are lost!

  39. Synchronization • An example: UnsynchBankTest.java • class Bank • A bank with a number of bank accounts. • class TransferRunnable implements Runnable - A runnable that transfers money from an account to other accounts in a bank. • public class UnsynchBankTest • Create 10 accounts and multiple threads to make random transfers

  40. Synchronization • public voidtransfer(int from, int to, int amount) { if (accounts[from] < amount) return ; accounts[from] -= amount; // added by Instructor so that corruption occurs //more easily try { Thread.sleep(3); } catch(InterruptedException e) {} accounts[to] += amount; counter++; //print out total after every 1000 transactions if (counter %1000 == 0){ System.out.print(Thread.currentThread()); System.out.printf(" %10.2f from %d to %d", amount, from, to); System.out.printf(" Total Balance: %10.2f%n", getTotalBalance()); }

  41. Synchronization • class TransferRunnable implements Runnable { publicTransferRunnable, int from, double max) {…} public void run() { try { while (true) { int toAccount = (int)(bank.size() * Math.random()); double amount = maxAmount * Math.random(); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int)Delay * Math.random()); }} catch(InterruptedException e) {} } private Bank bank; private int fromAccount; private double maxAmount; private int DELAY = 1000;

  42. Synchronization • ClassUnsynchBankTest publicstatic void main(String[] args) { Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); int i; for (i = 0; i < NACCOUNTS; i++) { TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE); Thread t = new Thread(r); t.start(); } } public static final int NACCOUNTS = 10; public static final int INITIAL_BALANCE = 10000; Note: Total amount in all accounts = 100,000

  43. Synchronization • Run the program • Very quickly, the amounts in the accounts do not add up to 100,000 • Why? • The transfer method of Bank class is not atomic: consists of many steps • Can be interrupted in the middle

  44. Synchronization • Problem scenario: • Thread 1 takes 50 from account A • Goes to sleep (simulate interruption, self interruption) • Thread 2 completes transfer and call test • Result: • 50 less in total • The total amount can only be less than 100,000 • If we swap the deduction and addition, the total will always be more.

  45. Synchronization • Note that even instructions are not atomic. • Consider the following accounts[to] += amount; • It is processed in three steps as follows: • Load current value of accounts[to] to a register • Add amount • Move the result back to accounts[to].

  46. Synchronization • Execution interruption • accounts[0] is currently 100. • Thread 1 perform accounts[0] += 50; • Thread 2 performs accounts[0] += 50; • The correct result should be: accounts[0] == 200. • What is the result if the following happens? Actual result: accounts[0] == 150 The probability of such interruptions is low (but possible). This is why we faked interruption using sleep.

  47. ReentrantLock • How to avoid the work of the transfer method being interrupted? JDK 5.0 introduces the Reentrantlock class class Bank { … publicvoid transfer( int from, int to,int amount){ bankLock.lock(); try{ if (accounts[from] < amount ) return; accounts[from] -= amount; try {Thread.sleep(1);}catch(InterruptedException e) {} accounts[to] += amount; … } finally {bankLock.unlock();} }…. Private Lock bankLock= newReentrantlock (); //Reentrantlock implements the Lock interface. } // SynchronizedBankTest0.java

  48. ReentrantLock • How does the mechanism work? • This construct guarantees that only one thread at a time can enter the critical section. As soon as one thread locks the lock object, no other thread can get past the lock statement. When other threads call lock they are blocked until the first thread unlocks the lock object. • Suppose one thread calls transfer and gets preempted before it is done. Suppose a second thread also calls transfer . The second thread cannot acquire the lock and is blocked in the call to the lockmethod. It is deactivated and must wait for the first thread to finish executing the transfer method. When the first thread unlockthe lock, then the second thread can proceed. • The lock is called reentrant because a thread can repeatedly acquire a lock that it already owns. The lock keeps a hold count that keeps track of the nested calls to the lockmethod. The thread has to call unlockfor every call to lockin order to relinquish the lock. So code that is protected by a lock can call another method that uses the same lock.

  49. Condition Object • Often, a thread enters a critical section, only to discover that it can’t proceed until a condition is fulfilled. JDK5.0 uses a condition object to manage threads that have acquired a lock but cannot do useful work. • For example, what do we do where there is not enough money in the account? We wait until some other thread has added funds. But this thread has just gained exclusive access to the banklock, so no other thread has a chance to make a deposit. This is where condition object come in. • A lock object can have one or more associated condition objects. You obtain a condition object with the newCondition method. It is customary to give each condition object a name that evokes the condition that it represents. For example: private Condition sufficientFunds; sufficientFunds = bankLock.newCondition ();

  50. Condition Object • If the transfer method finds that sufficient funds are not available, it calls sufficientFunds.await(); • The current thread is now blocked and gives up the lock. This lets in another thread that can (possibly) increase the account balance. • When another thread transfers money, it should call sufficientFunds.signalAll();to unblock all threads that are waiting for the condition. or call sufficientFunds.signal(); to unblock a single thread from the wait set, chosen at random. • When the threads are removed from the wait set, they are again runnable and the scheduler will eventually activate them again. At that time, they will attempt to reenter the object. As soon as the lock is available, one of them will acquire the lock and continue where it left off, returning from the await. At this time the thread should test the condition again. There is no guarantee that the condition is now fulfilled.

More Related