0% found this document useful (0 votes)
5 views26 pages

Java Multithreading Execution Order

Chapter 4 covers Exception Handling and Multithreaded Programming, detailing types of errors, exceptions, and their management in Java. It explains compile-time and run-time errors, the distinction between checked and unchecked exceptions, and provides examples of common exceptions. Additionally, the chapter discusses multithreading concepts, including thread creation, lifecycle, synchronization, and communication.

Uploaded by

anupatil7576
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views26 pages

Java Multithreading Execution Order

Chapter 4 covers Exception Handling and Multithreaded Programming, detailing types of errors, exceptions, and their management in Java. It explains compile-time and run-time errors, the distinction between checked and unchecked exceptions, and provides examples of common exceptions. Additionally, the chapter discusses multithreading concepts, including thread creation, lifecycle, synchronization, and communication.

Uploaded by

anupatil7576
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Chapter 4: Exception Handling & Multithreaded Programming

Chapter 4: Exception Handling & Multithreaded Programming


CONTENTS

4.1 Errors & Exception

 Types of errors
 exceptions,
 try & catch statement,
 nested try statement,
 throws & Finally statement,
 build-in exceptions,
 chained exceptions,
 Creating own exception, subclasses.
4.2 Multithreaded Programming

 Creating a Thread: By extending the thread class & by implementing runnable


Interface.
 Life cycle of thread: Thread Methods: wait (), sleep (), notify (), resume (), suspend
(), stop ().
 Thread exceptions,
 thread priority & methods,
 synchronization,
 inter-thread communication,
 Deadlock.

Prepared by Mrs. N. S. Gite 1


Chapter 4: Exception Handling & Multithreaded Programming

4.1 Errors & Exception

Introduction

Rarely does a program run successfully at its very first attempt. It is common to make
mistakes while developing as well as typing a program. a mistake might lead to an
error causing the program to produce unexpected results. Errors are the wrongs that
can make program go wrong.
An error may produce an incorrect output or may terminate the execution of the
program abruptly or even may cause the system to crash. It is therefore important to
detect and manage properly all the possible error conditions in the program so that the
program will not terminate or crash during execution.

Types of errors

Errors may broadly be classified into two categories:

1. Compile-time errors
2. Run-time errors

1. Compile-Time Errors

All syntax errors will be detected and displayed by the Java compiler and therefore
these errors are known as compile-time errors. Whenever the computer displays an
error, it will not create .class file. It is therefore necessary that we fix all the errors
before we can successfully compile and run the program.

The most common compile-time errors are:


1. Missing semicolons
2. Missing (or mismatch of) brackets in classes and methods
3. Misspelling of identifiers and keywords.
4. Missing double quotes in strings
5. Use of undeclared variables
6. Incompatible types in assignments/initialization
7. Bad reference to objects
8. Use of = in place of == operator
And so on…….

2. Run-Time Errors

Prepared by Mrs. N. S. Gite 2


Chapter 4: Exception Handling & Multithreaded Programming

Sometimes, a program may compile successfully creating the .class file but may not
run properly. Such programs may produce wrong results due to wrong logic or may
terminate due to errors such as stack overflow. Such a errors are called as Run-Time
errors. Run-Time errors are detected and display by Java Interpreter.

Most common run-time errors are:


1. Dividing an integer by zero
2. Accessing an element that is out of the bounds of an array
3. Trying to store a value into an array of an incompatible class or type
4. Trying to cast an instance of a class to one of its subclasses
5. Passing a parameter that is not in a valid range or value for a method
6. Trying to illegally change the state of a thread
7. Attempting to use a negative size of array
8. Using a null object reference as a legitimate object reference to access a method or a
variable
9. Converting invalid string to a number
10. Accessing a character that is out of bounds of a string
And many more….

When such errors are encountered, Java typically generates an error message and
aborts the programs.

Types of Exception

There are mainly two types of exceptions: checked and unchecked where error is
considered as unchecked exception. The sun microsystem says there are
three types of exceptions:
1. Checked Exception
2. Unchecked Exception
3. Error

Difference between checked and unchecked exceptions


1) Checked Exception

The classes that extend Throwable class except RuntimeException and Error
are known as checked exceptions [Link], SQLException etc. Checked
exceptions are checked at compile-time.

2) Unchecked Exception
The classes that extend RuntimeException are known as unchecked exceptions
e.g. ArithmeticException, NullPointerException,
ArrayIndexOutOfBoundsException etc.
Unchecked exceptions are not checked at compile-time rather they are checked at
runtime.
3) Error

Prepared by Mrs. N. S. Gite 3


Chapter 4: Exception Handling & Multithreaded Programming

Error is irrecoverable
e.g. OutOfMemoryError, VirtualMachineError, AssertionError etc.

Common scenarios where exceptions may occur

There are given some scenarios where unchecked exceptions can occur. They are as
follows:

1) Scenario where ArithmeticException occurs

If we divide any number by zero, there occurs an ArithmeticException.

int a=50/0;//ArithmeticException
2)Scenario where NullPointerException occurs

If we have null value in any variable, performing any operation by the variable occurs
an NullPointerException.

String s=null;
[Link]([Link]()); //NullPointerException

3)Scenario where NumberFormatException occurs

The wrong formatting of any value, may occur NumberFormatException. Suppose I


have a string variable that have characters, converting this variable into digit will
occur NumberFormatException.

String s="abc";
int i=[Link](s);//NumberFormatException

4)Scenario where ArrayIndexOutOfBoundsException occurs

If you are inserting any value in the wrong index, it would result
ArrayIndexOutOfBoundsException as shown below:

int a[]=new int[5];


a[10]=50; //ArrayIndexOutOfBoundsException

Exceptions

An exception is a condition that is caused by a run-time error in the program. when


the Java interpreter encounters an error such as dividing an integer by zero, it creates
an exception object and throws it (i.e., informs us that an error has occurred).

If we want the program to continue with the execution of the remaining code, then we
should try to catch the exception object thrown by the error condition and then

Prepared by Mrs. N. S. Gite 4


Chapter 4: Exception Handling & Multithreaded Programming

displaying an appropriate message for taking corrective actions. This task is known as
exception handling.

Error handling code performs the following tasks:


1. Find the problem (Hit the exception)
2. Inform that an error has occurred (Throw the exception)
3. Receive the error information (Catch the exception)
4. Take corrective actions (Handle the exception)
The error handling code basically consists of two segments, one to detect errors and to
throw exceptions and the other to catch exceptions and to take appropriate actions.

Exception Hierarchy

Prepared by Mrs. N. S. Gite 5


Chapter 4: Exception Handling & Multithreaded Programming

Common Java Exceptions

Exception Type Cause of Exception


ArithmeticException Caused by math errors such as division by zero
ArrayIndexOutOfBoundsException Caused by bad array indexes
ArrayStoreException Caused when a program tries to store the wrong
type of data in an array
FileNotFoundException Caused by an attempt to access a non-existent
file
IOException Caused by general I/O failures, such as inability
to read from a file
NullPointerException Caused by referencing a null object
NumberFormatException Caused when a conversion between strings and
numbers fails
OutOfMemoryException Caused when there‟s not enough memory to
allocate a new object

Prepared by Mrs. N. S. Gite 6


Chapter 4: Exception Handling & Multithreaded Programming

SecurityException Caused when an applet tries to perform an


action not allowed by the browser‟s security
setting
StackOverFlowException Caused when the system runs out of stack space
StringIndexOutOfBoundsException Caused when a program attempts to access a
non-existent character position in a string
ClassNotFoundException This Exception is raised when we try to access
a class whose definition is not found
InterruptedException It is thrown when a thread is waiting , sleeping ,
or doing some processing , and it is interrupted.
NoSuchFieldException It is thrown when a class does not contain the
field (or variable) specified
NoSuchMethodException It is thrown when accessing a method which is
not found.
RuntimeException This represents any exception which occurs
during runtime.

Java Exception Keywords


try
catch
throw
throws
finally

try & catch statement

Java uses a keyword try to preface a block of code that is likely to cause an error
condition and “throw” an exception. A catch block defined by the keyword catch
“catches” the exception “thrown” by the try block and handles it appropriately. The
catch block is added immediately after the try block.

SYNTAX:
try
{
Statement; //generates an exception
}
catch (Exception – type1 e)
{
Statement; //processes the exception
}

Prepared by Mrs. N. S. Gite 7


Chapter 4: Exception Handling & Multithreaded Programming

Problem without exception handling

Let's try to understand the problem if we don't use try-catch block.

class Testtrycatch1
{
public static void main(String args[])
{
int data=50/0; //may throw exception
[Link]("rest of the code...");
}
}

Output:

Exception in thread main [Link]:/ by zero


As displayed in the above example, rest of the code is not executed (in such case, rest of the
code... statement is not printed).

There can be 100 lines of code after exception. So all the code after exception will not be
executed.

Solution by exception handling

Let's see the solution of above problem by java try-catch block.

class Testtrycatch2
{
public static void main(String args[])
{
try
{
int data=50/0;
}catch(ArithmeticException e)

Prepared by Mrs. N. S. Gite 8


Chapter 4: Exception Handling & Multithreaded Programming

{
[Link](e);
}
[Link]("rest of the code...");
}
}

Output:

Exception in thread main [Link]:/ by zero


rest of the code...

Now, as displayed in the above example, rest of the code is executed i.e. rest of
the code... statement is printed.

Multiple catch Clauses

In some cases, more than one exception could be raised by a single piece of code. To
handle this type of situation, you can specify two or more catch clauses, each catching
a different type of exception. When an exception is thrown, each catch statement is
inspected in order, and the first one whose type matches that of the exception is
executed. After one catch statement executes, the others are bypassed, and execution
continues after the try/catch block.

SYNTAX:

try
{
Statement; //generates an exception
}
catch (Exception – type1 e)
{
Statement; //processes the exception
}
catch (Exception – type2 e)
{
Statement; //processes the exception
}
………………
catch (Exception – typeN e)
{
Statement; //processes the exception
}
……………….

Nested try statement

Prepared by Mrs. N. S. Gite 9


Chapter 4: Exception Handling & Multithreaded Programming

The try statement can be nested. That is, a try statement can be used inside the block
of another try. Each time when a try statement is entered, the context of that exception
is pushed on the stack. If an inner try statement does not have a catch handler for a
particular exception, the stack is unwound and the next try statement‟s catch handlers
are inspected for a match of exception. This continues until one of the catch
statements succeeds, or until all the nested try statements are exhausted. If no catch
statement matches, then the Java run-time system will handle the exception.

// Nested try blocks

import java. util. Scanner;


class NestTry
{
public static void main (String args [])
{
int x, z;
Scanner in = new Scanner([Link]);
[Link]("Enter number: ");
x = in. nextInt ();

try
{
z=82/x; //statement1
[Link] ("Division: "+z);

try
{
int a = 100 / (x-1); //statement2
short arr [] = {15};
arr [10] =25; //statement3
[Link]("Inner try end...");
}
catch (ArrayIndexOutOfBoundsException e) //1
{
[Link]("Array indexing wrong");
}
[Link]("Outer try end...");
}
catch (ArithmeticException e) //2
{
[Link]("Division by zero");
}
[Link]("Program end...");
}
}

Prepared by Mrs. N. S. Gite 10


Chapter 4: Exception Handling & Multithreaded Programming

Throws & Finally statement

The finally block

The finally is a block of code after try/catch block that will be executed after a
try/catch block has completed and before the code following the try/catch block. The
finally block will execute whether an exception is thrown or not. If an exception is
thrown, the finally block will execute even if no catch statement matches the
exception.

If any time a method is about to return to the caller from inside a try/catch block, via
an uncaught exception or an explicit return statement, the finally clause is also
executed just before the method returns. This can be useful for closing file handles
and freeing up any other resources that might have been allocated at the beginning of
a method. The finally clause is optional. But, each try statement requires at least one
catch or a finally clause. The try-catch-finally of try-finally construct can be created
as,
try
{
.......
}
catch (....) //multiple catch are allowed
{ ....... }
finally
{
.......
}

or

try
{
.......
}
finally
{
.......
}

The throws clause

If a method is capable of causing an exception that it does not handle, it must specify
this behaviour so that callers of the method can protect themselves against that
exception. We do this by including a throws clause in front of the method‟s
declaration.

Prepared by Mrs. N. S. Gite 11


Chapter 4: Exception Handling & Multithreaded Programming

A throws clause lists the types of exceptions that a method might throw. This is
necessary for all exceptions, except those of type Error or RuntimeException, or any
of their subclasses. All other exceptions that a method can throw must be declared in
the throws clause. If they are not, a compile-time error will occur. The general form
of writing a throws clause is,

data-type method-name(parameter-list) throws exception-list


{
// body of method
}

Here the exception-list is the list of exceptions that the method might throw separated
by comma.

For many classes and methods, it is necessary to throw the exception by the method
which is using it. For example, while using DataInputStream it is necessary to throw
the IOException as well as for many methods of multithreading it is necessary to
throw InterruptedException.

class ThrowsDemo
{
public static void main (String args []) throws ClassNotFoundException
{
//statements
}
}

Creating own exception, subclasses.

Java has defined a lot of Exception and Error classes for different conditions. But
many times it is required in some conditions that we want to create your own
exception types to handle situations specific to our applications.
This is quite easy to do. We just have to define a subclass of Exception (which is a
subclass of Throwable). Our subclasses don‟t need to actually implement anything.
It is their existence in the type system that allows us to use them as exceptions. The
Exception class does not define any methods of its own. It inherits all the methods
provided by class Throwable.
Thus, all exceptions, including those that we create, have the methods defined by
Throwable available to them. In order to create our own exception, we need to derive
our class from Exception.

The throw statement

Prepared by Mrs. N. S. Gite 12


Chapter 4: Exception Handling & Multithreaded Programming

If we want to throw the exceptions by our own, the throw statement can be used. That
is, it will force the Java run-time system to throw an exception. The general form of
throw statement is:

throw new Throwable-Instance;

Here, the Throwable-Instance must be an object of type Throwable or a subclass of


Throwable.
Primitive data types, such as int or char, as well as non-Throwable classes, such as
String and Object, cannot be used as exceptions.
There are two ways that we can obtain a Throwable object. First is using a parameter
into a catch clause and second is creating it with a new operator. The flow of
execution stops immediately after the throw statement.
So any subsequent statements are not executed. The nearest enclosing try block is
inspected to see if it has a catch statement that matches the type of the exception. If it
does find a match, control is transferred to that statement.
If not, then the next enclosing try statement is inspected, and so on. If no matching
catch is found, then the default exception handler terminates the program and prints
the stack trace.

// Creating our own exception.


class NegativeOutputException extends Exception
{
private int det;
NegativeOutputException(int a)
{
det = a;
}
public String toString()
{
return "NegativeOutputException["+det+"]";
}
}

class OwnException
{
public static void main (String args [])
{
int x = [Link](args[0]);
int y = [Link](args[1]);
int z;
try
{
z = x * y;
if(z<0) //statement1
throw new NegativeOutputException(z);
[Link]("Output: "+z);

Prepared by Mrs. N. S. Gite 13


Chapter 4: Exception Handling & Multithreaded Programming

}
catch (NegativeOutputException e)
{
[Link]("Caught: "+e);
}
}
}

Outputs:
java OwnException 4 8
Output: 32

java OwnException 4 -3
Caught: NegativeOutputException[-12]

java OwnException -4 -3
Output: 12

Example 2

class MyException extends Exception


{
MyException (String message)
{
super (message);
}
}

class TestMyException
{
public static void main (String args [])
{
int x = 5, y = 1000;
try
{
float z = (float) x / (float) y;
if (z < 0.01)
{
throw new MyException (“Number is too small”);
}
}
catch (MyException e)
{
[Link](“Caught my exception”);
[Link](e);
}
finally
{
[Link](“I am always here”);
}

Prepared by Mrs. N. S. Gite 14


Chapter 4: Exception Handling & Multithreaded Programming

}
}

Difference between throw and throws in Java

throw throws
Throw keyword is used to Java throws Java throws keyword is used to declare an
keyword is used to explicitly throw an exception.
exception.
Checked exception cannot be propagated using Checked exception can be propagated with
throw only. throws.
Throw is followed by an instance. Throws is followed by class.
Throw is used within the method. Throws is used with the method signature.
You cannot throw multiple exceptions. You can declare multiple exceptions e.g.
public void method()throws
IOException,SQLException.

4.2 Multithreaded Programming

Multithreading is one of the features of Java. It provides built-in support for multithreaded
programming. Basically, it is not supported by most of the programming languages.
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.
That is a thread is a light-weight process. We can call multithreading is a specialized form of
multitasking.
The thread is the smallest unit of dispatchable code. This means that a single program can
perform two or more tasks simultaneously. A thread is similar to a program that has single
flow of control.

Differentiate between multithreading and multitasking

Multithreading Multitasking
It is a programming concept In which a It is an operating system concept in which
program or a process is divided into two or multiple tasks are performed simultaneously.
more subprograms or threads that are executed
at the same time in parallel.
It supports execution of multiple parts of a It supports execution of multiple programs
single program simultaneously. simultaneously.
The processor has to switch between different The processor has to switch between different
parts or threads of a program. programs or processes.
It is highly efficient. It is less efficient in comparison to
multithreading.
A thread is the smallest unit in multithreading A program or process is the smallest unit in a
multitasking environment.

Prepared by Mrs. N. S. Gite 15


Chapter 4: Exception Handling & Multithreaded Programming

It helps in developing efficient programs It helps in developing efficient operating systems


It is cost-effective in case of context switching. It is expensive in case of context switching.

 Creating a Thread:

 By extending to thread class


 By implementing runnable Interface

Creating threads in Java is simple. Thread are implemented in the form of objects that
contain a method called run (). The run () method is the heart and soul of any thread.
It makes up the entire body of a thread and is the only method in which the thread‟s
behaviour can be implemented. A typical run () would appear as follows:

public void run ()


{
…………….
(statements for implementing threads)
…………….
}

The run () method should be invoked by an object of the concerned thread. This can
be achieved by creating the thread and initiating it with the help of another thread
method called start ().

A new thread can be created in two ways:

1. By creating a thread class: Define a class that extends Thread class and override its run
() method with code required by the thread.
2. By converting a class to a thread: Define a class that implements Runnable interface.
The Runnable interface has only one method, run (), that is to be defined in the method
with code to be executed by the thread.
Extending the Thread class

1. Declare the class as extending Thread class.


2. Implement the run () method that is responsible for executing the sequence of code that
the thread will execute.
3. Create a thread object and call the start () method to initiate the thread execution.

Starting New Thread


To actually create and run an instance of our thread class, we must write the following:

MyThread aThread = new MyThread ();


[Link] ();

Prepared by Mrs. N. S. Gite 16


Chapter 4: Exception Handling & Multithreaded Programming

Implementing the Runnable class

1. Declare the class as implementing Runnable class.


2. Implement the run () method.
3. Create a thread by defining an object that is instantiated from this “runnable” class as the
target of the thread.
4. Call the thread‟s start () to run the thread.

Starting New Thread

To actually create and run an instance of our thread class, we must write the following:

MyThread aThread = new MyThread ();


Thread tObject = new Thread (aThread);
[Link] ();

Life cycle of thread:

There are many threads in which a thread can enter during its lifetime. These are:
1. Newborn state
2. Runnable state
3. Running state
4. Blocked state
5. Dead state

A thread is always in one of these five states. It can be shifted from one state to
another via variety of ways as shown in figure.

Prepared by Mrs. N. S. Gite 17


Chapter 4: Exception Handling & Multithreaded Programming

Newborn state

After creation of the thread object, the thread is born which is called as new-born
thread. This thread is not scheduled for running. We can either start this state to make
it runnable using start () method or kill the thread using stop () method. Only these
two operations can be performed on this state of the thread. If we attempt to perform
any other operation, the exception will be thrown.

Runnable state

When the thread is ready for execution and is waiting for availability of the processor,
it is said to be in runnable state. The thread has joined the queue of threads that are
waiting for execution. If all the threads have equal priority, then they are given time
slots for execution in round robin fashion i.e. on first come first serve basis.
The thread that relinquishes control joins the queue at the end and again waits for its
execution. This process of assigning time to threads is known as time slicing. If we
want a thread to relinquish control to another thread of equal priority, a yield ()
method can be used.

Running state

When the processor has given time to the thread for its execution then the thread is
said to be in running state. The thread runs until it relinquishes control to its own or it
is pre-empted by a higher priority thread. A running thread may relinquish its control
in any one of the following situations:
1. The thread has been suspended using suspend () method. This can be revived by
using resume () method. This is useful when we want to suspend a thread for some
time rather than killing it.
2. We can put a thread to sleep using sleep (time) method where „time‟ is the time
value given in milliseconds. Means, the thread is out of queue during this time period.
3. A thread can wait until some event occurs using wait () method. This thread can be
scheduled to run again using notify () method.

Blocked state

When a thread is prevented from entering into the runnable state and subsequently in
running state it is said to be blocked. This happens when the thread is suspended,
sleeping or waiting in order to satisfy certain requirements. A blocked thread is
considered “not runnable” but not dead and therefore fully qualified to run again.

Dead state
A running thread ends its life when it has completed its execution of run () method. It
is a natural death. However, we can kill it by sending the stop message to it at any
state thus causing a premature death to it. A thread can be killed as soon as it is born
or while it is running or even when it is in blocked state.

Prepared by Mrs. N. S. Gite 18


Chapter 4: Exception Handling & Multithreaded Programming

 Thread exceptions

Whenever we use sleep () method it should be enclosed in a try block followed by a


catch block. This is necessary because the sleep () method throws an exception,
which should be caught. If we fail to catch the exception, program will not compile.
Java run system will throw IllegalThreadStateException whenever we attempt to
invoke a method that a thread cannot handle in the given state.

For example, a sleeping thread cannot deal with the resume () method because a
sleeping thread cannot receive any instructions. The same is true with suspend ()
method when it is used on a blocked thread.
Whenever we call a thread method that is likely to throw an exception, we have to
supply an appropriate exception handler to catch it. The catch statement may take one
of the following forms:

catch (ThreadDeath e)
{
………….. //Killed Thread
…………..
}
catch (InterruptedException e)
{
…………………… //Cannot handle it in the current state
}
catch (IllegalArgumentException e)
{
……………………. //Illegal method argument
}
catch (Exception e)
{
………………………. //Any other
}

 Thread priority & methods

Thread priorities are used by the thread scheduler to decide when each thread should
be allowed to run.
In theory, over a given period of time, higher-priority threads get more CPU time than
lower-priority threads.
In practice, the amount of CPU time that a thread gets often depends on several
factors besides its priority. (For example, how an operating system implements
multitasking can affect the relative availability of CPU time.) A higher-priority thread
can also preempt a lower-priority one.

Prepared by Mrs. N. S. Gite 19


Chapter 4: Exception Handling & Multithreaded Programming

For instance, when a lower-priority thread is running and a higher-priority thread


resumes (from sleeping or waiting on I/O, for example), it will preempt the lower-
priority thread.
In theory, threads of equal priority should get equal access to the CPU. But you need
to be careful.
Remember, Java is designed to work in a wide range of environments. Some of those
environments implement multitasking fundamentally differently than others.
For safety, threads that share the same priority should yield control once in a while.
This ensures that all threads have a chance to run under a nonpreemptive operating
system.
In practice, even in nonpreemptive environments, most threads still get a chance to
run, because most threads inevitably encounter some blocking situation, such as
waiting for I/O. When this happens, the blocked thread is suspended and other threads
can run. But, if you want smooth multithreaded execution, you are better off not
relying on this. Also, some types of tasks are CPU-intensive. Such threads dominate
the CPU. For these types of threads, you want to yield control occasionally so that
other threads can run.

To set a thread’s priority, use the setPriority( ) method, which is a member of


Thread.
This is its general form:

final void setPriority(int level)

Here, level specifies the new priority setting for the calling thread. The value of level
must be within the range MIN_PRIORITY and MAX_PRIORITY.
Currently, these values are 1 and 10, respectively.

To return a thread to default priority, specify NORM_PRIORITY, which is


currently 5.
These priorities are defined as static final variables within Thread.
You can obtain the current priority setting by calling the getPriority( ) method of
Thread, shown here:

final int getPriority()

Implementations of Java may have radically different behavior when it comes to


scheduling.
Most of the inconsistencies arise when you have threads that are relying on
preemptive behavior, instead of cooperatively giving up CPU time. The safest way to
obtain predictable, cross-platform behavior with Java is to use threads that voluntarily
give up control of the CPU.

Synchronization

Prepared by Mrs. N. S. Gite 20


Chapter 4: Exception Handling & Multithreaded Programming

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.
Key to synchronization is the concept of the monitor (also called a semaphore). A
monitor is an object that is used as a mutually exclusive lock, or mutex. 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 reenter the same monitor if
it so desires.

You can synchronize your code in either of two ways.

1. Using synchronized Method


2. Using synchronized Object

Using Synchronized Methods

Synchronization is easy in Java, because all objects have their own implicit monitor
associated with them. To enter an object‟s monitor, just call a method that has been
modified with the synchronized keyword. While a thread is inside a synchronized
method, all other threads that try to call it (or any other synchronized method) on the
same instance have to wait. To exit the monitor and relinquish control of the object to
the next waiting thread, the owner of the monitor simply returns from the
synchronized method.

// This program is not synchronized.


class Callme {
void call(String msg) {
[Link]("[" + msg);
try {
[Link](1000);
} catch(InterruptedException e) {
[Link]("Interrupted");
}
[Link]("]");
}
}
class Caller implements Runnable {
String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s) {
target = targ;
msg = s;
t = new Thread(this);

Prepared by Mrs. N. S. Gite 21


Chapter 4: Exception Handling & Multithreaded Programming

[Link]();
}
public void run() {
[Link](msg);
}
}
class Synch {
public static void main(String args[]) {
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try {
[Link]();
[Link]();
[Link]();
} catch(InterruptedException e) {
[Link]("Interrupted");
}
}
}

Here is the output produced by this program:

Hello[Synchronized[World]
]
]

As you can see, by calling sleep( ), the call( ) method allows execution to switch to
another thread. This results in the mixed-up output of the three message strings. In
this program, nothing exists to stop all three threads from calling the same method, on
the same object, at the same time. This is known as a race condition, because the three
threads are racing each other to complete the method.

To fix the preceding program, you must serialize access to call( ). That is, you must
restrict its access to only one thread at a time. To do this, you simply need to precede
call( )‟s definition with the keyword synchronized, as shown here:

class Callme
{
synchronized void call(String msg)
{
...
}

Prepared by Mrs. N. S. Gite 22


Chapter 4: Exception Handling & Multithreaded Programming

This prevents other threads from entering call( ) while another thread is using it. After
synchronized has been added to call( ), the output of the program is as follows:

[Hello]
[Synchronized]
[World]

The synchronized Object

While creating synchronized methods within classes that you create is an easy and effective
means of achieving synchronization, it will not work in all cases.

Imagine that you want to synchronize access to objects of a class that was not designed for
multithreaded access. That is, the class does not use synchronized methods. Further, this
class was not created by you, but by a third party, and you do not have access to the source
code. Thus, you can‟t add synchronized to the appropriate methods within the class. How can
access to an object of this class be synchronized? Fortunately, the solution to this problem is
quite easy: You simply put calls to the methods defined by this class inside a synchronized
block.

This is the general form of the synchronized statement:

synchronized(object) {
// statements to be synchronized
}

Here, object is a reference to the object being synchronized. A synchronized block ensures
that a call to a method that is a member of object occurs only after the current thread has
successfully entered object‟s monitor.

// This program uses a synchronized block.

class Callme
{
void call(String msg)
{
[Link]("[" + msg);
try
{
[Link](1000);
} catch (InterruptedException e)
{
[Link]("Interrupted");
}
[Link]("]");
}
}
class Caller implements Runnable
{

Prepared by Mrs. N. S. Gite 23


Chapter 4: Exception Handling & Multithreaded Programming

String msg;
Callme target;
Thread t;
public Caller(Callme targ, String s)
{
target = targ;
msg = s;
t = new Thread(this);
[Link]();
}

// synchronize calls to call()

public void run()


{
synchronized(target)
{
// synchronized block
[Link](msg);
}
}
}
class Synch1
{
public static void main(String args[])
{
Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello");
Caller ob2 = new Caller(target, "Synchronized");
Caller ob3 = new Caller(target, "World");
// wait for threads to end
try {
[Link]();
[Link]();
[Link]();
} catch(InterruptedException e)
{
[Link]("Interrupted");
}
}
}

Interthread Communication

Threads also provide a secondary benefit: they do away with polling. Polling is usually
implemented by a loop that is used to check some condition repeatedly. Once the condition is
true, appropriate action is taken. This wastes CPU time.

For example, consider the classic queuing problem, where one thread is producing some
data and another is consuming it. To make the problem more interesting, suppose that the

Prepared by Mrs. N. S. Gite 24


Chapter 4: Exception Handling & Multithreaded Programming

producer has to wait until the consumer is finished before it generates more data. In a polling
system, the consumer would waste many CPU cycles while it waited for the producer to
produce. Once the producer was finished, it would start polling, wasting more CPU cycles
waiting for the consumer to finish, and so on. Clearly, this situation is undesirable.

To avoid polling, Java includes an elegant interprocess communication mechanism via


the wait( ), notify( ), and notifyAll( ) methods. These methods are implemented as final
methods in Object, so all classes have them. All three methods can be called only from
within a synchronized context. Although conceptually advanced from a computer science
perspective, the rules for using these methods are actually quite simple:

• wait( ) tells the calling thread to give up the monitor and go to sleep until some other
thread enters the same monitor and calls notify( ).
• notify( ) wakes up a thread that called wait( ) on the same object.
• notifyAll( ) wakes up all the threads that called wait( ) on the same object. One of the
threads will be granted access.

These methods are declared within Object, as shown here:


final void wait( ) throws InterruptedException
final void notify( )
final void notifyAll( )
class Customer
{
int amount=0;
int flag=0;
public synchronized int withdraw(int amount)
{
[Link]([Link]().getName()+" is going to withdraw");

if(flag==0)
{
try
{
[Link]("waiting....");
wait();
}catch(Exception e){}
}
[Link]-=amount;
[Link]("withdraw completed");
return amount;
}
public synchronized void deposit(int amount)
{
[Link]([Link]().getName()+" is going to deposit");
[Link]+=amount;
[Link]("deposit completed");
notifyAll();
flag=1;
}
}

Prepared by Mrs. N. S. Gite 25


Chapter 4: Exception Handling & Multithreaded Programming

public class SyncThreadDemo


{
public static void main(String[] args)
{
final Customer c = new Customer();

Thread t1 = new Thread()


{
public void run(){
[Link](5000);
[Link]("After withdraw amount is "+[Link]);
}
};

Thread t2 = new Thread()


{
public void run(){
[Link](9000);
[Link]("After deposit amount is "+[Link]);
}
};
[Link]("abc");
[Link]("xyz");
[Link]();
[Link]();
}
}

Prepared by Mrs. N. S. Gite 26

You might also like