Download presentation
Presentation is loading. Please wait.
Published byBelen Haseltine Modified over 9 years ago
1
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Multithreading Example from Liang textbook follows. This example sets up several threads that produce various output and runs them simultaneously. Before we take any steps to control how the output from the different threads is synchronized, the order of the output depends on aspects of the operating system and hardware that we can't predict. Run the original code several times, and you will probably see different output. 1
2
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. public class TaskThreadDemo { public static void main(String[] args) { // Create tasks Runnable printA = new PrintChar('a', 100); Runnable printB = new PrintChar('b', 100); Runnable print100 = new PrintNum(100); // Create threads Thread thread1 = new Thread(printA); Thread thread2 = new Thread(printB); Thread thread3 = new Thread(print100); // Start threads thread1.start(); thread2.start(); thread3.start(); } // The task for printing a specified character in specified times class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat /** Construct a task with specified character and number of * times to print the character */ public PrintChar(char c, int t) { charToPrint = c; times = t; } @Override /** Override the run() method to tell the system * what the task to perform */ public void run() { for (int i = 0; i < times; i++) { System.out.print(charToPrint); } // The task class for printing number from 1 to n for a given n class PrintNum implements Runnable { private int lastNum; /** Construct a task for printing 1, 2,... i */ public PrintNum(int n) { lastNum = n; } @Override /** Tell the thread how to run */ public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); } 2
3
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Context Switch When the CPUs switch between threads, they also have to access the memory used by the new thread and change out the contents of the processor caches. This is called context switching. Since context switching is expensive, the OS has extensive rules for scheduling threads. The actual results depend, among many other things, on what else is occurring on the computer. It is not usually practical to predict how processors will be scheduled. Add a Thread.sleep(1); to the run() methods in the demo and the threads will come closer to taking turns, as the delay makes it more likely that the scheduler has has given the CPU to another thread. 3
4
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. The Static yield() Method You can use the yield() method to temporarily release time for other threads. For example, suppose you modify the code in Lines 56-60 in TaskThreadDemo.java as follows: public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); Thread.yield(); } Every time a number is printed, the print100 thread is yielded. No more than one number is printed at a time while other threads are running. 4
5
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. The join() Method You can use the join() method to force one thread to wait for another thread to finish. For example, suppose you modify the run() of PrintNum as follows: public void run() { Runnable printA = new PrintChar('a', 100); Thread thread2 = new Thread(printA); thread2.start(); for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); if (i >= 2) try { thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } 5 The numbers after 2 are printed after thread printA is finished.
6
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Multiple Cores and Multithreading Assignment of your threads to threads in the kernel, which in turn are assigned to particular processors, is generally unpredictable. This differs from one OS to another, and there are many other threads also running at any time. You will learn more about this in CS440. Try the following example with one thread, two threads, and three threads, etc, and check your CPU usage. You will probably find that, while total usage is high, you can’t see any obvious patterns related to the number of threads in use. 6
7
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Multiple Cores and Multithreading package week8; public class CPUBurner implements Runnable { long a = 0; @Override public void run() { while (true) { a++; } 7
8
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Multiple Cores and Multithreading package week8; public class CPUBurnerDemo { public static void main(String[] args){ Runnable b1 = new CPUBurner(); Runnable b2 = new CPUBurner(); Runnable b3 = new CPUBurner(); Thread t1 = new Thread(b1); Thread t2 = new Thread(b2); Thread t3 = new Thread(b3); t1.start(); t2.start(); t3.start(); } **Use the red stop button in Eclipse to terminate this after you get bored!!!** If you forget to close an app in Eclipse, you can get a list of open apps by clicking on the monitor screen icon in the output panel, choosing the zombie app, and clicking on the red button. 8
9
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Thread Life Cycle: States Threads may be in any of the following states: New (not started) Ready (scheduled by OS, not yet running) Running Waiting (say, for input) Timed Waiting (Thread.sleep) Blocked (by CPU scheduler, for cases where another thread must execute first) Terminated 9
10
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. isAlive(), interrupt(), and isInterrupted() The isAlive() method is used to find out the state of a thread. It returns true if a thread is in the Ready, Blocked, or Running state; it returns false if a thread is new and has not started or if it is finished. The interrupt() method interrupts a thread in the following way: If a thread is currently in the Ready or Running state, its interrupted flag is set; if a thread is currently blocked, it is awakened and enters the Ready state, and an java.io.InterruptedException is thrown. The isInterrupted() method tests whether the thread is interrupted. 10
11
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. The deprecated stop(), suspend(), and resume() Methods NOTE: The Thread class also contains the stop(), suspend(), and resume() methods. As of Java 2, these methods are deprecated (or outdated) because they are known to be inherently unsafe. You should assign null to a Thread variable to indicate that it is stopped rather than use the stop() method. 11
12
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Life Cycle Demo package week8; import javax.swing.JOptionPane; public class LifeCycleThread implements Runnable { int a = 0; @Override public void run() { int quit; do { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } quit = JOptionPane.showConfirmDialog(null, "Quit?"); } while(quit != 0); } 12
13
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Life Cycle Demo package week8; public class LimitedCPUBurner implements Runnable { long a = 0; @Override public void run() { while(true){ a++; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } 13
14
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. package week8; import java.lang.Thread.State; public class LifeCycleDemo { public static void main(String[] args){ Runnable b1 = new CPUBurner(); Runnable l = new LifeCycleThread(); Runnable b2 = new LimitedCPUBurner(); Thread t1 = new Thread(b1); Thread t2 = new Thread(l); Thread t3 = new Thread(b2); System.out.println("Thread 1 is " + t1.getState()); t1.start(); //t2.start(); System.out.println("Thread 1 is " + t1.getState()); System.out.println("Thread 1 is " + (t1.isAlive()?"alive":"dead")); System.out.println("Thread 1 is " + (t1.isInterrupted()?"":"not ") +"interrupted"); System.out.println("Interrupting t1"); t1.interrupt(); System.out.println("Thread 1 is " + t1.getState()); System.out.println("Thread 1 is " + (t1.isInterrupted()?"":"not ") +"interrupted"); t2.start(); t3.start(); System.out.println("Thread 3 is " + t3.getState()); do { try { Thread.sleep(1000); System.out.println("Thread 2 is " + t2.getState()); System.out.println("Thread 3 is " + t3.getState()); } catch (InterruptedException e) { e.printStackTrace(); } } while(t2.getState() != State.TERMINATED); t2 = null; System.exit(0); } 14
15
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Thread Priority Each thread is assigned a default priority of Thread.NORM_PRIORITY. You can reset the priority using setPriority(int priority). Some constants for priorities include Thread.MIN_PRIORITY Thread.MAX_PRIORITY Thread.NORM_PRIORITY The results of setting priorities are still not fully predictable; your OS has complex ways of deciding when threads get the CPU and output 15
16
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. package week8; public class ThreadPriorityDemo { public static void main(String[] args) { // Create tasks Runnable printA = new MyPrintChar('a', 100); Runnable printB = new MyPrintChar('b', 100); Runnable print100 = new MyPrintNum(100); // Create threads Thread thread1 = new Thread(printA); Thread thread2 = new Thread(printB); Thread thread3 = new Thread(print100); thread1.setPriority(Thread.MIN_PRIORITY); thread3.setPriority(Thread.MAX_PRIORITY); // Start threads thread1.start(); thread2.start(); thread3.start(); } // The task for printing a specified character in specified times class MyPrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat /** Construct a task with specified character and number of * times to print the character */ public MyPrintChar(char c, int t) { charToPrint = c; times = t; } @Override /** Override the run() method to tell the system * what the task to perform */ public void run() { for (int i = 0; i < times; i++) { System.out.print(charToPrint); } // The task class for printing number from 1 to n for a given n class MyPrintNum implements Runnable { private int lastNum; /** Construct a task for printing 1, 2,... i */ public MyPrintNum(int n) { lastNum = n; } @Override /** Tell the thread how to run */ public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); } 16
17
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. GUI Event Dispatcher Thread GUI event handling and painting code executes in a single thread, called the event dispatcher thread. This ensures that each event handler finishes executing before the next one executes and the painting isn’t interrupted by events. 17
18
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Thread Pools 18 Starting a new thread for each task could limit throughput and cause poor performance as the OS juggles a huge number of threads. A thread pool provides a limited number of threads and allocates them to tasks, which are usually held in a queue. The JDK uses the Executor interface for executing tasks in a thread pool and the ExecutorService interface for managing and controlling tasks. ExecutorService is a subinterface of Executor.
19
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Creating Executors 19 To create an Executor object, use the static methods in the Executors class in the java.util.concurrent package.
20
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. 20 package week8; import java.util.concurrent.*; public class ExecutorDemo { public static void main(String[] args) { // Create a fixed thread pool with maximum three threads ExecutorService executor = Executors.newFixedThreadPool(3); // Submit runnable tasks to the executor executor.execute(new PrintChar('a', 100)); executor.execute(new PrintChar('b', 100)); executor.execute(new PrintChar('c', 100)); executor.execute(new PrintChar('d', 100)); executor.execute(new PrintNum(100)); // Shutdown the executor executor.shutdown(); } // The thread class for printing a specified character // in specified times private static class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat /** Construct a thread with specified character and number of times to print the character */ public PrintChar(char c, int t) { charToPrint = c; times = t; }
21
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. 21 /** Override the run() method to tell the system what the thread will do */ public void run() { for (int i = 0; i < times; i++) System.out.print(charToPrint); } // The thread class for printing number from 1 to n for a given n private static class PrintNum implements Runnable { private int lastNum; /** Construct a thread for print 1, 2,... i */ public PrintNum(int n) { lastNum = n; } /** Tell the thread how to run */ public void run() { for (int i = 1; i <= lastNum; i++) System.out.print(" " + i); }
22
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Thread Synchronization 22 A shared resource may be corrupted if it is accessed simultaneously by multiple threads. For example, two unsynchronized threads accessing the same bank account may cause conflict.
23
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. package week8; import java.util.concurrent.*; public class AccountWithoutSync { private static Account account = new Account(); public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool(); // Create and launch 100 threads for (int i = 0; i < 100; i++) { executor.execute(new AddAPennyThread()); } executor.shutdown(); // Wait until all tasks are finished while (!executor.isTerminated()) { } System.out.println("What is balance ? " + account.getBalance()); } // A thread for adding a penny to the account private static class AddAPennyThread implements Runnable { public void run() { account.deposit(1); } // An inner class for account private static class Account { private int balance = 0; public int getBalance() { return balance; } public void deposit(int amount) { int newBalance = balance + amount; // This delay is deliberately added to magnify the // data-corruption problem and make it easy to see. try { Thread.sleep(1); } catch (InterruptedException ex) { ex.printStackTrace(); } balance = newBalance; } 23
24
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Race Condition What, then, caused the error in the example? Here is a possible scenario: 24 The effect of this scenario is that Task 1 did nothing, because in Step 4 Task 2 overrides Task 1's result. Task 1 and Task 2 are accessing a common resource in a way that causes conflict. This is a common problem known as a race condition in multithreaded programs. A class is said to be thread-safe if an object of the class does not cause a race condition in the presence of multiple threads. As demonstrated in the preceding example, the Account class is not thread-safe.
25
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. The synchronized keyword To avoid race conditions, more than one thread must be prevented from simultaneously entering certain part of the program, known as critical region. The critical region in the Listing 29.7 is the entire deposit method. You can use the synchronized keyword to synchronize the method so that only one thread can access the method at a time. One way to correct the problem with Account is to make it thread- safe by adding the synchronized keyword in the deposit method as follows: public synchronized void deposit(int amount) 25
26
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Synchronizing Instance Methods and Static Methods With the deposit method synchronized, the preceding scenario cannot happen. If Task 2 starts to enter the method, and Task 1 is already in the method, Task 2 is blocked until Task 1 finishes the method. 26
27
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Synchronizing Instance Methods and Static Methods A synchronized method must acquire a lock before it executes. For an instance method, the lock is on the object for which the method was invoked. For a static method, the lock is on the class. If one thread invokes a synchronized instance method (respectively, static method) on an object, the lock of that object (respectively, class) is acquired first, then the method is executed, and finally the lock is released. Another thread invoking the same method of that object (respectively, class) is blocked until the lock is released. 27
28
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Synchronizing Statements Invoking a synchronized instance method of an object acquires a lock on the object, and invoking a synchronized static method of a class acquires a lock on the class. A synchronized statement can be used to acquire a lock on any object, not just this object, when executing a block of the code in a method. This block is referred to as a synchronized block. The general form of a synchronized statement is as follows: synchronized (expr) { statements; } The expression expr must be an object reference. If the object is already locked by another thread, the thread is blocked until the lock is released. When a lock is obtained on the object, the statements in the synchronized block are executed, and then the lock is released. 28
29
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Synchronizing Statements vs. Methods Any synchronized instance method can be converted into a synchronized statement. Suppose that the following is a synchronized instance method: public synchronized void xMethod() { // method body } This method is equivalent to public void xMethod() { synchronized (this) { // method body } 29
30
Liang, Introduction to Java Programming, Ninth Edition, (c) 2013 Pearson Education, Inc. All rights reserved. Deadlock Threads must sometimes wait for particular resources, such as the CPU or output hardware, to become available. A deadlock occurs when multiple threads are waiting for resources held by the others in an order that cannot be resolved. The simplest form of deadlock occurs when a process or thread enters a waiting state because a resource requested is being held by another waiting process, which in turn is waiting for a resource that the current thread is holding. 30
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.