Java Chapter 3 Notes
Java Chapter 3 Notes
Java provides built-in support for multithreaded programming concept. A multithreaded program
contains two or more parts that can run concurrently. Each part of a program is called a thread, and each
thread defines a separate path of execution. Thus, multithreading is a form of multitasking. For example,
a subprogram displaying animation while another is building an animation next to be displayed. It is also
similar to dividing a task into subtasks and assigning them differently for execution independently and
simultaneously.
Multitasking:
* Process based: A process is a program that is executing. Thus, a process-based multitasking is the
feature that allows the computer to run two or more programs concurrently. For example, process-based
multitasking enables to run Java compiler at the same time you can use the text editor. In the process
based multitasking, a program is a smallest unit of code that can be dispatched by the scheduler. Process
is a heavyweight task that requires their own address spaces. Interprocess communication is expensive
and limited. Context switching from one process to another process is costly. Java programs make the use
of process-based multitasking environment, but the process-based multitasking is not under the control
of Java.
* Thread based: In a thread based multitasking environment, the thread is the smallest unit of
dispatchable code. That means a single program can perform two or more tasks simultaneously. For an
instance, a text editor can format text at the same time that is printing, as long as the two separate threads
are performing these two actions. Thus, the process-based multitasking deals with "big picture", and the
thread based multitasking handles the details. Multitasking thread requires fewer overheads than
multitasking process. The threads are lightweight processes. They share the same address space and
cooperatively share the same heavyweight process. Inter-thread communication is inexpensive, and
context switching from one thread to another thread is low cost. However, the multi-threading is
multitasking in Java.
Thread is very similar to a program that has a single flow of control. It has a beginning, a body, and an end,
and it executes commands sequentially.
Multithreading enables us to write very efficient programs that make maximum use of the CPU because
idle time can be kept to a minimum. This is especially important for the interactive, networked
environment in which Java operates, because idle time is common.
The Java support for multithreading is a unique property of Java. That means, Java enables the use of
multiple flows of control in program development. Each flow of control may be considered as a separate
tiny program or module known as a thread that runs in parallel |
Advantages of multithreading
* Speed of program is improved because the program is divided into threads and threads are executed
concurrently.
* In general, a thread can be created by instantiating an object of type Thread. Java defines two ways in
which this can be accomplished:
i. Implement runnable interface: First define a class that implements the Runnable interface. The
Runnable interface contains only one method, run(). The run() method is defined in the method with the
code to be executed by the thread.
Threads are implemented in the form of objects that contain a method called run(). The run() method
makes up the entire body of the thread and is the only method in which the thread's behavior can be
implemented. A run() appears as follows:
// Statements for
// implementing threads
The run() method is invoked by an object of the concerned thread. This can be done like first create a
thread and then initiate that thread by another thread method called start().
ii. Extend the thread class itself: Define a class that extends the Thread class and override its run() method.
The approach to be used can be decided according to the requirement like for what purpose the classes
are created. If it requires to extend another class, then regardless but to implement the Runnable
interface, since Java classes cannot have two superclasses.
Threads are implemented in form of objects that contain a method called run().
In this, to create a thread is to create a new class that extends Thread and then to create an instance of
that class.
Extending the Thread class includes the following steps:
* Declare the class extending the Thread class. The Thread class can be extended as follows:
// ...
* Implement the run() method that is responsible for executing the sequence of code that the thread will
execute. The extending class must override the run() method, which is the entry point of the new thread.
The run() method is inherited by the class MyFirstThread. Now override this method in order to implement
the code to be executed by the new thread MyFirstThread. The implementation of run() will be like:
// ...
// Thread code
// ...
When a new thread is started with start(), Java calls the thread's run() method, so it is the run() method
where all the action takes place.
* Create a thread object and call the start() method to initiate the thread execution. The following
statement creates a new thread.
ii. T.start();
statement calls the start() method, causing the thread to move into the runnable state. Then, the Java
runtime will schedule the thread to run by invoking its run() method. Now the thread is said to be in the
running state.
* The easiest way to create a thread is to create a class that implements the Runnable interface. Runnable
abstracts a unit of executable code. Threads can be created by implementing the Runnable interface. The
Runnable interface declares the run() method that is required for implementing threads in a program.
Follow the given steps:
* Create a thread by defining an object that is instantiated from this "runnable" class as the target of the
thread.
* The run() can call other methods, use other classes and declare variables, just like the main thread class.
The only difference is that run() establishes the entry point for another, concurrent thread of execution
within your program. The thread will end when run() returns.
Stopping a thread
AThread.stop();
* The above statement causes the thread to move to the dead state.
* A thread will also move to the dead state automatically when it reaches the end of its run() method.
* The stop() method can be used when the premature death of a thread is required.
* A thread can be temporarily suspended or blocked from entering into the runnable and subsequently
running state by using either of the following thread methods.
ii. The thread is blocked until further order for execution of thread using suspend().
iii. The thread is blocked until a certain condition occurs by using wait().
* Above methods cause the thread to go into a blocked or not runnable state.
* Following are the methods with which the thread will return to the runnable state:
* The thread can enter into many states during its life time. The five types of states are:
i. Newborn state
v. Dead state.
Newborn state
* When a thread object is created, the thread is born, and called as thread is in the Newborn state. In the
Newborn state, the thread is not yet scheduled for running.
Runnable state
* The runnable state of a thread means that the thread is ready for execution and is waiting for the
availability of the processor. The threads which are ready for execution are placed in a queue. So the
runnable state joins the queue of the threads that are waiting for execution.
* If all threads have the same priority, then they are given a time slice for execution in a round-robin
fashion, first-come-first-serve manner. The thread after completing its time slice joins the end of the
queue again, waits for (CPU to) its turn for execution. And this process of assigning time to threads is
known as time slicing.
* To release the control of a thread to another thread of equal priority before its turn comes, the yield()
method can be used. The following Fig. 4.1.4 shows relinquishing control using the yield() method.
Running state
* The running state means that the processor has given its time to the thread for its execution. The thread
runs until it releases control on its own or it is preempted by a higher-priority thread. A running thread
can relinquish its control in any one of the following situations:
* It is suspended using the suspend() method, which can be useful when you want to suspend a thread
for some time but do not want to kill
* It can be made to sleep. The thread can be made to sleep for a specified time period using the sleep(time)
method, where time is in milliseconds.
In this period, the queue is out of the ready queue. As soon as the time period is over, the thread is re-
entered in the runnable state
* A thread is waiting until some event occurs, and the wait() method is used to wait for a condition. Using
the notify() method, the thread can be scheduled to run
Blocked state
It is prevented from entering into the runnable state and subsequently the running state; then it is said to
be a blocked
Thread Priority
* Priority decides the execution time of a thread, meaning at what time the thread is to be executed. A
thread is assigned a priority, which affects the order in which it is scheduled for execution or running.
* The Java scheduler gives equal treatment to equal-priority threads. Hence, equal-priority threads may
share the processor on a first-come-first-serve basis.
* Java assigns to each thread a priority that determines how that thread should be treated with respect
to others. Threads are used by the thread scheduler to decide when each thread should be allowed to run.
Higher-priority threads get more CPU time than lower-priority threads. Threads of equal priority get equal
access to the CPU. The thread priority is used to decide when to switch from one running thread to the
next; this is known as a context switch. Following are the rules that determine when a context switch
takes place:
i. A thread can willingly relinquish control: Here, first all other threads are checked, and then the thread
with the highest priority which is ready to run is given the CPU.
ii. A thread can be preempted by a higher-priority thread: Here, a lower-priority thread is simply blocked
or preempted without the concern of what is doing by a lower-priority thread, and then the higher-priority
thread runs. This is called preemptive multitasking.
setPriority()
* Thread priorities are integers that specify the relative priority. The thread priority can be assigned by
using the following method: setPriority().
ThreadName.setPriority(int Number);
getPriority()
MIN_PRIORITY = 1
NORM_PRIORITY = 6
MAX_PRIORITY = 10
* Whenever a higher-priority thread comes, the currently running thread will be preempted by the
incoming thread. And thus, it forces the current running thread to move to the runnable state.
Deadlock
* When two threads have a circular dependency on a pair of synchronized objects, then there is a
deadlock. When two or more threads are waiting to gain control of a resource. Due to some reasons, the
condition on which the waiting threads rely on to gain control does not happen. The result is called a
deadlock.
For example, suppose thread A must access Method1 before it can release Method2, but thread B cannot
release Method1 until it gets hold of Method2. Because these are mutually exclusive conditions, a
deadlock occurs.
i. In general, it occurs only rarely, when two threads' time-slice in just the right way.
ii. It may involve more than two threads and two synchronized objects. (That is, deadlock can occur
through a more convoluted sequence of events than just described).
Synchronization
enforced. Threads use their own data and methods which is provided inside their run() method. But when
they try to use data and methods outside themselves, it will create a serious problem. When two or more
threads want to access a shared resource, there is a requirement that the shared resource must be used
by only one thread at a time. The synchronization process is used to achieve this.
* For example: One thread trying to read records from a file while another thread is still writing to the
same file. In Java, this problem can be overcome by using a technique known as synchronization. The
keyword synchronized is used.
* When a method is declared as synchronized, Java creates a monitor (semaphore) and hands it over to
the thread that calls the method for the first time. 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. As long as the thread holds the monitor, no other thread can
enter the synchronized section of code. The monitor is similar to a key, and the thread that holds the key
can only open the lock. These other threads are said to be waiting for the monitor.
Syntax:
* Errors are wrongs or mistakes that can make a program go wrong. Errors may be logical or may be
typing mistakes. An error may produce an erroneous or incorrect output or may terminate the execution
of the program abruptly or even may cause the system to crash. So, it is important to detect and manage
all error conditions in the program so that the program will not terminate or crash during execution.
* An exception is an abnormal condition that arises in a code sequence at runtime. That is, an exception
is an run-time error.
Types of Errors
* Compile-time errors
* Run-time errors
1. Compile-time errors
* Java compilers detect all syntax errors and display them. So, these errors are known as compile-time
errors. When the compiler displays errors, or suppose a program contains an error, the compiler does not
create the .class file. So, it is necessary to fix all the errors before successful compilation and execution of
the program.
* Missing semicolon.
2. Run-time error
After successfully compiling a program, the .class file is created but may not run properly. Programs may
produce wrong results due to wrong logic or may terminate due to errors such as stack overflow.
* Using a null object reference as a legitimate object reference to access a method or a variable.
When such an error occurs, Java generates an error message and aborts the program.
Exception
* An exception is a condition that is caused by a run-time error in a program. When the Java interpreter
caught an error such as division by zero, the interpreter creates an exception object and throws it to
inform that an error has occurred.
* A Java exception is nothing but an object which provides the information of an exceptional condition
that occurred in the program. When an exceptional condition occurs, an object which represents the
exception is created. The object is then thrown in the method that caused the error, and this method can
handle the exception itself or pass it on. Exceptions can be generated by the Java run-time system or
manually by the code. Exceptions generated by Java are related to the fundamental errors that violate the
Java language constraints.
* The exception-handling mechanism actually provides a means to detect and report an "exceptional
circumstance" so that corrective action can be taken. The exception-handling mechanism suggests the
incorporation of separate error-handling code that performs the following task:
* If an exception is created and thrown, but the exception object is not caught and handled properly,
the Java interpreter will display an error message, and sometimes it will terminate the program. If the
requirement is that the program should continue with the execution of the remaining code, then try to
catch the exception object thrown by the error condition and then display an appropriate error message
for taking corrective actions. This is known as exception handling.
* Java exception handling is managed by five keywords: try, catch, throw, throws, and finally.
* try: The program statements that are to be monitored for exceptions are contained within the try block.
If an exception occurs within the try block, it is thrown.
try
// ...
* catch: Your code can catch this exception using catch and handle it in some rational manner.
try
// ...
catch (...)
// ...
* throw: System-generated exceptions are automatically thrown by the Java run-time system. To
manually throw an exception, the throw keyword is used.
* throws: Any exception that is generated out of a method must be specified as such by a throws clause.
//body of a method
}
* finally: Any code that must be executed before a method returns is put in a finally block.
When a finally block is defined, it gives a guarantee to execute, regardless of whether or not an exception
is thrown.
* The try keyword is used for the block of codes that causes an error condition and throws an exception.
The catch keyword is used for the block of code that "catches" the exception "thrown" by the try block
and handles it. The catch block is added immediately after the try block.
try
catch (Exception-type1 e)
catch (Exception-type2 e)
// ...
finally
// statements to be executed
}
* The try block contains one or more statements that generate an exception. If the one statement
generates the exception, then the remaining statements are skipped, and execution jumps to the catch
block 1.
* The catch block can also contain one or more statements which are necessary to process the exception.
Every try statement must be followed by at least one catch statement; otherwise, a compilation error
occurs. The catch statement works the same as a method definition. The catch statement is passed a
single parameter, which is a reference to the exception object thrown by the try block. If the catch
parameter matches with the type of exception object, then the exception is caught, and the statements
in the catch block will be executed. Otherwise, the exception is not caught, and the default exception
handler will cause the execution to terminate.
* All exception types are subclasses of the built-in class Throwable. Thus, Throwable is at the top of the
exception class hierarchy. Two classes are derived from Throwable - Error and Exception.
* Error - The Error class is used for exceptional conditions that the user program should not try to catch.
RuntimeException is a subclass of Exception. Exceptions of this type are automatically defined for the
program that the user writes, such as division by zero.
* Exception - The Exception class defines exceptions that are not expected to be caught under normal
circumstances by the program. Exceptions of the Error type are used by the Java run-time system to
indicate errors having to do with the run-time environment, such as stack overflow.
* Any exception that is not caught by the program will ultimately be processed by the default handler.
The default handler displays a string describing the exception, prints a stack trace from the point at which
the exception occurred, and terminates the program.
Built-in Exception
The standard java.lang package defines several built-in exceptions. Most of these exceptions are the
subclasses of the standard type known as RuntimeException.
As the java.lang is implicitly available to all Java programs, the exceptions derived from RuntimeException
are automatically and easily available to the Java program.