0% found this document useful (0 votes)
43 views212 pages

Java Fundamentals and Mutlithreading

Uploaded by

swastiksharma.hp
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)
43 views212 pages

Java Fundamentals and Mutlithreading

Uploaded by

swastiksharma.hp
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
You are on page 1/ 212

Module 1

Java Fundamentals and Multithreading

Java Fundamentals- Class, Packages and Interface, Multi


threading: thread life- cycle, thread creation, thread
priorities, thread scheduler, thread pool, thread group,
synchronization and Inter thread communication.
INTRODUCTION TO JAVA

https://www.youtube.com/watch?v=2TZMjmp6Vts
Java Design goal

The design goals of Java focus on creating a language that is


simple, efficient, secure, and portable, while supporting modern
software development needs.
Java Buzzwords/ Features
of Java Language
Simple
Java is a simple programming language.It removes some of the
complicated concepts such as:

● Java doesn’t support complex concepts like pointers,


operator overloading, so Java programs work as fast and its
required less development time.
● Java has added the concept of garbage collation to destroy
unnecessary objects automatically that free up memory.
● It provides user-friendly syntax which is based on C++
Object-oriented

● Java is purely an Object Oriented


Programming language i.e., all the code of
the Java language is written into the
classes and objects.
Distributed
● Java is a distributed language because of its ability
to share the data and programs over the LAN.
● Access remote objects.
Multi-threaded

● Java supports multi-threading programming, which allows us


to write programs that do multiple operations
simultaneously.
Secure
● Java is said to be more secure programming language because it does
not have pointers concept, java provides a feature "applet" which
can be embedded into a web application.
● The applet in java does not allow access to other parts of the
computer, which keeps away from harmful programs like viruses and
unauthorized access.
Portable
● Portability is one of the core features of java which enables the java
programs to run on any computer or operating system.

● For example, an applet developed using java runs on a wide variety of


CPUs, operating systems, and browsers connected to the Internet.
Robust
● Java is more robust because the java code can be executed on a
variety of environments, java has a strong memory management
mechanism (garbage collector), java is a strictly typed language, it has a
strong set of exception handling mechanism, and many more.
Architecture-neutral (or) Platform Independent
● Java has invented to archive "write once; run anywhere, any
time, forever". The java provides JVM (Java Virtual Machine) to to
archive architectural-neutral or platform-independent. The JVM allows
the java program created using one operating system can be executed
on any other operating system.
Interpreted
● Java enables the creation of cross-platform programs by compiling
into an intermediate representation called Java bytecode. The byte
code is interpreted to any machine code so that it runs on the
native machine.

High performance
● Java provides high performance with the help of features like
JVM, interpretation, and its simplicity.
Dynamic
● Java is said to be dynamic because the java byte code may be dynamically
updated on a running system and it has a dynamic memory allocation
and deallocation (objects and garbage collector).
Standalone applications

● Standalone applications are also known as desktop applications o


window-based applications.
These are traditional software that we need to install on every
machine.
Examples of standalone application are Media player, antivirus, etc.
AWT and Swing are used in Java for creating standalone application
Web Applictaion:

● An application that runs on the server side and creates


a dynamic page is called a web application. Currently,
Servlet,JSP, Struts, Spring, Hibernate, JSF, etc.
technologies are used for creating web applications in
Java.
Enterprise Application

An application that is distributed in nature, such as


banking applications, etc. is called enterprise
application.
It has advantages of the high-level security, load
balancing, and clustering. In Java, EJB is used for
creating enterprise applications.
Mobile Application

● An application which is created for mobile devices is


called a mobile application.
● Currently, Android and Java ME are used for creating
mobile applications
Java Virtual MAchine (JVM) & Byte Code

JVM is vital component of JRE which provides runtime environment to the


java application.
JVM accepts platform independent bytecode(.class file) generated by the
compiler (javac.exe)
JVM converts the bytecode into platform specific native machine code and
executes this code line by line.
JVM job is to load and execute functions.
Lets divide JVM is loading, verifying & executing whatever
class file generated from source code by java compiler is
loaded
How does jvm instance load and compile the file
NEED FOR OBJECT ORIENTED APPROACH
•CHALLENGES IN DEVELOPING A BUSINESS APPLICATION
Integration of Illusion of
modules /
Extensibility High level simplicity
applications of of
existing code flexibility

• If these challenges are not addressed it may lead to Software Crisis


• Features needed in the business application to meet these challenges:
Modularity Extendibility Reusability Interoperability
Security

• Challenges can be addressed using object oriented approach


35
OOP TERMINOLOGIES
Object Real world entities, which has two characteristics namely, state
(attributes) and behavior (method). It is an
active entity.
A Class is a "blueprint" for creating objects.
Class

Method object's data is accessed, modified, or processed

Hides all but the relevant data about an object so as to reduce


Abstraction complexity and increase efficiency. Focus on what the
object does instead of how it does

Encapsulation This wraps code and data into a single unit. implementation of
abstraction.

Inheritance Inheritance allows us to define a class that inherits all the methods and
properties from another class

Polymorphism means that different types respond to the same function


Polymorphism
Classes & Objects
Object-oriented Programming Is The Problem-solving
Approach And Used Where Computation Is Done By Using
Objects
Class

● In object-oriented programming, a class is a blueprint from which


individual objects are created (or, we can say a class is a data type of an
object type). In Java, everything is related to classes and objects. Each
class has its methods and attributes that can be accessed and
manipulated through the objects.
Object
● In object-oriented programming, an object is an entity that has two
characteristics (states and behavior). Some of the real-world objects are
book, mobile, table, computer, etc. An object is a variable of the type
class, it is a basic component of an object-oriented programming system.
A class has the methods and data members (attributes), these methods
and data members are accessed through an object. Thus, an object is an
instance of a class.
•Users of the retail application – Billing staff,
Admin, Retail outlet manager Who are the users
of the retail

•Each user needs to know some details and need application?

not know other details What are the things


each user must know
to perform their
activities ?

Billing staff Admin Retail Outlet Manager


(Billing of (Registration of (Registration of
customers ) customers) users)

ABSTRACTION : Process of identifying the essential details to be known and ignoring the
non-essential details from the perspective of the user of the system
ENCAPSULATION
How is a swipe machine
used for payment of bill in a
retail store?
Swipe machine in a retail store
– Used by billing staff to key the amount
– Used by admin to record payment

ENCAPSULATION : A mechanism of hiding the members from the external world.


Swipe machine has all the control to perform the operations.

41
INHERITANCE What are the two
different types of
customers you can see
in the retail
Customers are of two kinds application?

– Regular
– Privileged All customers have Customer Id, Name,
Telephone Number and Address
The regular customer in addition is given
discounts Privileged
All customers have some generic features. The Regular
The privileged customer gets a membership Customers Customers
different kinds of customers have all generic
card based on which gifts are given
features in addition to some specific features

INHERITANCE : Is a mechanism which allows to define generalized characteristics and behavior and also create
specialized ones. The specialized ones automatically tend to inherit all the properties of the generic ones

42
TYPES OF INHERITANCE

Grand
Father Animal
Father Bird Mammal
Father Wild Domestic
Son
Son Lion
Bat

Single Inheritance Multi-level Inheritance Multiple Inheritance Hierarchy Inheritance

43
POLYMORPHISM
What do you
observe in this
• Payment of bill - Two modes retail store
scenario?
– Cash (Calculation includes VAT)
Total Amount = Purchase amount +
VAT

– Credit card(Calculation includes processing charge and VAT)

Total Amount = Purchase amount +


VAT
+ Processing charge

The activity of paying the bill is the same. But the formula for calculation of bill
differs as per the mode of payment

POLYMORPHISM: Refers to the ability of an object/operation to


behave differently in different situations 44
OBJECT ORIENTED APPROACH – BENEFITS

• Leads to development of smaller but stable subsystems

• The subsystems are resilient to change


• Reduces the risk factor in building large systems as they are built
incrementally from subsystems which are stable
Java source file structure

We put a class in a source file


We put methods in a class
What happens when we create a program?
First, we create a plain text file using Visual Studio Code, write some code in it, and save
it as a HelloWorld.java file on our machine.
The file where we wrote source code and saved it in our machine is called a source file.
File with a .java extension is a java source file because it contains the source code for our
program, written in human-readable plain text format.

When we compile source files(in essence source code) using a compiler(in java it is
javac), the compiler generates a binary file and automatically saves it in our machine.
Single-line Comments
Single-line comments start with two forward slashes (//).

System.out.println("Hello World"); // This is a comment

Java Multi-line Comments


Multi-line comments start with /* and ends with */.

/* The code below will print the words Hello World

to the screen, and it is amazing */

System.out.println("Hello World");
Syntax of a Class Declaring a Java Method
class <class_name>
The syntax to declare a method is:
{
field; returnType methodName()
{
method;
// method body
} }
Basic programming constructs
Class Fundamentals
What is a Class in Java?

• A class is a group of objects which have common properties. It is a template or blueprint from which objects
are created. It is a logical entity.

What is Object?

• An object is a real-word entity that has state and behaviour.

Characteristics of an Object:

• State: It represents the data (value) of an object.

• Behavior: It represents the behavior (functionality) of an object such as deposit, withdraw, etc.

• Identity: An object's identity is typically implemented via a unique ID. The ID's value is not visible to the
external user; however, it is used internally by the JVM to identify each object uniquely.
Object Definitions:
• An object is a real-world entity.
• An object is a runtime entity.
• The object is an entity which has state and behavior.
• The object is an instance of a class.
Syntax of a Class
Example:
class <class_name> class Person
{
{ String name;
field; int age;

method; // Method to display person's information


public void displayInfo()
} {
System.out.println("Name: " + name + ", Age: " + age);
}
}
How to create object in java?
Using new Keyword:
ClassName object = new ClassName();
public class CreateObjectExample1 Output: Welcome to
{ javaTpoint
void show()
{
System.out.println("Welcome to javaTpoint");
}
public static void main(String[] args)
{
//creating an object using new keyword
CreateObjectExample1 obj = new CreateObjectExample1();
//invoking method using the object
obj.show();
}
}
Passing Parameters: Passing the values as parameters is called
parameter passing or argument passing.
public class Main
{
void myMethod(String fname)
{
System.out.println(fname + " Refsnes");
}

public static void main(String[] args)


{
Main obj=new Main();
obj.myMethod("Liam");
obj.myMethod("Jenny");
myMethod("Anja");
Passing Parameter as integer values and accessing the instance
variable.
public class MyClass
{
int myField;
public void MyClass1(int value)
{
myField = value;
System.out.println(myField);
}
public static void main(String[] args)
{
// Using the new keyword to create an instance of MyClass
MyClass myObject = new MyClass();
myObject.MyClass1(100);
// Accessing the instance variable of the object
System.out.println("Value of myField: " + myObject.myField);
}
}
Return Values
To return a value from method, can use a primitive data type (such as int, char, etc.) instead of void,

and use the return keyword inside the method:

public class Main


{
int myMethod(int x)
{
return 5 + x;
}

public static void main(String[] args)


{
Main object1=new Main();
int x=object1.myMethod(5);
System.out.println(“The return value =” +x));
}
}
public class Main public class Main
{ {
int myMethod(int x, int y) { int myMethod(int x, int y)
return x + y; {
} return x + y;
}
public static void main(String[] args)
{
public static void main(String[] args)
Main obj=new Main();
{
System.out.println(obj.myMethod(5, 3)); Main obj=new Main();
}
}
int z = obj.myMethod(5, 3);
System.out.println(z);
// Outputs 8 (5 + 3)
}
}
// Outputs 8 (5 + 3)
class Main public static void main(String[] args)
{
{ int num1 = 25;
int num2 = 15;
// create a method // create an object of Main

public int addNumbers(int a, int b) Main obj = new Main();

{ // calling method

int sum = a + b; int result = obj.addNumbers(num1, num2);

// return value System.out.println("Sum is: " + result);

return sum; }
}
Sum is:
40
}
class Main
{
// create a method
public int square(int num)
{
// return statement
return num * num;
}
public static void main(String[] args)
{
int result;
// call the method
// store returned value to result
Main object1=new Main();
result = object1.square(10);
System.out.println("Squared value of 10 is: " + result);
}
}
class Main
{
// method with no parameter
public void display1()
{
System.out.println("Method without parameter");
}
// method with single parameter
public void display2(int a)
{
System.out.println("Method with a single parameter: " +
a);
}
public static void main(String[] args)
{
// create an object of Main
Main obj = new Main();
// calling method with no parameter
obj.display1();
// calling method with the single parameter
obj.display2(24);
}
//Java Program to illustrate how to define a class and fields
//Defining a Student class.
class Student
{
//defining fields
int id=10;//field or data member or instance variable
String name="ADHYA";
//creating main method inside the Student class

public static void main(String args[])


{
//Creating an object or instance
Student s1=new Student();//creating an object of Student
//Printing values of the object
System.out.println(s1.id);//accessing member through reference
variable
System.out.println(s1.name);
}
}
Scanner class
In Java, Scanner is a class in java.util package used for obtaining the input of the
primitive types like int, double, etc. and strings.Using the Scanner class in Java is
the easiest way to read input in a Java program.

Java Scanner Input Types


Scanner class helps to take the standard input stream in Java. So, we need some
methods to extract data from the stream. Methods used for extracting data are
mentioned below:
Method Description

Used for reading Boolean value


nextBoolean()

nextByte() Used for reading Byte value

nextDouble() Used for reading Double value

nextFloat() Used for reading Float value

nextInt() Used for reading Int value

nextLine() Used for reading Line value

nextLong() Used for reading Long value

nextShort() Used for reading Short value


import java.util.Scanner;
public class scannerdemo
{ Enter the Name:
public static void main(String[] args) Adhya
{ Adhya
// TODO Auto-generated method stub Enter the gender
Scanner sc = new Scanner(System.in); F
// String input F
System.out.println("Enter the Name:"); Enter the age
String name = sc.nextLine(); 3
System.out.println(name); 3
Enter the mobile no
System.out.println("Enter the gender"); 123456789
char gender = sc.next().charAt(0); Mobile Number: 123456789
System.out.println(gender);

System.out.println("Enter the age");


int age = sc.nextInt();
System.out.println(age);

System.out.println("Enter the mobile no");


long mobileNo = sc.nextLong();
System.out.println("Mobile Number: " + mobileNo);
}
}
Java program by using 2 classes
// Java program to demonstrate reference
// variable in java

import java.io.*;
OUTPUT: Demo@214c265e
class Demo {
int x = 10; x = 10
int display() 0
{
System.out.println("x = " + x);
return 0;
}
}

class Main {
public static void main(String[] args)
{
Demo D1 = new Demo(); // point 1

System.out.println(D1); // point 2

System.out.println(D1.display()); // point 3
}
Java program by using 2 classes
// Java program to demonstrate reference
// variable in java

import java.io.*;
OUTPUT: Demo@214c265e
class Demo {
int x = 10; x = 10
int display() 0
{
System.out.println("x = " + x);
return 0;
}
}

class Main {
public static void main(String[] args)
{
Demo D1 = new Demo(); // point 1

System.out.println(D1); // point 2

System.out.println(D1.display()); // point 3
}
class Circle
{ By using two classes:
double radius;

void calculateArea() //method 1 definition


{
double area = 3.14*radius*radius;
System.out.println("Area of circle: " +area);
}
void calculateCircumference() //method 2 definition
{
double circum = 2*3.14*radius;
System.out.println("Circumference of circle: " +circum);
}
}
class Main
{
public static void main(String args[])
{
Circle c = new Circle(); //creating object of class circle
c.radius = 5;
c.calculateArea(); //invokes calculateArea() with object c
c.calculateCircumference(); //invokes
calculateCircumference() with object c
}
}
Object reference

When you pass an object to a method, what is actually passed is


the reference to the object, not a copy of the object. This means
that changes made to the object within the method will affect the
original object.
Object reference: public static void main(String args[]) {
public class ComplexNumber {
int real, imag; // Creating two complex numbers
public ComplexNumber(int r, int i) { ComplexNumber c1 = new ComplexNumber(4, 5);
this.real = r; ComplexNumber c2 = new ComplexNumber(10, 5);
this.imag = i;
// Printing the complex numbers
}
System.out.print("First Complex number: ");
c1.showC();
//Display the complex number in the form of (a + bi) System.out.println();
public void showC() { System.out.print("\second Complex number: ");
System.out.println("(" + this.real + " + " +"i"+ this.imag + c2.showC();
")");
} // Calling add() to perform addition
ComplexNumber res = add (c1, c2);
// Addition of two complex numbers
public static ComplexNumber add(ComplexNumber n1, // Displaying the addition
ComplexNumber n2) { System.out.print("\nAddition is :");
// Creating a new variable to store the result res.showC();
ComplexNumber res = new ComplexNumber(0, 0); }}
res.real = n1.real + n2.real;
res.imag = n1.imag + n2.imag;
return res;
}
Array of objects
In Java, an array of objects is an array where each element in the array is a reference to an object. This means
the array can store multiple references to objects, and each reference points to an individual object in memory.

An array of objects works similarly to an array of primitive types but instead of storing primitive values, it
stores references (addresses) to objects in memory.

Key Points:

1. Array Declaration: You can declare an array of objects of a particular class type.

2. Array Initialization: Just like arrays of primitive types, arrays of objects can be initialized with a specific
size or values.

3. Object Creation: Each element in the object array is a reference, and it can be assigned an object
(instance of a class).

4. Accessing Object Fields and Methods: You can access the fields and methods of objects in the array
using the object references.
class Book
{ public class Main
String title; {
String author; public static void main(String[] args)
{
public Book(String title, String author) // Inline initialization of an array of Book objects
{ Book[] books = {
this.title = title; new Book("1984", "George Orwell"),
this.author = author; new Book("To Kill a Mockingbird", "Harper Lee"),
new Book("The Great Gatsby", "F. Scott Fitzgerald")
}
};

public void displayInfo()


// Display information about each book
{
for (Book book : books)
System.out.println("Title: "
{
+ title + ", Author: " + author);
book.displayInfo();
}
}
}
}
}
Scanner class
In Java, Scanner is a class in java.util package used for obtaining the input of
the primitive types like int, double, etc. and strings.Using the Scanner class in
Java is the easiest way to read input in a Java program.

Java Scanner Input Types


Scanner class helps to take the standard input stream in Java. So, we
need some methods to extract data from the stream. Methods used for
extracting data are mentioned below:
Method Description

Used for reading Boolean value


nextBoolean()

nextByte() Used for reading Byte value

nextDouble() Used for reading Double value

nextFloat() Used for reading Float value

nextInt() Used for reading Int value

nextLine() Used for reading Line value

nextLong() Used for reading Long value

nextShort() Used for reading Short value


import java.util.Scanner;
public class scannerdemo Enter the Name:
{ Adhya
public static void main(String[] args) Adhya
{ Enter the gender
// TODO Auto-generated method stub F
Scanner sc = new Scanner(System.in); F
// String input Enter the age
System.out.println("Enter the Name:"); 3
String name = sc.nextLine(); 3
System.out.println(name); Enter the mobile no
123456789
System.out.println("Enter the gender"); Mobile Number: 123456789
char gender = sc.next().charAt(0);
System.out.println(gender);

System.out.println("Enter the age");


int age = sc.nextInt();
System.out.println(age);

System.out.println("Enter the mobile no");


long mobileNo = sc.nextLong();
System.out.println("Mobile Number: " + mobileNo);
}
}
class Circle
{ By using two classes:
double radius;

void calculateArea() //method 1 definition


{
double area = 3.14*radius*radius;
System.out.println("Area of circle: " +area);
}
void calculateCircumference() //method 2 definition
{
double circum = 2*3.14*radius;
System.out.println("Circumference of circle: " +circum);
}
}
class Main
{
public static void main(String args[])
{
Circle c = new Circle(); //creating object of class circle
c.radius = 5;
c.calculateArea(); //invokes calculateArea() with object c
c.calculateCircumference(); //invokes
calculateCircumference() with object c
}
}
interface
interface
● An interface can have methods and variables, but the methods declared
in an interface are by default abstract

● Interface methods are by default abstract and public


● Interface attributes are by default public, static and final
● An interface cannot contain a constructor
● To declare an interface, use interface keyword.
● To implement interface use implements keyword.
Why do we use interface ?
● It is used to achieve total abstraction.

● Since java does not support multiple inheritance in case of class, but by using
interface it can achieve multiple inheritance .
Rule

★ All methods in an interface are public and abstract by


default.
★ An interface cannot have a constructor.
★ You can't create objects of an interface.
★ A class uses the implements keyword to implement an
interface.
★ A class can implement multiple interfaces.
Output:
Hello
Output:
drawing circle
Output
Programming Language: Java
interface Animal
{
void makeSound(); // method declaration
class Dog implements Animal }
{
public void makeSound()
public class Test
{
{
System.out.println("Bark");
public static void main(String[] args)
}
{
}
Animal d = new Dog();
Animal c = new Cat();
class Cat implements Animal
{
d.makeSound(); // Output: Bark
public void makeSound()
c.makeSound(); // Output: Meow
{
}
System.out.println("Meow");
}
}
}
Multiple inheritance in Java by interface

• If a class implements multiple interfaces, it is


known as multiple inheritance.
interface A{
void method1(); }
interface B{
void method2(); }
class C implements A, B{
public void method1(){ System.out.println("Method 1");
}
public void method2(){ System.out.println("Method 2");
}
}
class MyClass {
public static void main(String args[]){
C obj = new C();
obj.method1();
obj.method2();
}
}
Interface with default
and static method
import java.io.*;
interface intfA
{
void m1();
}
interface intfB
{
void m2();
}
// class implements both interfaces
// and provides implementation to the method.
class sample implements intfA, intfB
{
@Override
public void m1()
{
System.out.println("Welcome: inside the method m1");
}
@Override
public void m2()
{
System.out.println("Welcome: inside the method m2");
class GFG
{
public static void main (String[] args)
{
sample ob1 = new sample();

// calling the method implemented


// within the class.
ob1.m1();
ob1.m2();
}
}
Output;
Welcome: inside the method m1
Welcome: inside the method m2
Interfaces Can Be Extended

● One interface can inherit another by use of the keyword


extends.

● The syntax is the same as for inheriting classes.

● When a class implements an interface that inherits another


interface, it must provide implementations for all methods
required by the interface inheritance chain.
// One interface can extend another.
interface A {
void meth1(); void meth2();
}
// B now includes meth1() and meth2() -- it adds meth3().
interface B extends A {
void meth3();
}
// This class must implement all of A and B
class MyClass implements B {
public void meth1() {
System.out.println("Implement meth1().");
}
public void meth2() {
System.out.println("Implement meth2().");
}
public void meth3() {
System.out.println("Implement meth3().");
}
}
class IFExtend {
public static void main(String arg[]) {
MyClass ob = new MyClass();
ob.meth1();
ob.meth2();
ob.meth3();
}
}
// Implementation Class
Static Method in Interface - we can public class InterfaceDemo implements NewInterface {
have static method in interface.
public static void main(String[] args)
// Java program to demonstrate {
// static method in Interface. InterfaceDemo interfaceDemo = new InterfaceDemo();

// Calling the static method of interface


interface NewInterface {
NewInterface.hello();

// static method // Calling the abstract method of interface


static void hello() interfaceDemo.overrideMethod("Hello, Override Method
{ here");
System.out.println("Hello, New Static }
Method Here");
// Implementing interface method
}
@Override
// Public and abstract method of Interface public void overrideMethod(String str)
void overrideMethod(String str); {
} System.out.println(str);
}
}
// Java program to demonstrate inheritance in
// interfaces.
import java.io.*;
interface intfA
{
void geekName();
}
interface intfB extends intfA
{
void geekInstitute();
}
// class implements both interfaces and provides
// implementation to the method.
class sample implements intfB
{
@Override
public void geekName()
{
System.out.println("Rohit");
}
@Override
public void geekInstitute()
{
System.out.println("JIIT");
}
public static void main (String[] args)
{
sample ob1 = new sample();

// calling the method implemented


// within the class.
ob1.geekName();
ob1.geekInstitute();
}
}
Output

Rohit
JIIT
Default Interface Methods
● A default method lets you define a default implementation for an interface
method.

● In other words, by use of a default method, it is now possible for an interface


method to provide a body, rather than being abstract.

● During its development, the default method was also referred to as an


extension method
● A primary motivation for the default method was to provide a means by
which interfaces could be expanded without breaking existing code.

● The default method solves this problem by supplying an implementation


that will be used if no other implementation is explicitly provided. Thus,
the addition of a default method will not cause preexisting code to
break.
Default Method Fundamentals
● An interface default method is defined similar to the way a method is
defined by a class.

● The primary difference is that the declaration is preceded by the


keyword default. For example, consider this simple interface:
public interface MyIF {
// This is a "normal" interface method declaration.
// It does NOT define a default implementation.
int getNumber();

// This is a default method. Notice that it provides


// a default implementation.
default String getString() {
return "Default String";
}
}
// Implement MyIF.
class MyIFImp implements MyIF {
// Only getNumber() defined by MyIF needs to be implemented.
// getString() can be allowed to default.
public int getNumber() {
return 100; // Use the default method.
} class DefaultMethodDemo {public static void main(String args[]) {
} MyIFImp obj = new MyIFImp();
// Can call getNumber(), because it is explicitly
// implemented by MyIFImp:
System.out.println(obj.getNumber());
// Can also call getString(), because of default
// implementation:
System.out.println(obj.getString());
}
The output is shown here:
100
Default String
interface TestInterface
{
Program // abstract method
public void square(int a);
// default method
default void show()
{
System.out.println("Default Method Executed");
}
}
class TestClass implements TestInterface
{
// implementation of square abstract method
public void square(int a)
{
System.out.println(a*a);
}
public static void main(String args[])
{
TestClass d = new TestClass();
d.square(4);
// default method executed
d.show();
}
Output
16 Default Method Executed
The default method gives you
• a way to gracefully evolve interfaces over time, and
• a way to provide optional functionality without requiring that a class
provide a
placeholder implementation when that functionality is not needed.
Use static Methods in an Interface
● JDK 8 added another new capability to interface: the ability to define one or
more static methods.
● Like static methods in a class, a static method defined by an interface can
be called independently of any object.
● Thus, no implementation of the interface is necessary, and no instance of the
interface is required, in order to call a static method.
● Instead, a static method is called by specifying the interface name, follow
by a period, followed by the method name.
Here is the general form:
InterfaceName.staticMethodName
The static method is getDefaultNumber( ). It returns zero.
public interface MyIF {
// This is a "normal" interface method declaration.
// It does NOT define a default implementation.
int getNumber();

// This is a default method. Notice that it provides


// a default implementation.
default String getString() {
return "Default String";
}
// This is a static interface method.
static int getDefaultNumber() {
return 0;
}
}
Note: As mentioned, no implementation or instance of MyIF is required to call
getDefaultNumber( ) because it is static.
One last point: static interface methods are not inherited by either an
implementing
// Java program to demonstrate // static method in Interface.
interface NewInterface {
// static method
static void hello()
{
System.out.println("Hello, New Static Method Here");
}
// Public and abstract method of Interface
void overrideMethod(String str);
}
// Implementation Class
public class InterfaceDemo implements NewInterface {
public static void main(String[] args)
{
InterfaceDemo interfaceDemo = new InterfaceDemo();
// Calling the static method of interface
NewInterface.hello();
// Calling the abstract method of interface
interfaceDemo.overrideMethod("Hello, Override Method here");
}
// Implementing interface method
@Override
public void overrideMethod(String str)
{
System.out.println(str);
}
}
Output:
Hello, New Static Method Here
Hello, Override Method here
Output:
Hello there i am ClassTwo Hello there its
ClassOne
Packages
A package in Java is used to group related classes. Think of it as a folder in a file
directory. We use packages to avoid name conflicts and to write a better
maintainable code. Packages are divided into two categories:

● Built-in Packages (packages from the Java API)


● User-defined Packages (create your own packages)

Built-in Packages

The Java API is a library of prewritten classes, that are free to use, included in the
Java Development Environment.

The library contains components for managing input, database programming, and much
much more. The complete list can be found at Oracles website:
https://docs.oracle.com/javase/8/docs/api/.
The library is divided into packages and classes. Meaning you can either import a single class
(along with its methods and attributes), or a whole package that contain all the classes that
belong to the specified package.

To use a class or a package from the library, you need to use the import keyword:

Syntax

import package.name.Class; // Import a single class

import package.name.*; // Import the whole packageImport a Class

If you find a class you want to use, for example, the Scanner class, which is used to get user input, write the following code:

Example

import java.util.Scanner;
User-defined Packages MyPackageClass.java
To create your own package, you need to
package mypack;
understand that Java uses a file system
directory to store them. Just like folders class MyPackageClass
on your computer:
{
Example
└── root public static void main(String[] args)

└── mypack
{
└── MyPackageClass.java
System.out.println("This is my package!");
To create a package, use the package keyword:

}
Prog 1
Note : MyClass.java must be saved inside the myPackage
directory since it is a part of the package.
Prog 2
/* File name : Animal.java */package animals;
/* File name : MammalInt.java */
package animals;
public class MammalInt implements Animal {
interface Animal {
public void eat(); public void eat() {
System.out.println("Mammal eats");
public void travel();
}
}
public void travel() {
System.out.println("Mammal travels");
}
To compile : $ javac -d . Animal.java
public int noOfLegs() { $ javac -d . MammalInt.java
return 0;
}

public static void main(String args[]) {


MammalInt m = new MammalInt();
m.eat();
m.travel();
} Output:
Mammal eats
} Mammal travels

interface Animal {
public void eat();
public void travel();
package payroll;
public class Boss package payroll;
{
import payroll.Employee;
public void payEmployee(Employee e)
{
public class Boss
e.mailCheck(); {
} public void payEmployee(Employee e)
} {
e.mailCheck();
package payroll; }

public static void main(String[] args)


public class Employee
{
{
Boss boss = new Boss();
public void mailCheck() Employee e = new Employee();
{ boss.payEmployee(e);
System.out.println("Pay }
received."); }
}
} Output: Pay received.
How to create a
\
package?

1. Right-click on the source folder.

2. Go to new and then package


THREAD
The Concept Of Multitasking

To help users Operating System accommodates users the privilege of


multitasking, where users can perform multiple actions simultaneously on
the machine. This Multitasking can be enabled in two ways:
1. Process-Based Multitasking
2. Thread-Based Multitasking
Process-Based Multitasking (Multiprocessing)
In this type of Multitasking, processes are heavyweight and each process was allocated by a
separate memory area. And as the process is heavyweight the cost of communication between
processes is high and it takes a long time for switching between processes as it involves actions
such as loading, saving in registers, updating maps, lists, etc.

Thread-Based Multitasking
As we discussed above Threads are provided with lightweight nature and share the same address
space, and the cost of communication between threads is also low.
Why Threads are used?

Threads are used as they had the advantage of being lightweight and can
provide communication between multiple threads at a Low Cost contributing
to effective multi-tasking within a shared memory environment.
Life Cycle of Thread

During its lifetime, a thread transitions through several states, they are:

1. New State

2. Active State

3. Waiting/Blocked State

4. Timed Waiting State

5. Terminated State
Stages of thread:
LIFE CYCLE OF A THREAD
New − A new thread begins its life cycle in the new state. It remains in this state until the program

starts the thread. It is also referred to as a born thread.

Runnable − After a newly born thread is started, the thread becomes runnable. A thread in this state

is considered to be executing its task.

Waiting − Sometimes, a thread transitions to the waiting state while the thread waits for another

thread to perform a task. A thread transitions back to the runnable state only when another thread

signals the waiting thread to continue executing.

Timed Waiting − A runnable thread can enter the timed waiting state for a specified interval of time.

A thread in this state transitions back to the runnable state when that time interval expires or when

the event it is waiting for occurs.

Terminated (Dead) − A runnable thread enters the terminated state when it completes its task or

otherwise terminates.
Creation of Threads using Java Programming Language

We can create Threads in java using two ways, namely :


1. Extending Thread Class
2. Implementing a Runnable interface
Creating a Thread
There are two ways to create a thread.

It can be created by extending the Thread class and overriding its run() method:

public class Main extends Thread


{
public void run()
{
System.out.println("This code is running in a thread");
}

}
Another way to create a thread is to implement the Runnable interface:

public class Main implements Runnable


{
public void run()
{
System.out.println("This code is running in a thread");
}

}
class Multi extends Thread

public void run()

System.out.println("thread is running...");

public static void main(String args[])

Multi t1=new Multi();

t1.start();

}
Running Threads
If the class extends the Thread class, the thread can be run by creating an instance of the class and call its start()
method:
public class Main extends Thread
{
public static void main(String[] args)
{
Main thread = new Main();
thread.start();
System.out.println("This code is outside of the thread");
}
public void run()
{
System.out.println("This code is running in a thread");
}
If the class implements the Runnable interface, the thread can be run by passing an instance of the class
to a Thread object's constructor and then calling the thread's start() method:

public class Main implements Runnable


{
public static void main(String[] args)
{
Main obj = new Main();
Thread thread = new Thread(obj);
thread.start();
System.out.println("This code is outside of the thread");
}
public void run()
{
System.out.println("This code is running in a thread");
}

}
If you are not extending the Thread class, your class object would not be treated as a thread object.
So you need to explicitly create the Thread class object. We are passing the object of your class
that implements Runnable so that your class run() method may execute.

class Multi3 implements Runnable{


public void run(){
System.out.println("thread is running...");
}
public static void main(String args[]){
Multi3 m1=new Multi3();
Thread t1 =new Thread(m1); // Using the constructor Thread(Runnable r)
t1.start();
}
}
package ecom;
package ecom;
public class Multi extends Thread{
public class mainthread {
public void run()
public static void main(String[] args) { {
// TODO Auto-generated method stub for(int i=0;i<5;i++)
Multi obj=new Multi(); {
obj.run(); System.out.println("Hello thread");
for(int i=0;i<5;i++) }
{ }
System.out.println("Hello i am main
thread");
}
} OUTPUT: Hello thread
Hello thread }
} Hello thread
Hello thread
Hello thread
Hello i am main thread This is sequence execution. It is Single
Hello i am main thread thread
Hello i am main thread
Hello i am main thread
Hello i am main thread
package ecom; package ecom;
public class mainthread { public class Multi extends Thread{
public static void main(String[] args) { public void run()
// TODO Auto-generated method stub {
Multi obj=new Multi(); for(int i=0;i<5;i++)
obj.start();
{
for(int i=0;i<5;i++)
System.out.println("Hello thread");
{
}
System.out.println("Hello i am main thread");
} }
}
}
OUTPUT: Hello i am main thread
Hello thread
Hello thread } This is parallel execution. Start()
Hello thread
Hello thread
methods starts new thread. This is
Hello thread concurrent programming
Hello i am main thread
Hello i am main thread
Hello i am main thread
Hello i am main thread
Case 1: start()---->creating new thread

Case 2: run()----->Existing thread (i.e., single thread)

Run method is overridden in child class

What is the purpose of start() method?


package ecom;
public class mainthread {
public static void main(String[] args) { java.lang.IllegalThreadStateException
// TODO Auto-generated method stub at java.base/java.lang.Thread.start(Thread.java:800)
Multi obj=new Multi(); at ecom.mainthread.main(mainthread.java:10)

obj.start();
obj.start();
for(int i=0;i<5;i++)
{
System.out.println("Hello i am main thread");
}
}
}
package ecom;
public class mainthread {
public static void main(String[] args) {
// TODO Auto-generated method stub
Multi obj=new Multi();
System.out.println(obj.getState());
//obj.start();
//obj.start();
for(int i=0;i<5;i++)
{
System.out.println("Hello i am main thread");
}
}
}

NEW
Hello i am main thread
Hello i am main thread
Hello i am main thread
Hello i am main thread
Hello i am main thread
package ecom; package ecom;
public class Multi extends Thread{ public class mainthread
public void run() {
public static void main(String[] args)
{
{
for(int i=0;i<5;i++) // TODO Auto-generated method stub
{ Multi obj=new Multi();
System.out.println("Hello i am main System.out.println(obj.getState());
obj.start();
thread"); System.out.println(obj.getState());
} //obj.start();
} for(int i=0;i<5;i++)
{
System.out.println("Hello thread");
NEW }
RUNNABLE }
Hello i am main thread
Hello i am main thread }
} Hello i am main thread
Hello i am main thread
Hello i am main thread
Hello thread
Hello thread
Hello thread
Hello thread
Hello thread
start(): it implicitly call the run() method.
sleep(milliseconds):it suspends the thread for given milliseconds & time. It is static
Thread.sleep(1000):it uses try catch method to handle exception. No object is
created to call static method .By using thread class it is called.
join():No object is created to call static method .By using thread class it is called.It
is static. it uses try catch method to handle exception.
It Waits until the another thread to complete its process.For ex: if one thread is
given as join() then the another thread has to wait until it completes its process.
getId(): gives the ID of the thread. obj.getId();
getName(): gives the thread name.obj.getName();
setName(String): Thread name will be replaced with given string.
obj.setName(“arudhra”);
getPriority(): priority ranges from 1 to 10.
MIN_PRIORITY=1
NORM_PRIORITY=5
MAX_PRIORITY=10
Normally the priority of thread will be 5.

setPriority(int): setPriority(10);
isAlive(): status of the thread
True: thread is still running
False: thread completes its execution
package threads;
package threads;
public class threadmain
public class threadsprgm extends Thread {
{ public static void main(String[] args)
public void run() {
{ // TODO Auto-generated method stub
for(int i=0;i<=4;i++) threadsprgm th=new threadsprgm();
{ th.start();
System.out.println(i); System.out.println("ID of the thread"+th.getId());
} System.out.println("Name of the thread"+
} th.getName());
} th.setName("Arudhra");
System.out.println("after changing the name"+ " "+
th.getName());

}
}
package threads;
package threads;
public class threadmain
public class threadsprgm extends Thread {
{ public static void main(String[] args)
public void run()
{
{
for(int i=0;i<=4;i++) // TODO Auto-generated method stub
{ threadsprgm th=new threadsprgm();
try { th.start();
Thread.sleep(1000); System.out.println("ID of the thread"+th.getId());
}
System.out.println("Name of the thread"+ th.getName());
catch(Exception e)
{ th.setName("Arudhra");
System.out.println("after changing the name"+ " "+
} th.getName());
System.out.println(i);
}
} }
} }
package threads; package threads;
public class threadsprgm extends Thread public class threadmain
{ {
public void run() public static void main(String[] args)
{ {
Thread t=currentThread();//object // TODO Auto-generated method stub
reference whatever thread starts from that is threadsprgm th=new threadsprgm();
stored in it th.start();
for(int i=0;i<=4;i++) System.out.println("ID of the thread"+th.getId());
{ System.out.println("Name of the thread"+ th.getName());
try { th.setName("Arudhra");
t.sleep(1000); System.out.println("after changing the name"+ " "+ th.getName())
}
catch(Exception e) }
{ }
OUTPUT:
} ID of the thread10
System.out.println(i); Name of the threadThread-0
} after changing the name Arudhra
}
0
}
1
2
3
4
package threads;
public class threadsprgm extends Thread package threads;
{ public class threadmain
public void run() {
{ public static void main(String[] args)
Thread t=currentThread();//object reference whatever {
thread starts from that is stored in it // TODO Auto-generated method stub
for(int i=0;i<=4;i++) threadsprgm th=new threadsprgm();
{ th.start();
try { System.out.println("ID of the thread"+th.getId());
System.out.println("Name of the thread"+ th.getName());
t.sleep(1000); th.setName("Arudhra");
} System.out.println("after changing the name"+ " "+ th.getNa
catch(Exception e)
System.out.println("Priority of the thread"+ th.getPriority()
{
th.setPriority(6);
System.out.println("Priority of the thread"+ th.getPriority()
}
System.out.println(i);
}
}
} }
} ID of the thread14
Name of the threadThread-0
after changing the name Arudhra
Priority of the thread5
Priority of the thread6
0
1
2
3
4
Commonly used methods of Thread class:

public void run(): is used to perform action for a thread.

public void start(): starts the execution of the thread.JVM calls the run() method on the thread.

public void sleep(long miliseconds): Causes the currently executing thread to sleep (temporarily cease execution) for the
specified number of milliseconds.

public void join(): waits for a thread to die.

public void join(long miliseconds): waits for a thread to die for the specified miliseconds.

public int getPriority(): returns the priority of the thread.

public int setPriority(int priority): changes the priority of the thread.

public String getName(): returns the name of the thread.

public void setName(String name): changes the name of the thread.

public Thread currentThread(): returns the reference of currently executing thread.

public int getId(): returns the id of the thread.

public Thread.State getState(): returns the state of the thread.

public boolean isAlive(): tests if the thread is alive.


public void yield(): causes the currently executing thread object to temporarily pause and allow other
threads to execute.

public void suspend(): is used to suspend the thread(depricated).

public void resume(): is used to resume the suspended thread(depricated).

public void stop(): is used to stop the thread(depricated).

public boolean isDaemon(): tests if the thread is a daemon thread.

public void setDaemon(boolean b): marks the thread as daemon or user thread.

public void interrupt(): interrupts the thread.

public boolean isInterrupted(): tests if the thread has been interrupted.

public static boolean interrupted(): tests if the current thread has been interrupted.
Using the Thread Class: Thread(String Name)
public class MyThread1

{ Output:

// Main method My first thread

public static void main(String argvs[])

// creating an object of the Thread class using the constructor Thread(String name)

Thread t= new Thread("My first thread");

// the start() method moves the thread to the active state

t.start();

// getting the thread name by invoking the getName() method

String str = t.getName();

System.out.println(str);

} }
Using the Thread Class: Thread(Runnable r, String name)
public class MyThread2 implements Runnable
{
public void run()
{ Output:
System.out.println("Now the thread is running ..."); My new thread
} Now the thread is running ...
// main method
public static void main(String argvs[])
{

// creating an object of the class MyThread2


Runnable r1 = new MyThread2();

// creating an object of the class Thread using Thread(Runnable r, String name)


Thread th1 = new Thread(r1, "My new thread");
// the start() method moves the thread to the active state
th1.start();

// getting the thread name by invoking the getName() method


String str = th1.getName();
System.out.println(str);
}
package threads; package threads;
public class thread1 extends Thread { public class mymainthread {
public void run() public static void main(String[] args) {
{ // TODO Auto-generated method stub
thread1 t1=new thread1();
Thread t=currentThread(); thread1 t2=new thread1();
t1.start();
for(int i=0;i<=4;i++)
t2.start();
{
}
try {
}
t.sleep(1000);
}
catch(Exception e)
0
{ 0
1
} 1
2
System.out.println(i);
2
} 3
} 3
4
}
4
package threads; package threads;
public class thread1 extends Thread { public class mymainthread {
public void run() public static void main(String[] args) {
{ // TODO Auto-generated method stub
thread1 t1=new thread1();
thread1 t2=new thread1();
for(int i=0;i<=4;i++) t1.start();
{ t2.start();
try { }
Thread.sleep(1000); }
}
catch(Exception e)
{ 0
0
1
} 1
System.out.println(i); 2
2
}
3
} 3
} 4
4
package threads;
package threads; public class mymainthread {
public class thread1 extends Thread { public static void main(String[] args) {
public void run() // TODO Auto-generated method stub
{ thread1 t1=new thread1();
thread1 t2=new thread1();
Thread t=currentThread(); t1.start();
for(int i=0;i<=4;i++)
try {
{
t1.join();
try {
t.sleep(1000); }
} catch(Exception e)
catch(Exception e) { 0
{ } 1
2
t2.start(); 3
} } 4
System.out.println(i); } 0
} 1
2
}
3
} 4
package threads;
package threads; public class mymainthread {
public class thread1 extends Thread { public static void main(String[] args) {
// TODO Auto-generated method stub
public void run()
thread1 t1=new thread1();
{
thread1 t2=new thread1();
t1.start();
Thread t=currentThread(); try {
for(int i=0;i<=4;i++) t1.join();
{ }
try { catch(Exception e)
t.sleep(1000); {
} }
catch(Exception e) System.out.println("Thraed1 status:"+t1.isAlive());
{ t2.start();
}} 0
1
} 2
System.out.println(i); 3
4
}
Thraed1 status:false
} 0
} 1
2
3
4
class mythread extends Thread
{
public void run()
{
try
{
sleep(1000);
for(int i=0;i<4;i++)
{
System.out.println("i is"+ " " +i);
}
}
catch(Exception e)
{
System.out.println(e);
}
}
}
class demothread
{
public static void main(String ar[])
{
mythread myobj=new mythread();
myobj.start();

}
}
class mythread extends Thread
{
public void run() Output:
{
false
for(int i=0;i<4;i++) child thread
{ child thread
System.out.println("child thread"); child thread
} child thread
} true
}
class demothread
{
public static void main(String ar[])
{
mythread myobj=new mythread();
System.out.println(myobj.isAlive());
myobj.start();
System.out.println(myobj.isAlive());
}
}
What is a Thread Scheduler?

The Thread Scheduler in Java is part of the JVM (Java Virtual Machine) that decides
which thread to run next when there are multiple threads ready to run (in the
Runnable state).

Java does not guarantee the order in which threads will execute — the Thread
Scheduler makes that decision based on:

● Thread priority (optional, not always effective)

● Time slicing (each thread gets a small amount of CPU time)

● Preemptive scheduling (a higher-priority thread can interrupt a lower-priority one)


class MyThread extends Thread public class ThreadSchedulerExample {
{ public static void main(String[] args) {
public void run() MyThread t1 = new MyThread();

{ MyThread t2 = new MyThread();


MyThread t3 = new MyThread();

System.out.println(Thread.currentThread().get
t1.setName("Thread-1");
Name() + " is running with priority " + t2.setName("Thread-2");
Thread.currentThread().getPriority()); t3.setName("Thread-3");
}
} t1.setPriority(Thread.MIN_PRIORITY); // Priority 1
t2.setPriority(Thread.NORM_PRIORITY); // Priority 5 (default)
t3.setPriority(Thread.MAX_PRIORITY); // Priority 10
Output: Thread-3 is running with priority 10
Thread-2 is running with priority 5
Thread-1 is running with priority 1 t1.start();

This output may vary each time you run the t2.start();
program because the thread scheduler t3.start();
behavior depends on the JVM and OS.
} }
What is a Thread Pool in Java?
A Thread Pool is a group of worker threads that are ready to perform tasks.

Instead of creating a new thread every time (which is costly), Java uses a pool of
pre-created threads. When a task comes, it reuses one of the threads from the pool.

Benefits of Thread Pool:


★ Reuses threads → avoids the cost of creating new threads again and again.

★ Limits the number of threads → prevents the system from being overloaded.

★ Improves performance → threads are managed efficiently.

How to Create a Thread Pool in Java?


Java provides ExecutorService in java.util.concurrent package to create and manage thread pools.
import java.util.concurrent.ExecutorService;
public class ThreadPoolExample
import java.util.concurrent.Executors; {
public static void main(String[] args)
class MyTask implements Runnable { {
private String taskName; // Create a thread pool with 3 threads
ExecutorService executor =
public MyTask(String name) { Executors.newFixedThreadPool(3);
this.taskName = name;
} // Submit 6 tasks to the pool
for (int i = 1; i <= 6; i++)
public void run() { {
System.out.println(Thread.currentThread().getName() + MyTask task = new MyTask("Task-" + i);
" is executing task: "+ taskName); executor.execute(task); // calling the
method execute which is in ExecutorService
try {
}
Thread.sleep(1000); // Simulate work
} catch (InterruptedException e) {
// Shutdown the executor
e.printStackTrace(); executor.shutdown();
} }
} }
}
for (int i = 1; i <= 6; i++)
{
MyTask task = new MyTask("Task-" + i);
executor.execute(task);
}

★ A loop that creates 6 tasks named Task-1 to Task-6.

★ executor.execute(task) submits the task to the thread pool.

★ The pool will run only 3 tasks in parallel at a time. As threads become available, they pick up
the remaining tasks.

Here, the run() method of the MyTask class is called indirectly by the thread
pool when you submit the task using:

executor.execute(task);
public class ThreadGroupExample
{

public static void main(String[] args)


{

// Create a thread group


ThreadGroup group = new ThreadGroup("MyGroup");

// Create runnable task


Runnable task = () -> {
System.out.println(Thread.currentThread().getName() + " is running");
try
{
Thread.sleep(1000); // Simulate work
// Create multiple threads in the same group
}
Thread t1 = new Thread(group, task, "Thread-1");
catch (InterruptedException e)
Thread t2 = new Thread(group, task, "Thread-2");
{ Thread t3 = new Thread(group, task, "Thread-3");

System.out.println(Thread.currentThread().getName() + " was interrupted"); // Start the threads


} t1.start();
}; t2.start();
t3.start();

// Print info about the group


System.out.println("Active Thread Count: " + group.activeCo
group.list(); // Lists the group and its threads
}
}
OUTPUT: Thread-1 is running
Thread-2 is running
Thread-3 is running
Active Thread Count: 3
java.lang.ThreadGroup[name=MyGroup,maxpri=10]
Thread[Thread-1,5,MyGroup]
Thread[Thread-2,5,MyGroup]
Thread[Thread-3,5,MyGroup]
Practice Question
You are developing a service that sends email notifications to users. Sending
an email is a time-consuming task (e.g., it takes 2 seconds per email). You have
10 emails to send.

Use a thread pool to send these emails concurrently to improve performance.


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class EmailTask implements Runnable {


private String email;

public EmailTask(String email) {


this.email = email;
}

@Override
public void run() {
System.out.println("Sending email to: " + email + " | Thread: " + Thread.currentThread().getName());
try {
Thread.sleep(2000); // Simulate delay in sending email
} catch (InterruptedException e) {
System.out.println("Email sending interrupted for: " + email);
}
System.out.println("Email sent to: " + email);
}
}
public class EmailSender {
public static void main(String[] args) {
// List of email addresses
String[] emailList = {
"[email protected]", "[email protected]", "[email protected]",
"[email protected]", "[email protected]", "[email protected]",
"[email protected]", "[email protected]", "[email protected]",
"[email protected]"
};

// Create a fixed thread pool of 3 threads


ExecutorService executor = Executors.newFixedThreadPool(3);

for (String email : emailList) {


EmailTask task = new EmailTask(email);
executor.execute(task); // Submit task to thread pool
}

executor.shutdown(); // Stop accepting new tasks


System.out.println("All email tasks submitted.");
}
}
ThreadGroup group = new ThreadGroup("MyGroup");

Creates a new thread group named "MyGroup".

This group will be used to group multiple threads.

Runnable task = () -> {

Defines a lambda expression (a short form for creating a class that implements Runnable).

This represents the task that each thread will run.

System.out.println(Thread.currentThread().getName() + " is running");

Prints a message showing the current thread's name and that it's running.
try
{
Thread.sleep(1000); // Simulate work
The thread sleeps for 1 second (1000 milliseconds) to simulate some task or delay.

}
catch (InterruptedException e)
{
System.out.println(Thread.currentThread().getName() + " was interrupted");
}

If the thread is interrupted during sleep, this block will catch and handle the exception.

};

Ends the definition of the Runnable task.


Thread t1 = new Thread(group, task, "Thread-1");
Thread t2 = new Thread(group, task, "Thread-2");
Thread t3 = new Thread(group, task, "Thread-3");
These lines create 3 threads, all assigned to the same thread group.

Each thread is passed: the group (group), the task (task), and a thread name ("Thread-1", etc.).

t1.start();
t2.start();
t3.start();

Starts all three threads — each one begins executing the code inside the Runnable (i.e., prints message and sleep
for 1 second).

System.out.println("Active Thread Count: " + group.activeCount());

Displays the number of active threads currently in the group.

group.list();

Prints detailed information about the group and all its threads, including names and priorities.
What is a Thread Group?

A Thread Group in Java is used to group multiple threads into a single unit for easier
management. You can:

★ Assign multiple threads to the same group.

★ Manage them as a unit (e.g., list them, interrupt them, etc.).

★ Create nested groups (thread group within another group).

ThreadGroup is part of the java.lang package. It is rarely used in modern Java


(ExecutorService is preferred), but it's still good to understand.
public class ThreadGroupExample { class MyTask implements Runnable {
public static void main(String[] args) { public void run() {
// Create a thread group System.out.println(Thread.currentThread().getName() + " is
ThreadGroup group = new ThreadGroup("MyGroup"); running in group " +
// Create threads and assign them to the group
Thread t1 = new Thread(group, new MyTask(), "Worker-1"); Thread.currentThread().getThreadGroup().getName());
Thread t2 = new Thread(group, new MyTask(), "Worker-2"); try {
Thread t3 = new Thread(group, new MyTask(), "Worker-3"); Thread.sleep(2000); // simulate work
// Start threads } catch (InterruptedException e) {
t1.start(); System.out.println(Thread.currentThread().getName() + " was
t2.start(); interrupted");
t3.start(); }
}
// Get information about the thread group }
System.out.println("Active Threads: " + group.activeCount());
System.out.println("Thread Group Name: " + group.getName());
// Wait for all threads to finish
try {
t1.join();
t2.join();
t3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("All threads have finished.");


}
}
Output:
Worker-1 is running in group MyGroup
Worker-2 is running in group MyGroup
Worker-3 is running in group MyGroup
Active Threads: 3
Thread Group Name: MyGroup
All threads have finished.
Threads synchronization

❏ When we start two or more threads within a program, there may be a


situation when multiple threads try to access the same resource and finally
they can produce unforeseen result due to concurrency issues.
❏ For example, if multiple threads try to write within a same file then they may
corrupt the data because one of the threads can override data or while one
thread is opening the same file at the same time another thread might be
closing the same file.
❏ So there is a need to synchronize the action of multiple threads and make
sure that only one thread can access the resource at a given point in
time.
Definition
The synchronized keyword is a modifier that locks a method so that only one thread can use it at
a time. This prevents problems that arise from race conditions between threads.
Thread Synchronization
There are two types of thread synchronization in Java: mutual exclusive and inter-thread communication.

1. Mutual Exclusive:

Mutual Exclusive helps keep threads from interfering with one another while sharing
data. It can be achieved by using the following three ways:

1. Synchronized method.
2. Synchronized block.
3. Static synchronization.

2. Cooperation (Inter-thread communication in Java)


Synchronized Methods

★ If you declare any method as synchronized, it is known as synchronized


method.
★ Synchronized method is used to lock an object for any shared resource.
★ When a thread invokes a synchronized method, it automatically acquires
the lock for that object and releases it when the thread completes its
task.
Without Synchronization
class Table { class MyThread1 extends Thread {
// Method to print the table, not synchronized Table t;
void printTable(int n) { // Constructor to initialize Table object
for(int i = 1; i <= 5; i++) { MyThread1(Table t) {
// Print the multiplication result this.t = t;
System.out.println(n * i); }
try { // Run method to execute thread
// Pause execution for 400 milliseconds
public void run() {
Thread.sleep(400);
// Call printTable method with argument 5
} catch(Exception e) {
t.printTable(5);
// Handle any exceptions
}
System.out.println(e);
}
}
}
} class MyThread2 extends Thread {
} Table t;
public class Main { // Constructor to initialize Table object
public static void main(String args[]) { MyThread2(Table t) {
this.t = t;
// Create a Table object
}
Table obj = new Table();
// Run method to execute thread
// Create MyThread1 and MyThread2 objects with the same Table object
public void run() {
MyThread1 t1 = new MyThread1(obj);
// Call printTable method with argument 100
MyThread2 t2 = new MyThread2(obj); t.printTable(100);
// Start both threads }
t1.start(); }
t2.start();
Output:

100

10

200

15

300

20

400

25

500
class Table {
class MyThread2 extends Thread {
// Synchronized method to print the table Table t;
synchronized void printTable(int n) { // Constructor to initialize Table object
for(int i = 1; i <= 5; i++) { MyThread2(Table t) {
// Print the multiplication result this.t = t;
System.out.println(n * i); }
try { // Run method to execute thread
// Pause execution for 400 milliseconds public void run() {
Thread.sleep(400); // Call synchronized method printTable with argument 100
} catch(Exception e) {
t.printTable(100);
// Handle any exceptions
}
System.out.println(e);
}
}
} public class Main {
} public static void main(String args[]) {
} // Create a Table object
class MyThread1 extends Thread { Table obj = new Table();
Table t; // Create MyThread1 and MyThread2 objects with the
// Constructor to initialize Table object same Table object
MyThread1(Table t) { MyThread1 t1 = new MyThread1(obj);
this.t = t; MyThread2 t2 = new MyThread2(obj);
}
// Start both threads
// Run method to execute thread
t1.start();
public void run() {
// Call synchronized method printTable with argument 5
t2.start();
t.printTable(5); }
}
Output:
5
10
15
20
25
100
200
300
400
500
public class Main {
Synchronized Method by Using Anonymous Class
public static void main(String args[]) {
In this program, we have created the two threads by using the // Create a Table object
anonymous class, so less coding is required. final Table obj = new Table(); // Only one object
// Create thread t1 using anonymous class
Example Thread t1 = new Thread() {
// Program of synchronized method by using anonymous public void run() {
class // Call synchronized method printTable wit
class Table { argument 5
// Synchronized method to print the table obj.printTable(5);
synchronized void printTable(int n) { }
for(int i = 1; i <= 5; i++) { };
// Print the multiplication result // Create thread t2 using anonymous class
System.out.println(n * i); Thread t2 = new Thread() {
try { public void run() {
// Pause execution for 400 milliseconds // Call synchronized method printTable wit
Thread.sleep(400); argument 100
} catch(Exception e) { obj.printTable(100);
// Handle any exceptions }
System.out.println(e); };
} // Start both threads
} t1.start();
} t2.start();
} }
Synchronized Block

Java Synchronized block can be used to perform synchronization on any specific resource of the method.

Suppose we have 50 lines of code in our method, but we want to synchronize only 5 lines, in such cases, we can use
synchronized block.

If we put all the codes of the method in the synchronized block, it will work same as the synchronized method.

Points to Remember
○ Synchronized block is used to lock an object for any shared resource.
○ Scope of synchronized block is smaller than the method.
○ A Java synchronized block doesn't allow more than one JVM, to provide access control to a shared resource.
○ The system performance may degrade because of the slower working of synchronized keyword.
○ Java synchronized block is more efficient than Java synchronized method.
//Creating Thread Class to call method
//Creating a class which contains synchronized block within class MyThread1 extends Thread
method {
class Table Table t;
{ MyThread1(Table t){
void printTable(int n){ this.t=t;
synchronized(this){//synchronized block }
for(int i=1;i<=5;i++){ public void run()
System.out.println(n*i); {
try{
Thread.sleep(400); t.printTable(5);
}catch(Exception e){System.out.println(e);} }
}
} }
}//end of the method class MyThread2 extends Thread
} {
//Creating Main class to start threads Table t;
public class Main{ MyThread2(Table t)
public static void main(String args[]){ {
Table obj = new Table();//only one object this.t=t;
MyThread1 t1=new MyThread1(obj); }
MyThread2 t2=new MyThread2(obj); public void run(){
t1.start(); t.printTable(100);
t2.start(); }
} } }
Output:
5
10
15
20
25
100
200
300
400
500
Synchronized Static method

If a thread is in the static synchronized region, all other threads trying to access this
region will be blocked.

Since static methods belong to the class therefore, static synchronization applies class
level lock.
class Counter {
private static int count = 0;

// Static synchronized method


public static synchronized void increment() {
count++;
System.out.println(Thread.currentThread().getName() + " - Count: " + count);
}
} public class StaticSyncExample {
public static void main(String[] args) {
class MyThread extends Thread {
// Create multiple threads
public void run() {
for (int i = 0; i < 5; i++) { MyThread t1 = new MyThread();
Counter.increment(); MyThread t2 = new MyThread();
}
}
t1.start();
}
t2.start();
}
}
Inter thread communication deadlock.
Inter thread communication means allowing one synchronized thread can communicate
with other synchronized threads.

Inter thread communication is a mechanism in which one thread goes to wait state until
the another thread sends a notification.

wait(): A thread goes into sleep or wait state until some other thread sends
notification.

notify(): Wakes up a single thread that is waiting on this object's monitor.

public void notifyAll(): Wakes up all the threads that called wait( ) on the
same object.
class ThreadB extends Thread {

int totalBalance = 0;

public void run() {


synchronized (this) {
System.out.println("child Thread starts calculation for total balance"); // step 2
for (int i = 0; i <= 50; i++) {
totalBalance = totalBalance + i;
}
System.out.println("child thread gives notification call"); // step 3
this.notify();
}
} public class ThreadA {

public static void main(String[] args) throws InterruptedException {

ThreadB b = new ThreadB();


b.start();
synchronized (b) {
System.out.println("main thread calling wait() method"); // Step 1
b.wait(); // Main thread waits until it gets a notify()
System.out.println("main thread got notification call"); // Step 4
System.out.println("totol balance " + b.totalBalance);

}
Main thread starts

ThreadB b = new ThreadB();


b.start();
synchronized(b) {
b.wait();
}
★ Main thread starts ThreadB and then enters a synchronized(b) block.
★ Inside that, it calls wait(). At this moment, it releases the lock on b and
goes into waiting.

ThreadB starts running

public void run() {


synchronized(this) {
// do work
notify();
}
}
★ The new thread enters run().
★ It tries to synchronize on this (which is the same as object b).
★ Since the main thread released the lock (because of wait()), ThreadB
can acquire it.
★ ThreadB finishes work

After the loop and calculation, it calls notify() inside the synchronized
block.

This wakes up the waiting main thread.

★ Main thread resumes

After being notified, the main thread continues and prints the result.

You might also like