Enables in A Program To Be Executed: Multiple Threads - Multithreading
Enables in A Program To Be Executed: Multiple Threads - Multithreading
Enables in A Program To Be Executed: Multiple Threads - Multithreading
Multithreading Concept
Introduction
• Multithreading in java is a process of executing multiple threads
simultaneously. Or in other words,
• Multithreading enables multiple tasks in a program to be executed
concurrently.
• Multiprocessor: refers to the use of two or more central processing units
(CPU) within a single computer system.
• Multiprocessing and multithreading, both are used to achieve multitasking.
• Java Multithreading is mostly used in games, animation, etc.
• Multitasking is when multiple processes share common processing resources
such as a CPU.
• Multi-threading extends the idea of multitasking into applications where you
can subdivide specific operations within a single application into individual
threads.
• Each of the threads can run in parallel.
1
Multitasking
• Multitasking is a process of executing multiple tasks simultaneously.
We use multitasking to utilize the CPU.
• Multitasking can be achieved in two ways:
1. Process-based Multitasking (Multiprocessing)
2. Thread-based Multitasking (Multithreading)
1. Process-based Multitasking (Multiprocessing)
– Each process has an address in memory. In other words, each process allocates
a separate memory area.
– A process is heavyweight.
– Cost of communication between the process is high.
– Switching from one process to another requires some time for saving and
loading registers, memory maps, updating lists, etc.
2. Thread-based Multitasking (Multithreading)
– Threads share the same address space.
– A thread is lightweight.
– Cost of communication between the thread is low.
2
Advantages of Multithreading
A process can communicate with A thread can communicate with other thread
other process by using inter- (of the same process) directly by using
process communication. methods like wait(), notify(), notifyAll().
A process does not have control Threads have control over the other threads of
over the sibling process; it has the same process.
control over its child processes
only. 4
What is Thread in Java?
Multiple threads
are running on
multiple CPUs
Multiple threads
sharing a single
CPU
7
The Thread class in Java
• Java provides Thread class to achieve thread programming.
• Thread class provides constructors and methods to create and perform
operations on a thread.
• Threads can be created by using two mechanisms :
1. Extending java.lang.Thread class
The thread class extends the Thread class
run() method must be overridden
run() is called when execution of the thread begins
A thread terminates when run() returns
start() method invokes run()
Calling run() does not create a new thread
2. Implementing java.lang.Runnable interface
Thread class implements Runnable interface.
Runnable interface have only one method named: public void run(): is used to
perform action for a thread.
You need to implement a run() method provided the Runnable interface
8
1. Creating a Thread by implementing Runnable Interface
• We create a new class which implements Runnable interface and
override run() method.
• Then we instantiate a Thread object and call start() method on
this object.
java.lang.Runnable TaskClass // Client class
public class Client {
...
// Custom task class public void someMethod() {
public class TaskClass implements Runnable { ...
... // Create an instance of TaskClass
public TaskClass(...) { TaskClass task = new TaskClass(...);
...
} // Create a thread
Thread thread = new Thread(task);
// Implement the run method in Runnable
public void run() { // Start a thread
// Tell system how to run custom thread thread.start();
... ...
} }
... ...
} }
9
Example: Creating and Launching Threads using
the Runnable Interface
10
Example: Using the Runnable Interface
// Start threads
thread1.start();
thread2.start();
thread3.start();
}
}
11
Example: Using the Runnable Interface
class PrintChar implements Runnable {
private char charToPrint;
private int times;
public PrintChar(char c, int t) {
charToPrint = c;
times = t;
}
public void run() {
for (int i = 0; i < times; i++) {
System.out.print(charToPrint);
}
}
}
class PrintNum implements Runnable{
private int lastNum;
public PrintNum(int n) {
lastNum = n;
}
public void run() {
for (int i = 1; i <= lastNum; i++) {
System.out.print(" " + i);
}
}
}
12
Code Description
• The program creates three tasks .
• To run them concurrently, three threads are created.
• The start() method is invoked to start a thread that causes the run()
method in the task to be executed.
• When the run() method completes, the thread terminates.
• Because the first two tasks, printA and printB, have similar functionality,
they can be defined in one task class PrintChar.
• The PrintChar class implements Runnable and overrides the run() method
with the print-character action.
• This class provides a framework for printing any single character a given
number of times.
• The runnable objects printA and printB are instances of the PrintChar class.
• The PrintNum class implements Runnable and overrides the run()
method with the print-number action.
• This class provides a framework for printing numbers from 1 to n, for any
integer n. The runnable object print100 is an instance of the class printNum
class.
13
Run() Methods
• The run() method in a task specifies how to
perform the task.
• This method is automatically invoked by the
JVM.
• You should not invoke it.
• Invoking run() directly merely executes this
method in the same thread; no new thread is
started.
14
2. Creating a Thread by extending Thread class
16
2. Creating a Thread by extending Thread class
17
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 the
run() method inTaskThreadDemo.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. So, the numbers are printed after the
characters.
18
The static sleep(milliseconds) Method
The sleep(long milliseconds) method of Thread class is used to sleep a
thread for the specified amount of time.
For example, suppose you modify the code in TaskThreadDemo.java as
follows:
public void run() {
for (int i = 1; i <= lastNum; i++) {
System.out.print(" " + i);
try {
if (i >= 50)
Thread.sleep(1);
}
catch (InterruptedException ex) {
}
}
}
Every time a number (>= 50) is printed, the print100 thread is put to
sleep for 1 millisecond.
19
The join() Method
You can use the join() method to force one thread to wait for another thread to
finish.
interrupt() sleep()
Target wait()
finished
23
Thread methods
isAlive()
method used to find out the state of a thread.
returns true: thread is in the Ready, Blocked, or Running state
returns false: thread is new and has not started or if it is finished.
interrupt()
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.
24
The deprecated stop(), suspend(), and resume()
Methods
NOTE: The Thread class also contains the stop(), suspend(), and
resume() methods.
25
Thread Priority
• Each thread have a priority. Priorities are represented by numbers ranging from 1 and 10.
• You can increase or decrease the priority of any thread by using the
setPriority method, and you can get the thread’s priority by using the getPriority method.
• The Thread class has three int constant priorities.
– public static int MIN_PRIORITY --- with value 1
– public static int NORM_PRIORITY --- with value 5
– public static int MAX_PRIORITY --- with value 10
• Default priority of a thread is 5 (NORM_PRIORITY).
• The JVM always picks the currently runnable thread with the highest priority.
• A lower priority thread can run only when no higher-priority threads are running.
• If all runnable threads have equal priorities, each is assigned an equal portion of the CPU
time in a circular queue. This is called round-robin scheduling.
• You can reset the priority using setPriority(int priority).
• For example, suppose you insert the following code in TaskThreadDemo.java for thread3.
thread3.setPriority(Thread.MAX_PRIORITY);
• The thread for the print100 task will be finished first.
26
Thread Scheduling in Java
28
Java Thread Pool
• Thread pool can be used to execute tasks efficiently
• Defining tasks and threads independently is convenient for a single task
execution, but it is not efficient for a large number of tasks, because you
have to create a thread for each task.
• Starting a new thread for each task could limit throughput and cause poor
performance.
• A thread pool is ideal to manage the number of tasks executing
concurrently.
• A thread pool reuses previously created threads to execute current tasks
and offers a solution to the problem of thread cycle overhead and
resource thrashing.
• Java provides the Executor interface for executing tasks in a thread pool
and the ExecutorService interface for managing and controlling tasks.
29
Java Thread Pool
• ExecutorService is a sub-interface of Executor, as shown in
Figure below.
«interface»
java.util.concurrent.Executor
+execute(Runnable object): void Executes the runnable task.
\
«interface»
java.util.concurrent.ExecutorService
+shutdown(): void Shuts down the executor, but allows the tasks in the executor to
complete. Once shutdown, it cannot accept new tasks.
+shutdownNow(): List<Runnable> Shuts down the executor immediately even though there are
unfinished threads in the pool. Returns a list of unfinished
tasks.
+isShutdown(): boolean Returns true if the executor has been shutdown.
+isTerminated(): boolean Returns true if all tasks in the pool are terminated.
30
Creating Executors
To create an Executor object, use the static methods in the Executors class
as shown in Figure below. The newFixedThreadPool(int) method creates a
fixed number of threads in a pool. If a thread completes executing a task, it
can be reused to execute another task. If a thread terminates due to a failure
prior to shutdown, a new thread will be created to replace it if all the
threads in the pool are not idle and there are tasks waiting for execution.
The newCachedThreadPool() method creates a new thread if all the
threads in the pool are not idle and there are tasks waiting for execution. A
thread in a cached pool will be terminated if it has not been used for 60
seconds. A cached pool is efficient for many short tasks.
java.util.concurrent.Executors
+newFixedThreadPool(numberOfThreads: Creates a thread pool with a fixed number of threads executing
int): ExecutorService concurrently. A thread may be reused to execute another task
after its current task is finished.
+newCachedThreadPool(): Creates a thread pool that creates new threads as needed, but
ExecutorService will reuse previously constructed threads when they are
available. 31
Example: Thread Pool
The following program shows how to rewrite the code in TaskThreadDemo.java using
a thread pool.
Steps to be follow:
1. Create a task (Runnable object) to execute
2. Create Executor Pool using Executors
3. Pass tasks to Executor Pool
4. Shutdown the Executor Pool
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 PrintNum(100));
33
Example: Showing Resource Conflict
• Objective: Write a program that demonstrates the problem of
resource conflict. Suppose that you create and launch one
hundred threads, each of which adds a penny to an account.
Assume that the account is initially empty.
34
Example: Showing Resource Conflict
import java.util.concurrent.*;
public class AccountWithoutSync {
private static Account account = new Account();
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 100; i++) {
executor.execute(new AddAPennyTask());
}
executor.shutdown();
while (!executor.isTerminated() ) {
}
System.out.println("What is balance? " + account.getBalance());
}
private static class AddAPennyTask implements Runnable {
public void run() {
account.deposit(1);
}
}
private static class Account {
private int balance = 0;
public int getBalance() {
return balance;
}
public void deposit(int amount) {
int newBalance = balance + amount;
try {
Thread.sleep(5);
}
catch (InterruptedException ex) {
}
balance = newBalance;
}
}
35
}
Race Condition
What, then, caused the error in the example? Here is a possible
scenario:
Step balance Task 1 Task 2
1 0 newBalance = balance + 1;
2 0 newBalance = balance + 1;
3 1 balance = newBalance;
4 1 balance = newBalance;
);
• Effect: Task 1 did nothing (in Step 4 Task 2 overrides the result)
• Problem: Task 1 and Task 2 are accessing a common resource in a
way that causes conflict.
• Known as a race condition in multithreaded programs.
•A thread-safe class does not cause a race condition in the presence of
multiple threads. The Account class is not thread-safe.
36
The synchronized Keyword
• Problem: race conditions
• Solution: give exclusive access to one thread at a time to code that
manipulates a shared object.
• To avoid race conditions, it is necessary to prevent more than one thread
from simultaneously entering a certain part of the program, known as the
critical region.
• Synchronization keeps other threads waiting until the object is available.
• The synchronized keyword synchronizes the method so that only one
thread can access the method at a time.
• The critical region in the previous code (AccountWithoutSync.java) is the
entire deposit method.
• One way to correct the problem in this code: make Account thread-safe by
adding the synchronized keyword in deposit method as follows:
Acquire a-char
locktoken
on the object account -char token
+getToken +getToken
-char token +setToken +setToken
+paintComponet +paintComponet
Execute
+getToken the deposit method
+mouseClicked +mouseClicked
+setToken
+paintComponet Wait to acquire the lock
-char token
+mouseClicked
-char token
+getToken Release the lock
+setToken
+getToken
+paintComponet
-char token Acqurie a lock
+setToken on the object account
+mouseClicked
+paintComponet
+getToken -char token
+mouseClicked
+setToken
+paintComponet Execute the deposit method
+getToken
+mouseClicked +setToken
+paintComponet
-char token
+mouseClicked
+getToken Release the lock 39
+setToken
+paintComponet
Synchronized Block
• Synchronized block can be used to perform synchronization on any specific resource of the
method.
• Suppose you have 50 lines of code in your method, but you want to synchronize only 5 lines,
you can use synchronized block.
• Synchronized block is used to lock an object for any shared resource.
• Scope of synchronized block is smaller than the method.
synchronized (object reference expression) {
statements;
}
• 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.
• Synchronized statements enable you to synchronize part of the code in a method instead of the
entire method. This increases concurrency.
• You can make AccountWithoutSync.java thread-safe by placing the statement inside a
synchronized block:
synchronized (account) {
account.deposit(1);
} 40
Inter-Thread Communication (Cooperation Among Threads)
• Inter-thread communication or Co-operation is all about allowing
synchronized threads to communicate with each other.
• Cooperation (Inter-thread communication) is a mechanism in which a
thread is paused running in its critical section and another thread is
allowed to enter (or lock) in the same critical section to be executed. It
is implemented by following methods of Object class:
• wait(): this method lets the thread wait until some condition occurs.
• notify(): this method wakes up only one thread from a waiting queue.
• notifyAll(): this method wakes up all waiting threads.
• Use the wait(), notify(), and notifyAll() methods to facilitate
communication among threads.
• The wait(), notify(), and notifyAll() methods must be called in a
synchronized method or a synchronized block on the calling object of
these methods. Otherwise, an IllegalMonitorStateException would
occur.
• Conditions can be used for communication among threads. 41
Inter-Thread Communication (Cooperation Among Threads)
42
Inter-Thread Communication (Cooperation Among Threads)
-char token
-char token
+getToken
Acquire a permit from a semaphore. semaphore.acquire();
+setToken
Wait if the permit is not available. +getToken
+paintComponet +setToken
+mouseClicked
-char token +paintComponet
+mouseClicked
+getToken
Access the resource Access the resource
+setToken
+paintComponet
-char token -char token
+mouseClicked
+getToken +getToken
Release the permit to the semaphore semaphore.release();
+setToken +setToken
+paintComponet 44
+paintComponet
-char token -char token
Creating Semaphores
• To create a semaphore, you have to specify the number of permits with an optional
fairness policy, as shown in Figure below.
• A task acquires a permit by invoking the semaphore’s acquire() method and releases
the permit by invoking the semaphore’s release() method.
• Once a permit is acquired, the total number of available permits in a semaphore is
reduced by 1.
• Once a permit is released, the total number of available permits in a semaphore is
increased by 1.
java.util.concurrent.Semaphore
+Semaphore(numberOfPermits: int) Creates a semaphore with the specified number of permits. The
fairness policy is false.
+Semaphore(numberOfPermits: int, fair: Creates a semaphore with the specified number of permits and
boolean) the fairness policy.
+acquire(): void Acquires a permit from this semaphore. If no permit is
available, the thread is blocked until one is available.
+release(): void Releases a permit back to the semaphore.
45
Deadlock
• Deadlock in java is a part of multithreading. Deadlock can occur in a situation
when a thread is waiting for an object lock, that is acquired by another thread
and second thread is waiting for an object lock that is acquired by first thread.
Since, both threads are waiting for each other to release the lock, the condition
is called deadlock.
• Consider the scenario with two threads and two objects, as shown in Figure
below. Thread 1 has acquired a lock on object1, and Thread 2 has acquired a
lock on object2. Now Thread 1 is waiting for the lock on object2, and Thread
2 for the lock on object1. Each thread waits for the other to release the lock it
needs, and until that happens, neither can continue to run.
46
Preventing Deadlock
48