Lecture 15 - Java MultiThreading

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 44

Lecture # 15: Java Multi-threading

SE 241 Advance Computer Programming


Muhammad Imran adopted from Dr. Usman Nasir
Multitasking
 In computers, multitasking is the
concurrent execution of multiple tasks
(also known as processes) over a certain
period of time.
 The tasks share common processing resources
 This way, several processes can be
running on one CPU at same time.
Multitasking in Java
 An effect of parallel execution by creating
multiple threads
 Threads are like the processes, but are
light-weight, that is, they do not require
as much overhead and operating system
resources as full blown processes
Java Thread & Multithreading
 In Java a thread is a
lightweight process
and has it own
separate path of
execution.
 Each thread represents
its own flow of logic,
gets separate runtime
stack
 A multithreaded
program contains two
or more threads that
can run concurrently.
Multithreading in Java
 The JVM (a process) executes each thread
in the program for a short amount of time
 Threads are largely managed by the JVM
 As everything in Java belongs to a class,
threading is integrated into objects
 New threads are created when objects are
started in their own thread
 Same code for every Java VM
 Simpler than in most other languages
Creating and Starting Threads
 Creating a thread in Java is done by
making an object of Thread class and
calling its start method.
Thread thread = new Thread();
thread.start()
 Thread class implements a generic thread
that, by default, does nothing
 There are two techniques for creating and
running a threads in Java :
 Inheriting from Thread class and overriding the
run method
 Implementing Runnable interface to your class.
Inheriting Thread class
public class ThreadExample extends Thread {
public ThreadTest(String name) {
super(name);
System.out.println("Created " + name);
}

public void run( ) {


System.out.println(getName()+" started");
try {
Thread.sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) { }
System.out.println(getName() + “ finishing");
}
}
public class ThreadDemo {
public static void main(String args[]) {
ThreadTest[] tt = new ThreadTest[3];
tt[0] = new ThreadTest("Thread 1");
tt[1] = new ThreadTest(“Thread 2”);
tt[2] = new ThreadTest(“Thread 3”);
System.out.println(“Finished creating threads");

tt[0].start();
tt[1].start();
tt[2].start();
System.out.println(“Finished starting threads");
}
}
 The exact output depends on your CPU & JVM. In executing
thread and finishing.
> java ThreadDemo
Created Thread 1
Created Thread 2
Created Thread 3
Finished creating threads
Thread 1 started
Thread 2 started
Thread 3 started
Finished starting threads
Thread 3 finishing
Thread 1 finishing
Thread 2 finishing
Implementing Runnable Interface
 The second way to is to write a class that
implements the java.lang.Runnable
interface.
 A Java object that implements the
Runnable interface can be executed by a
Java Thread.
 Runnable interface only has a single
method
public void run( )
 When creating and starting a thread for
runnable reference a common mistake is
to call the run() method of the Thread
instead of start()
Thread newThread = new
Thread(MyRunnable());
newThread.run(); //should be start();

 The run( ) method is executed but not


executed by the new thread.
Implementing Runnable Interface
public class ThreadTestRun implements Runnable {
String name;
public ThreadTest2(String name) {
this.name = name;
System.out.println(“Created “ + name);
}

public void run( ) {


System.out.println(name + “ started");
try {
Thread.sleep((long)(Math.random() * 1000));
} catch (InterruptedException e) { }
System.out.println(name + “ finishing");
}
}
public class ThreadDemo2 {
public static void main(String args[]) {
ThreadTestRun one= new ThreadTestRun
("Thread 1");
ThreadTestRun two= new ThreadTestRun
("Thread 1");
System.out.println(“Finished creating
threads");
Thread t= new Thread(one);
t.start();
new Thread(two).start();
System.out.println(“Finished starting
threads");
}
}
Java Thread Model
 Java run-time system depends on threads to reduce
inefficiency by preventing the waste of CPU cycles.
 A thread in Java exist in several states:
 New
 When we create an instance of Thread class, a thread is in a
new state.
 Running
 The Java thread is in running state.
 Suspended
 A running thread can be suspended, which temporarily
suspends its activity.
 Blocked
 A Java thread can be blocked when waiting for a resource.
 Terminated
 A thread can be terminated, which halts its execution
immediately at any given time. Once a thread is terminated, it
cannot be resumed.
The life cycle of a thread

start
Thread State: New
 After creating an instance Thread, the
thread is in new thread state
 ThreadTest tt = new ThreadTest("Thread 1");
 When a thread is in new state, it is merely an
empty Thread object and no system resources
have been allocated to it.
In this state, you can only start the thread.
 Calling any method besides start when a
thread is in this state makes no sense and
causes an IllegalThreadStateException.
Thread State: Running
 Once start method is invoked on a thread,
the thread goes into running state
tt.start( );

 Start method creates the system resources


necessary to run the thread, schedules the
thread to run, and calls the thread's run
method
Time Slicing & Thread Scheduler
 The thread scheduler runs each thread for
a short amount of time called a time slice.
 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
Thread Not Runnable
 A thread becomes Not Runnable when one
of these events occurs:
 Its sleep method is invoked
 The thread calls the wait method to wait for a
specific condition to be satisfied
 The thread is blocking on I/O

 For each entrance into the Not Runnable


state, there is a specific escape route that
returns the thread to the Runnable state
Escape Routes
 If a thread has been put to sleep, then the
specified number of milliseconds must
elapse
 If a thread is waiting for a condition, then
another object must notify the waiting
thread of a change in condition by calling
notify or notifyAll

 If a thread is blocked on I/O, then the I/O


must complete.
Stoping a Thread
 A thread terminates when its run method finishes.
 Program are recommended that they do not terminate
a thread using the deprecated stop method rather use
a method interrupt()
 This notifies the thread that it should terminate.
 Thus a thread's run method should check occasionally
whether it has been interrupted by checking 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 and then terminate the thread
public class Threading extends Thread {
public void run() {int count = 0;
System.out.println(getName() + " started");
System.out.println("Working in " +
Thread.currentThread().getName());
for (int i = 0; i < 10000000 && !isInterrupted(); i++) { count++;}
System.out.println(getName() + " finishing and count is: " + count);
}

public static void main(String args[]) throws Exception {


Threading one = new Threading("Thread 1");
Threading two = new Threading("Thread 2");
one.start(); two.start();
Thread.sleep(7);//Puts main to sleep for 07 milli seconds only
one.interrupt();
}
}//end of class
Output:
Thread 1 started
Thread 2 started
Working in Thread 2
Working in Thread 1
Thread 1 finishing and count is: 34150
Thread 2 finishing and count is: 10000000
Java Memory Model and Threads
 Each thread running in the Java virtual
machine has its own thread stack that
contains information about what methods the
thread has called to reach the current point of
execution.
 The thread stack also contains all local
variables for each method being executed. A
thread can only access it's own thread stack.
 Local variables created by a thread are invisible to
all other threads than the thread who created it.
 All local variables of primitive types are fully stored
on the thread stack and are thus not visible to
other threads.
Critical section & Race condition
 Critical section is a section of code that is
executed by multiple threads and where
the sequence of execution for the threads
makes a difference in the result of the
concurrent execution of the critical section.
 Race condition is the situation where two
threads compete for the same resource
and the sequence in which the resource is
accessed is significant.
Preventing Race Conditions
 To prevent race conditions from occurring
programmer must make sure that the critical
section is executed as an atomic instruction.
 Once a single thread is executing instruction, no
other threads can execute that instruction until the
first thread has left the critical section.

 Race conditions can be avoided by proper


thread synchronization in critical sections.
Java synchronized block
 Synchronized block marks a method or a
block of code as synchronized that helping
avoiding race conditions.
 Synchronized blocks in Java are marked with
the synchronized keyword.
 A synchronized block in Java is synchronized on
some object.
 The synchronized synchronized keyword can
be used to mark four different types of blocks:
 Instance methods
 Static methods
 Code blocks inside instance methods
 Code blocks inside static methods
 Method add( ) is synchronized.
public synchronized void add(int value){
this.count += value;
}

 Synchronized Static methods:


public static synchronized void add(int
value){
count += value;
}
 Synchronized Blocks in Instance Methods
 You do not have to synchronize a whole method,
some part of code can be synchronized inside
methods
 Synchronized block inside an unsynchronized
method:
public void add(int value){
synchronized(this){
this.count += value;
}
}
 Synchronized Blocks in Static Methods

public class MyClass {

public static synchronized void log1(String msg1, String


msg2){
log.writeln(msg1);
log.writeln(msg2);
}

public static void log2(String msg1, String msg2){


synchronized(MyClass.class){
log.writeln(msg1);
log.writeln(msg2);
}
}
}
Bank Application (Example)
 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 on
sometimes it is not
BankAccount.java
public BankAccount() {
balance = 0;
}
public BankAccount(double initDepo) {
balance = initDepo;
}
public void deposit(double amount) {
double newBalance = balance + amount;
System.out.println("Depositing " + amount +", new
balance is " + newBalance);
balance = newBalance;}

}
BankAccount.java
public void withdraw(double amount) {
double newBalance = balance - amount;
System.out.println("Withdrawing " +
amount +", new balance is "+ newBalance);
balance = newBalance;
}

public double getBalance() { return balance;}

}//end of class
DepositThread.java
public class DepositThread extends Thread {
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;
}
Driver
BankAccount acc = new BankAccount(0);
System.out.println(acc.getBalance());

DepositThread deposits = new DepositThread(acc,


100);
WithdrawThread withdraws = new
WithdrawThread(acc, 100);

deposits.start(); withdraws.start();

Thread.sleep(1000);
System.out.println("Closing Bal now: " +
acc.getBalance());
Output
0.0
Depositing 100.0, new balance is 100.0
Withdrawing 100.0, new balance is -100.0
Withdrawing 100.0, new balance is -200.0
Depositing 100.0, new balance is 0.0
Depositing 100.0, new balance is 100.0
……………
……………
Withdrawing 100.0, new balance is 0.0
Depositing 100.0, new balance is 200.0
Withdrawing 100.0, new balance is 200.0
Depositing 100.0, new balance is 400.0
Closing Bal now: 400.0
 The first thread t0 executes the lines
 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 and t0 regains control
and picks up where it left off.
 t0 executes next lines
Synchronized Methods
public class BankAccount {
public synchronized void deposit(double
amount) {
...
}

public synchronized void withdraw(double


amount) {
...
}
...
}
 By declaring both the deposit and withdraw
methods to be synchronized
 Only one thread at a time can execute either
method on a given object
 When a thread starts one of the methods, it is
guaranteed to execute the method to completion
before another thread can execute a
synchronized method on the same object.
Thank you
 Very good tutorial with a lot of details:
http://tutorials.jenkov.com/java-
concurrency/index.html

You might also like