Unit IV-Multithreading in java:
Multithreading
The process of executing multiple tasks (also called threads) simultaneously is called
multithreading. A multithreaded program contains two or more parts that can run concurrently.
Java Threads
A thread is the smallest unit of a program that can run independently.
It is a lightweight sub-process within a program that shares the same memory but executes tasks
separately.
Threads allow a program to operate more efficiently by doing multiple things at the same time.
Threads can be used to perform complicated tasks in the background without interrupting the main
program.
Creating a Thread:
There are two ways to create a thread.
1. It can be created by extending the Thread class:
Syntax:
public class Main extends Thread
{ public void run() {
System.out.println("This code is running in a thread");
}}
Example:
public class Main extends Thread
{ public void run() {
System.out.println("This code is running in a thread");
}
public static void main(String[] args)
{ Main ob = new Main();
ob.start();
System.out.println("This code is outside of the thread");
}
2. Another way to create a thread is to implement the Runnable interface:
Java runnable is an interface used to execute code on a concurrent thread. It is an interface which is
implemented by any class.The runnable interface has an undefined method run() with void as return type,
and it takes in no arguments.
Syntax:
public class Main implements Runnable
{ public void run() {
System.out.println("This code is running in a thread");
}}
Example :
public class Main implements Runnable
{ public void run() {
System.out.println("This code is running in a thread");
public static void main(String[] args)
{ Main obj = new Main();
Thread thread = new Thread(obj);
thread.start();
In Java, threads can be broadly classified into two main types:
1. User Threads
These are high-priority threads created by the user.
They run in the foreground and perform the main tasks of the program.
The JVM keeps running until all user threads have finished execution.
Example: Threads used for calculations, I/O operations, etc.
2.Daemon Threads in Java
Definition
A Daemon Thread is a background thread that provides services to user threads.
It runs in the background and does not prevent the JVM from exiting.
When all user threads finish, JVM automatically ends all daemon threads.
Thread Life cycle: A thread in Java goes through different states from creation to termination.
1. New.
2. Runnable.
3. Running.
4. Blocked(Non-Runnable).
5. Terminated/Dead.
New:A thread is in this state when it is created but not yet started using start() method.
Runnable:After calling start(), the thread becomes Runnable and is eligible to run.
Running:The thread is actively executing. The JVM thread scheduler selects it from the runnable pool.
Blocked (Non-Runnable):The thread is alive but not eligible to run. It may be waiting for a resource (like
I/O or a lock).
Terminated (Dead):A thread enters this state when it completes execution normally or abruptly (e.g.,
due to an exception).
Deadlock in Java:
Deadlock in Java is a situation where two or more threads are stuck forever because each thread is
waiting for a lock that another thread is holding.
To prevent deadlocks, we can use the synchronized keyword to make methods or blocks thread-safe which
means only one thread can have the lock of the synchronized method and use it, other threads have to wait
till the lock releases other one acquires the lock.
Thread synchronization:
Thread synchronization in Java is important for managing shared resources in a multithreaded environment.
It ensures that only one thread can access a shared resource at a time, which enhances the overall system
performance and prevents race conditions and data corruption.
Why is Thread Synchronization Important?
In a multithreaded environment, threads may compete for shared resources i.e. files, memory, etc. Without
synchronization, simultaneous access can lead
Race Conditions: Multiple Threads interchanging shared data at the same time and it results an
unpredictable output.
Data Corruption: Incomplete or corrupted data when multiple threads modify the same resource
simultaneously.
Thread synchronization can be achieved by
1. Synchronized Method
We can declare a method as synchronized using the synchronized keyword. This will make the code written
inside the method thread-safe so that no other thread will execute while the resource is shared.
synchronized returnType methodName(parameters) {
// code
2. Synchronized Block
If we declare a block as synchronized, only the code which is written inside that block is executed
sequentially not the complete code. This is used when we want sequential access to some part of code or to
synchronize some part of code.
Syntax
synchronized (object reference)
{
// Insert code here
}
3. Static Synchronization
In this, the synchronized method is declared as “static” which means the lock or monitor is applied on the
class not on the object so that only one thread will access the class at a time.
Syntax:
synchronized static returnType methodName(parameters) {
// code
}
Suspending and Resuming Threads in Java
Earlier versions of Java had methods like suspend() and resume(), but these are deprecated because they can
cause deadlocks.
Instead, we use safer techniques like wait/notify or using a flag variable.
Priorities in Threads
Priorities in Threads in Java is a concept where each thread has a priority.Every object has priority here
which is represented by numbers ranging from 1 to 10 and the constant defined can help to implement
which are mentioned below.
public final int getPriority(): This method returns the priority of the given thread.
public final void setPriority(int newPriority):This method changes the priority of thread to the value
newPriority.
Constant Description
public static int
Sets the default priority for the Thread. (Priority: 5)
NORM_PRIORITY
Sets the Minimum Priority for the Thread. (Priority:
public static int MIN_PRIORITY
1)
Sets the Maximum Priority for the Thread. (Priority:
public static int MAX_PRIORITY
10)
import java.lang.*;
class Thread1 extends Thread {
public void run()
{
System.out.println(Thread.currentThread().getName() + " is running with priority " +
Thread.currentThread().getPriority());
}
public static void main(String[] args)
{
// Creating random threads with the help of above class
Thread1 t1 = new Thread1();
Thread1 t2 = new Thread1();
Thread1 t3 = new Thread1();
// Display the priority of above threads using getPriority() method
System.out.println("t1 thread priority: " + t1.getPriority());
System.out.println("t2 thread priority: " + t2.getPriority());
System.out.println("t3 thread priority: " + t3.getPriority());
// Setting priorities of above threads by passing integer arguments
t1.setPriority(2);
t2.setPriority(5);
t3.setPriority(8);
// Error will be thrown in this case t3.setPriority(21);
// Last Execution as the Priority is low
System.out.println("t1 thread priority: " + t1.getPriority());
// Will be executed before t1 and after t3
System.out.println("t2 thread priority: " + t2.getPriority());
// First Execution as the Priority is High
System.out.println("t3 thread priority: " + t3.getPriority());
// Now Let us Demonstrate how it will work According to it's Priority
t1.start();
t2.start();
t3.start();
}
}
Producer-Consumer Solution using Threads in Java
In computing, the producer-consumer problem (also known as the bounded-buffer problem) is a classic
example of a multi-process synchronization problem. The problem describes two processes, the producer
and the consumer, which share a common, fixed-size buffer used as a queue.
The producer's job is to generate data, put it into the buffer, and start again.
At the same time, the consumer is consuming the data (i.e. removing it from the buffer), one piece at
a time.
Problem
To make sure that the producer won't try to add data into the buffer if it's full and that the consumer won't try
to remove data from an empty buffer.
Solution
The producer is to either go to sleep or discard data if the buffer is full. The next time the consumer removes
an item from the buffer, it notifies the producer, who starts to fill the buffer again. In the same way, the
consumer can go to sleep if it finds the buffer to be empty. The next time the producer puts data into the
buffer, it wakes up the sleeping consumer.
An inadequate solution could result in a deadlock where both processes are waiting to be awakened.
File handling, deals with processing input and producing output in programs. The java.io package
contains all necessary classes to perform these operations using streams.
Streams
Stream: A sequence of data. In Java, streams are composed of bytes.
Standard Streams: Java automatically creates three streams:
1. System.out: Standard output stream.
2. System.in: Standard input stream.
3. System.err: Standard error stream.
OutputStream and InputStream
The explanation of OutputStream and InputStream classes are given below:
InputStream
Java application uses an input stream to read data from a source; it may be a file, an array, peripheral device
or socket.Let's understand the working of Java OutputStream and InputStream by the figure given below.
OutputStream
Java application uses an output stream to write data to a destination; it may be a file, an array,
peripheral device or socket.
1. Reader: This is the base class for all classes that read character streams.
Subclasses of Reader include:
o BufferedReader: Buffers input to improve efficiency.
o FileReader: Reads characters from a file.
o InputStreamReader: Bridges byte streams to character streams.
o StringReader: Reads characters from a String.
Common methods in Reader include:
oint read(): Reads a single character.
oint read(char[] cbuf, int off, int len): Reads characters into a portion of an array.
o void close(): Closes the stream and releases resources.
2. Writer: This is the base class for all classes that write character streams.
Subclasses of Writer include:
o BufferedWriter: Buffers output to improve efficiency.
o FileWriter: Writes characters to a file.
o OutputStreamWriter: Bridges character streams to byte streams.
o StringWriter: Writes characters to a StringBuffer.
Writer methods include:
o void write(int c): Writes a single character.
o void write(char[] cbuf, int off, int len): Writes characters from a portion of an array.
o void close(): Closes the stream and releases resources.
InputStream
InputStream: The abstract base class for all byte input streams. It provides the standard
methods to read bytes from a source.
Subclasses:
o FileInputStream: Reads bytes from a file.
o BufferedInputStream: Buffers the input to enhance reading efficiency.
o ByteArrayInputStream: Reads bytes from a byte array.
o DataInputStream: Reads primitive data types and strings in a machine-independent
way.
Common methods:
int read(): Reads the next byte of data from the input stream.
int read(byte[] b): Reads bytes from the input stream into the buffer array b.
void close(): Closes the input stream and releases any system resources.
OutputStream
OutputStream: The abstract base class for all byte output streams. It provides the standard
methods to write bytes to a destination.
Subclasses:
o FileOutputStream: Writes bytes to a file.
o BufferedOutputStream: Buffers the output to enhance writing efficiency.
o ByteArrayOutputStream: Writes bytes to a byte array.
o DataOutputStream: Writes primitive data types and strings in a machine-independent
way.
Common methods:
void write(int b): Writes the specified byte to the output stream.
void write(byte[] b): Writes bytes from the specified byte array to the output stream.
void close(): Closes the output stream and releases any system resources.
Example: import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileCopy {
public static void main(String args[]) throws IOException {
FileInputStream fin = new FileInputStream("sample.txt");
FileOutputStream fout = new FileOutputStream("output.txt");
int ch;
while ((ch = fin.read()) != -1) {
fout.write(ch);
}
fin.close();
fout.close();
System.out.println("File copied successfully.");
}
}
Output:
File copied successfully.
The DataOutputStream Class
The DataOutputStream class in Java is a subclass of FilterOutputStream. It allows an application to write
primitive data types (int, float, double, char, boolean, etc.) to an output stream in a machine-independent
way. This means the data can be read back correctly by DataInputStream regardless of the machine platform.
Key Methods of DataOutputStream:
• writeInt(int v) – Writes an int to the output stream.
• writeDouble(double v) – Writes a double value.
• writeChar(int v) – Writes a char value.
• writeBoolean(boolean v) – Writes a boolean value.
The DataInputStream Class
The DataInputStream class is a subclass of FilterInputStream. It allows an application to read primitive data
types (int, float, double, char, boolean, etc.) from an input stream in a machine-independent way.
Key Methods of DataInputStream:
• readInt() – Reads an int from the input stream.
• readDouble() – Reads a double value.
• readChar() – Reads a char value.
• readBoolean() – Reads a boolean value.
ObjectInputStream
3. ObjectInputStream: A specialized input stream that can read objects from an input stream. It
is capable of deserializing objects that were previously serialized and written to a stream.
• Common methods:
• Object readObject(): Reads an object from the input stream.
• int read(): Reads the next byte of data from the input stream.
• int read(byte[] b): Reads bytes from the input stream into the buffer array b.
• void close(): Closes the input stream and releases any system resources.
ObjectOutputStream
4. ObjectOutputStream: A specialized output stream that can write objects to an output stream. It is
capable of serializing objects and writing them to a stream.
• Common methods:
• void writeObject(Object obj): Writes the specified object to the output stream.
• void write(int b): Writes the specified byte to the output stream.
• void write(byte[] b): Writes bytes from the specified byte array to the output
stream.
• void close(): Closes the output stream and releases any system resources.
Random Access Files
Random access files allow you to read and write to any part of a file. This is done using the
RandomAccessFile class.
Java RandomAccessFile providing a non-sequential access to files. It behaves like a large array of bytes
stored in the file system. That means you don't need to start from 1st line and you can jump to anywhere
in the file. It's similar to array data structure, just like you can access any element in array by index you
can read any content from file by using file pointer. The real advantage is that once file is opened, it can be
read from or written to in a random manner just by using a record number or you can add to the end
since you will know how many records are in the file.
Access Modes:
r - Read only.
rw - Read and write.
rwd - Read and write, synchronously update file content.
Common methods:
int read(): Reads a byte of data from the file.
void write(int b): Writes a byte to the file.
void close(): Closes the random access file stream and releases any system resources.
Applet and its life cycle
A Java Applet is a Java program that runs inside a web browser. An Applet is
embedded in an HTML file using <applet> or <objects> tags. Applets are used to
make the website more dynamic and entertaining.Applet is a class in Java.
Applet life cycle
The life cycle of the applet as shown in the below figure
There are five methods of an applet life cycle, and they are:
init() Method in Applet
The init() method is the first method that runs when an applet starts.
It is called only once by the browser when the applet is loaded.
Inside init(), we can:
Create objects needed for the applet
Set starting values
Load images or fonts
Set colors or layout
·
General
syntax is
public void init()
{
………………………..
………………………..
}
start(): The start() method contains the actual code of the applet and starts
the applet. It is invoked immediately after the init() method is invoked. Every
time the browser is loaded or refreshed, the start() method is invoked. It is
also invoked whenever the applet is maximized, restored, or moving from
one tab to another in the browser.
The general syntax is
public void start()
{
………………………..
………………………..
}
paint(): The paint() method belongs to the Graphics class in Java. It is used to
draw shapes like circle, square, trapezium, etc., in the applet. It is executed after
the start() method and when the browser or applet windows are resized.
The general syntax is
public void paint(Graphics g)
{
………………………..
………………………..
}
stop(): The stop() method stops the execution of the applet. The stop ()
method is invoked whenever the applet is stopped, minimized, or moving from
one tab to another in the browser, the stop() method is invoked. When we go
back to that page, the start() method is invoked again.
The general syntax is
public void stop()
{
………………………..
………………………..
}
destroy(): The destroy() method destroys the applet after its work is done. It
is invoked when the applet window is closed or when the tab containing the
webpage is closed. It removes the applet object from memory and is executed
only once. We cannot start the applet once it is destroyed.
The general syntax is
public void destroy()
{
………………………..
………………………..
}
Steps to Create an Applet
1. Import Applet and AWT packages
import java.applet.Applet;
import java.awt.Graphics;
2. Create a class that extends Applet.
Override the paint() method to display output on the screen.
The paint(Graphics g) method is used for drawing text, shapes, or images.
import java.applet.Applet;
import java.awt.Graphics;
/* <applet code="MyApplet.class" width=300 height=200> </applet> */
public class MyApplet extends Applet {
public void paint(Graphics g) {
g.drawString("Hello, Applet World!", 50, 100);
Steps to Execute an Applet
Save the file → MyApplet.java
Compile the file →javac MyApplet.java
Run the file ->appletviewer MyApplet.java
Attributes in <applet> Tag
The <applet> tag is used in HTML to embed applets.
Important attributes:
code → Name of the applet class (e.g., HelloApplet.class)
width → Width of applet display area
height → Height of applet display area
alt → Message to display if applet cannot run
align → Position (top, bottom, left, right, middle)
vspace / hspace → Vertical and horizontal spacing
Example:
<applet code="HelloApplet.class" width="300" height="200" alt="Applet not supported">
</applet>
Passing Parameters to Applets
Parameters can be passed using <param> tag inside <applet>.
getParameter("paramName") is used inside applet to retrieve .
import java.applet.Applet;
import java.awt.Graphics;
/* <applet code="ParamApplet.class" width=300 height=200>
<param name="user" value="MCA Student">
</applet> */
public class ParamApplet extends Applet {
String msg;
public void init() {
msg = getParameter("user");
if (msg == null) msg = "Guest";
public void paint(Graphics g) {
g.drawString("Hello, " + msg, 50, 100);
}
}
Working with Graphics in Applets
Use Graphics class methods inside paint(Graphics g) to draw text, shapes, and images.
Common Methods:
drawString(String msg, int x, int y) → Displays text
drawLine(int x1, int y1, int x2, int y2) → Draws a line
drawRect(int x, int y, int w, int h) → Rectangle (outline)
fillRect(int x, int y, int w, int h) → Filled rectangle
drawOval(int x, int y, int w, int h) → Circle/ellipse outline
fillOval(int x, int y, int w, int h) → Filled circle/ellipse
setColor(Color c) → Sets drawing color
Example:
import java.applet.Applet;
import java.awt.*;
/* <applet code="GraphicsApplet.class" width=300 height=200> </applet> */
public class GraphicsApplet extends Applet {
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawString("Graphics Demo", 50, 50);
g.drawLine(20, 60, 200, 60);
g.drawRect(20, 80, 100, 50);
g.fillOval(150, 80, 60, 60);
}
Types of Applets
Local Applet Remote Applet
Stored on the local Stored on a remote
machine (hard server.
disk).
Executed using a Executed using
file URL (file://). HTTP/HTTPS URL
(http:// or https://).
Can be run only by Can be accessed by any
users who have the user over the Internet.
file locally.
No hosting needed; Requires uploading to a
just run locally. web server.
Faster to load as Slower as files are
files are already downloaded from the
local. server.
Does not require Requires Internet
Internet connection. connectivity.