0% found this document useful (0 votes)
17 views37 pages

MultiThreadedProgramming

Uploaded by

Nikunj Shah3540
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
0% found this document useful (0 votes)
17 views37 pages

MultiThreadedProgramming

Uploaded by

Nikunj Shah3540
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
Download as pptx, pdf, or txt
Download as pptx, pdf, or txt
You are on page 1/ 37

Multithreaded

Programming
multithreaded programming
multithreaded programming
• Java provides built-in support for multithreaded programming. A
multithreaded program contains two or more parts that can run
concurrently. Each part of such a program is called a thread, and each
thread defines a separate path of execution. Thus, multithreading is a
specialized form of multitasking.
• There are two distinct types of multitasking: process-based and
thread-based.
multithreaded programming
• A process is, in essence, a program that is executing.
• Thus, process-based multitasking is the feature that allows your
computer to run two or more programs concurrently. For example,
process-based multitasking enables you to run the Java compiler at
the same time that you are using a text editor or visiting a web site. In
process-based multitasking, a program is the smallest unit of code
that can be dispatched by the scheduler.
multithreaded programming
• In a thread-based multitasking environment, the thread is the
smallest unit of dispatchable code. This means that a single program
can perform two or more tasks simultaneously. For instance, a text
editor can format text at the same time that it is printing, as long as
these two actions are being performed by two separate threads.
• Thus, process-based multitasking deals with the “big picture,” and
thread-based multitasking handles the details.
multithreaded programming
• Multitasking threads require less overhead than multitasking
processes.
• Processes are heavyweight tasks that require their own separate
address spaces.
• Interprocess communication is expensive and limited. Context
switching from one process to another is also costly.
multithreaded programming
• Threads, on the other hand, are lighter weight.
• They share the same address space and cooperatively share the same
heavyweight process.
• Interthread communication is inexpensive, and context switching
from one thread to the next is lower in cost.
• While Java programs make use of process-based multitasking
environments, process-based multitasking is not under Java’s direct
control.
• However, multithreaded multitasking is.
multithreaded programming
• Multithreading enables you to write efficient programs that make
maximum use of the processing power available in the system.
• One important way multithreading achieves this is by keeping idle
time to a minimum.
• This is especially important for the interactive, networked
environment in which Java operates because idle time is common.
• Multithreading helps you reduce this idle time because another
thread can run when one is waiting.
multithreaded programming
• Threads exist in several states.
• A thread can be running. It can be ready to run as soon as it gets CPU
time.
• A running thread can be suspended, which temporarily halts its
activity. A suspended thread can then be resumed, allowing it to pick
up where it left off.
• A thread can be blocked when waiting for a resource. At any time, a
thread can be terminated, which halts its execution immediately.
• Once terminated, a thread cannot be resumed.
multithreaded programming
• Java assigns to each thread a priority that determines how that thread
should be treated with respect to the others. Thread priorities are
integers that specify the relative priority of one thread to another. As
an absolute value, a priority is meaningless; a higher-priority thread
doesn’t run any faster than a lower-priority thread if it is the only
thread running.
• Instead, a thread’s priority is used to decide when to switch from one
running thread to the next. This is called a context switch. The rules
that determine when a context switch takes place are simple:
multithreaded programming
• A thread can voluntarily relinquish control. This occurs when explicitly
yielding, sleeping, or when blocked. In this scenario, all other threads
are examined, and the highest-priority thread that is ready to run is
given the CPU.
• A thread can be preempted by a higher-priority thread. In this case, a
lower-priority thread that does not yield the processor is simply
preempted —no matter what it is doing—by a higher-priority thread.
Basically, as soon as a higher-priority thread wants to run, it does. This
is called preemptive multitasking.
multithreaded programming
• New Thread creation: When a program calls the start() method, a new
thread is created and then the run() method is executed. But if we
directly call the run() method then no new thread will be created and
run() method will be executed as a normal method call on the current
calling thread itself and no multi-threading will take place.
• Example Program
• As we can see in the above example, when we call the start() method
of our thread class instance, a new thread is created with default
name Thread-0 and then run() method is called and everything inside
it is executed on the newly created thread.
multithreaded programming
• Now, let us try to call run() method directly instead
of start() method:
• Example Program
• As we can see in the above example, when we called
the run() method of our MyThread class, no new thread
is created and the run() method is executed on the
current thread i.e. main thread. Hence, no multi-
threading took place. The run() method is called as a
normal function call.
multithreaded programming
• Multiple invocation: In Java’s multi-threading
concept, another most important difference
between start() and run() method is that we can’t call
the start() method twice otherwise it will throw
an IllegalStateException whereas run() method can be
called multiple times as it is just a normal method
calling.
• As we can see in the above example,
calling run() method twice doesn’t raise any exception
and it is executed twice as expected but on
the main thread itself.
multithreaded programming
• How can one thread know when another thread
• Two ways exist to determine whether a thread has finished. First, you can call
• isAlive( ) on the thread. This method is defined by Thread, and its general
form is shown here:
• final boolean isAlive( ) has ended?
• The isAlive( ) method returns true if the thread upon which it is called is still
• running. It returns false otherwise.
• While isAlive( ) is occasionally useful, the method that you will more
• commonly use to wait for a thread to finish is called join( ), shown here:
• final void join( ) throws InterruptedException
multithreaded programming
• This method waits until the thread on which it is called terminates. Its name
comes from the concept of the calling thread waiting until the specified thread
joins it. Additional forms of join( ) allow you to specify a maximum amount
of
time that you want to wait for the specified thread to terminate.
• Here is an improved version of the preceding example that uses join( ) to
ensure that the main thread is the last to stop.
Synchronization
• When two or more threads need access to a shared resource, they need
some way to ensure that the resource will be used by only one thread at
a time. The process by which this is achieved is called synchronization.
Java provides unique, language-level support for it.
• Key to synchronization is the concept of the monitor. A monitor is an
object that is used as a mutually exclusive lock. Only one thread can
own a monitor at a given time. When a thread acquires a lock, it is said
to have entered the monitor. All other threads attempting to enter the
locked monitor will be suspended until the first thread exits the monitor.
These other threads are said to be waiting for the monitor. A thread that
owns a monitor can re-enter the same monitor if it so desires.
Synchronization
• To understand the need for synchronization, let’s begin with a simple
example that does not use it—but should. The following program has
three simple classes.
• The first one, Callme, has a single method named call( ).
• The call( ) method takes a String parameter called msg. This method
tries to print the msg string inside of square brackets.
• The interesting thing to notice is that after call( ) prints the opening
bracket and the msg string, it calls Thread.sleep(1000), which pauses
the current thread for one second.
Synchronization
• The constructor of the next class, Caller, takes a reference to an
instance of the Callme class and a String, which are stored in target
and msg, respectively.
• The constructor also creates a new thread that will call this object’s
run( ) method. The run( ) method of Caller calls the call( ) method on
the target instance of Callme, passing in the msg string.
• Finally, the Synch class starts by creating a single instance of Callme,
and three instances of Caller, each with a unique message string. The
same instance of Callme is passed to each Caller.
Gaurded Blocks
• Threads often have to coordinate their actions. The most common
coordination idiom is the guarded block. Such a block begins by
polling a condition that must be true before the block can proceed.
There are a number of steps to follow in order to do this correctly.

• Suppose, for example guardedJoy is a method that must not proceed


until a shared variable joy has been set by another thread. Such a
method could, in theory, simply loop until the condition is satisfied,
but that loop is wasteful, since it executes continuously while waiting.
Guarded Blocks

• public void guardedJoy() {


• // Simple loop guard. Wastes
• // processor time. Don't do this!
• while(!joy) {}
• System.out.println("Joy has been achieved!");
•}
Guarded Blocks
• A more efficient guard invokes Object.wait to suspend the current thread. The invocation of wait does not
return until another thread has issued a notification that some special event may have occurred — though
not necessarily the event this thread is waiting for:

• public synchronized void guardedJoy() {


• // This guard only loops once for each special event, which may not
• // be the event we're waiting for.
• while(!joy) {
• try {
• wait();
• } catch (InterruptedException e) {}
• }
• System.out.println("Joy and efficiency have been achieved!");
• }
Guarded Blocks
• Always invoke wait inside a loop that tests for the condition being waited for. Don't assume that
the interrupt was for the particular condition you were waiting for, or that the condition is still
true.
• Like many methods that suspend execution, wait can throw InterruptedException. In this
example, we can just ignore that exception — we only care about the value of joy.

• Why is this version of guardedJoy synchronized? Suppose d is the object we're using to invoke
wait. When a thread invokes d.wait, it must own the intrinsic lock for d — otherwise an error is
thrown. Invoking wait inside a synchronized method is a simple way to acquire the intrinsic lock.

• When wait is invoked, the thread releases the lock and suspends execution. At some future time,
another thread will acquire the same lock and invoke Object.notifyAll, informing all threads
waiting on that lock that something important has happened:
Guarded Blocks
• public synchronized notifyJoy() {
• joy = true;
• notifyAll();
•}
• Some time after the second thread has released the lock, the first thread
reacquires the lock and resumes by returning from the invocation of wait.
• There is a second notification method, notify, which wakes up a single thread.
Because notify doesn't allow you to specify the thread that is woken up, it is
useful only in massively parallel applications — that is, programs with a large
number of threads, all doing similar chores. In such an application, you don't
care which thread gets woken up.
Polling
• The process of testing a condition repeatedly till it becomes true is known as
polling.
• Polling is usually implemented with the help of loops to check whether a
particular condition is true or not. If it is true, certain action is taken. This
waste many CPU cycles and makes the implementation inefficient.
• For example, in a classic queuing problem where one thread is producing
data and other is consuming it.
• To avoid polling, Java uses three methods, namely, wait(), notify() and
notifyAll().
• All these methods belong to object class as final so that all classes have
them. They must be used within a synchronized block only.
Polling
• wait()-It tells the calling thread to give up the lock and go to sleep
until some other thread enters the same monitor and calls notify().

• notify()-It wakes up one single thread that called wait() on the same
object. It should be noted that calling notify() does not actually give
up a lock on a resource.

• notifyAll()-It wakes up all the threads that called wait() on the same
object.
Wait and notify

Wait() Notify()
When wait() is called on a thread holding the When the notify() is called on a thread holding
monitor lock, it surrenders the monitor lock and the monitor lock, it symbolizes that the thread is
enters the waiting state. soon going to surrender the lock.

One of the waiting threads is randomly selected


and notified about the same. The notified thread
then exits the waiting state and enters the
There can be multiple threads in the waiting blocked state where it waits till the previous
state at a time. thread has given up the lock and this thread has
acquired it. Once it acquires the lock, it enters
the runnable state where it waits for CPU time
and then it starts running.
Polling(Program)
• In the main class a new PC object is created.
• It runs produce and consume methods of PC object using two different
threads namely t1 and t2 and wait for these threads to finish.
• First of all, use of synchronized block ensures that only one thread at a time
runs. Also since there is a sleep method just at the beginning of consume
loop, the produce thread gets a kickstart.
• When the wait is called in produce method, it does two things. Firstly it
releases the lock it holds on PC object. Secondly it makes the produce
thread to go on a waiting state until all other threads have terminated, that
is it can again acquire a lock on PC object and some other method wakes it
up by invoking notify or notifyAll on the same object.
Polling
• First of all, use of synchronized block ensures that only one thread at a
time runs. Also since there is a sleep method just at the beginning of
consume loop, the produce thread gets a kickstart.
• When the wait is called in produce method, it does two things. Firstly it
releases the lock it holds on PC object. Secondly it makes the produce
thread to go on a waiting state until all other threads have terminated,
that is it can again acquire a lock on PC object and some other method
wakes it up by invoking notify or notifyAll on the same object.
• Therefore we see that as soon as wait is called, the control transfers to
consume thread and it prints -“Waiting for return key”.
Polling
• After we press the return key, consume method invokes notify(). It also does 2
things- Firstly, unlike wait(), it does not releases the lock on shared resource
therefore for getting the desired result, it is advised to use notify only at the end
of your method. Secondly, it notifies the waiting threads that now they can wake
up but only after the current method terminates.
• As you might have observed that even after notifying, the control does not
immediately passes over to the produce thread. The reason for it being that we
have called Thread.sleep() after notify(). As we already know that the consume
thread is holding a lock on PC object, another thread cannot access it until it has
released the lock. Hence only after the consume thread finishes its sleep time and
thereafter terminates by itself, the produce thread cannot take back the control.
• After a 2 second pause, the program terminates to its completion.
Threads
• Java’s multithreading system is built upon the Thread class, its
methods, and its companion interface, Runnable. Thread
encapsulates a thread of execution.
• Since you can’t directly refer to the ethereal state of a running thread,
you will deal with it through its proxy, the Thread instance that
spawned it. To create a new thread, your program will either extend
Thread or implement the Runnable interface.
• The Thread class defines several methods that help manage threads.
Thread
Thread
• A reference to the current thread (the main thread, in this case) is
obtained by calling currentThread( ), and this reference is stored in
the local variable t. Next, the program displays information about the
thread. The program then calls setName( ) to change the internal
name of the thread.
• Information about the thread is then redisplayed. Next, a loop counts
down from five, pausing one second between each line. The pause is
accomplished by the sleep( ) method. The argument to sleep( )
specifies the delay period in milliseconds
Thread
• Notice the try/catch block around this loop. The sleep( ) method in Thread might throw
an InterruptedException. This would happen if some other thread wanted to interrupt
this sleeping one. This example just prints a message if it gets interrupted. In a real
program, you would need to handle this differently. Here is the output generated by
this program:
• Current thread: Thread[main,5,main]
• After name change: Thread[My Thread,5,main]
•5
•4
•3
•2
•1
Thread
• Notice the output produced when t is used as an argument to println( ). This
displays, in order: the name of the thread, its priority, and the name of its
group.
• By default, the name of the main thread is main. Its priority is 5, which is the
default value, and main is also the name of the group of threads to which this
thread belongs. A thread group is a data structure that controls the state of a
collection of threads as a whole. After the name of the thread is changed, t is
again output.
• This time, the new name of the thread is displayed. Let’s look more closely at
the methods defined by Thread that are used in the program. The sleep( )
method causes the thread from which it is called to suspend execution for
the specified period of milliseconds.

You might also like