290 likes | 383 Vues
Learn to implement and run threads in Java with practical examples and best practices for handling threads effectively to enhance your programming skills.
E N D
Multithreading (cont.)
Steps to Programming/Running a Threads • Implement a class that extends the Thread class • Place the code for your task into the run method of your class • Create an object of your subclass • Call the start method of your class to start the thread • When a Thread object is started, the code in its run method is executed in a new thread
GreetingThread Outline • A program to print a time stamp and "Hello World" once a second for ten seconds public class GreetingThread extends Thread { public void run() { //thread action . . . } //variables used by the thread action . . . }
Thread Action for GreetingThread • Print a time stamp • Print the greeting • Wait a second
GreetingThread • We can get the date and time by constructing Date object Date now = new Date(); • To wait a second, use the sleep method of the Thread class sleep(milliseconds) • A sleeping thread can generate an InterruptedException • Catch the exception • Terminate the thread
GreetingThreadrunmethod public void run() { try { //thread action } catch (InterruptedException e) { //cleanup, if necessary } }
File GreetingThread.java import java.util.Date; /** A thread that repeatedly prints a greeting. */ public class GreetingThread extends Thread { /** Constructs the thread object. @param aGreeting the greeting to display */ public GreetingThread(String aGreeting) { greeting = aGreeting; }
public void run( ) { try { for (int i = 1; i <= REPETITIONS; i++) { Date now = new Date(); System.out.println(now + " " + greeting); sleep(DELAY); } } catch (InterruptedException exception) { } } private String greeting; private static final int REPETITIONS = 10; private static final int DELAY = 1000; } /* end class */
To Start the Thread • Construct an object of your thread classGreetingThread t = new GreetingThread("Hello World"); • Call the start methodt.start();
File GreetingThreadTest.java import java.util.Date; /** This program tests the greeting thread by running two threads in parallel. */ public class GreetingThreadTest { public static void main(String[] args) { GreetingThread t1 = new GreetingThread("Hello, World!"); GreetingThread t2 = new GreetingThread("Goodbye, World!"); t1.start(); t2.start(); } }
Thread Scheduler • The thread scheduler runs each thread for a short amount of time called a time slice (quantum) • Then the scheduler picks another thread from those that are runnable • A thread is runnable if it is not asleep or blocked in some way • There is no guarantee about the order in which threads are executed
Terminating Threads • A thread terminates when its run method returns • Do not terminate a thread using the deprecated stop method • Instead, notify a thread that it should terminate t.interrupt();
Terminating Threads • A thread's run method should check occasionally whether it has been interrupted • Use the isInterrupted method • An interrupted thread should release resources, clean up, and exit • The sleep method throws an InterruptedException when a sleeping thread is interrupted • Catch the exception • Terminate the thread
Terminating a Thread public void run( ) { try { for (int = 1; i <= REPETITIONS &&!isInterrupted(); i++) { //do the work } } catch (InterruptedException exception) { //handling the exception } //cleanup }
Corrupting Data with Unsynchronized Threads • When threads share a common object, they can conflict with each other. • In this example, a DepositThread and a WithdrawThread both manipulate a single BankAccount
Sample Application • Create a BankAccount object • Create a DepositThread t0 to deposit $100 into the account for 10 iterations • Create a WithdrawThread t1 to withdraw $100 from the account for 10 iterations • The result should be zero, but sometimes it is not
Scenario to Explain Non-zero Result • The first thread t0 executes the lines System.out.print("Depositing " + amount); double newBalance = balance + amount; • t0 reaches the end of its time slice and t1 gains control • t1 calls the withdraw method which withdraws $100 from the balance variable. • Balance is now -100 • t1 goes to sleep
Scenario to Explain Non-zero Result (cont.) • t0 regains control and picks up where it left off. • t0 executes the lines System.out.println(", new balance is " + newBalance); balance = newBalance; • The balance is now 100 instead of 0 because the deposit method used the OLD balance • This is called a race condition.
Race condition • Occurs if the effect of multiple threads on shared data depends on the order in which the threads are scheduled • It is possible for a thread to reach the end of its time slice in the middle of a statement. • It may evaluate the right-hand side of an assignment but not be able to store the result until its next turn.
File BankAccountThreadTest.java /** This program runs two threads that deposit and withdraw money from the same bank account. */ public class BankAccountThreadTest { public static void main(String[] args) { BankAccount account = new BankAccount(); DepositThread t0 = new DepositThread(account, 100); WithdrawThread t1 = new WithdrawThread(account, 100); t0.start(); t1.start(); } }
File DepositThread.java /** A deposit thread makes periodic deposits to a bank account. */ class DepositThread extends Thread { /** Constructs a deposit thread. @param anAccount the account into which to deposit money @param anAmount the amount to deposit in each repetition */ public DepositThread( BankAccount anAccount, double anAmount) { account = anAccount; amount = anAmount; }
public void run() { try { for (int i = 1; i <= REPETITIONS && !isInterrupted(); i++) { account.deposit(amount); sleep(DELAY); } } catch (InterruptedException exception) { } } private BankAccount account; private double amount; private static final int REPETITIONS = 10; private static final int DELAY = 10; } /* end class */
run Method of DepositThread public void run() { try { for (int i = 1; i <= REPETITIONS && !isInterrupted(); i++) { account.deposit(amount); sleep(DELAY); } } catch (InterruptedException exception) { } }
File WithdrawThread.java /** A withdraw thread makes periodic withdrawals from a bank account. */ class WithdrawThread extends Thread { /** Constructs a withdraw thread. @param anAccount the account from which to withdraw money @param anAmount the amount to withdraw in each repetition */ public WithdrawThread(BankAccount anAccount, double anAmount) { account = anAccount; amount = anAmount; }
public void run() { try { for (int i = 1; i <= REPETITIONS && !isInterrupted(); i++) { account.withdraw(amount); sleep(DELAY); } } catch (InterruptedException exception) { } } private BankAccount account; private double amount; private static final int REPETITIONS = 10; private static final int DELAY = 10; }
File BankAccount.java /** A bank account has a balance that can be changed by deposits and withdrawals. */ public class BankAccount { /** Constructs a bank account with a zero balance */ public BankAccount() { balance = 0; } /** Deposits money into the bank account. @param amount the amount to deposit */
public void deposit(double amount) { System.out.print("Depositing " + amount); double newBalance = balance + amount; System.out.println(", new balance is " + newBalance); balance = newBalance; } /** Withdraws money from the bank account. @param amount the amount to withdraw */ public void withdraw(double amount) { System.out.print("Withdrawing " + amount); double newBalance = balance - amount; System.out.println(", new balance is " + newBalance); balance = newBalance; }
/** Gets the current balance of the bank account. @return the current balance */ public double getBalance() { return balance; } private double balance; }
Sometimes ... The final balance is not zero! The data is corrupted!