Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Unit 4

Download as pdf or txt
Download as pdf or txt
You are on page 1of 40

UNIT IV MULTITHREADING AND GENERIC PROGRAMMING

Understanding Threads, Thread Priorities, Synchronizing Threads, Thread lifecycle, Inter-thread


communication. Generic Programming–Generic classes–generic methods–Bounded Types–Restrictions and
Limitations-Introduction to JDBC, JDBC Drivers and Architecture, Accessing Database with JDBC.

UNDERSTANDING THREADS
INTRODUCTION:
Multitasking:
 Multitasking is a process of executing multiple tasks simultaneously.
 Multitasking is when multiple processes share common processing resources such as a CPU.
 Multitasking can be achieved in two ways:
 Process-based Multitasking(Multiprocessing)
 Thread-based Multitasking (Multithreading)
Process-based Multitasking (Multiprocessing)
 Each process has its own address in memory i.e. each process allocates separate memory area.
 Process is heavyweight.
 Cost of communication between the processes is high.
 Switching from one process to another require some time for saving and loading registers, memory
maps, updating lists etc.
Thread-based Multitasking (Multithreading)
 Threads share the same address space.
 Thread is lightweight.
 Cost of communication between the thread is low.
 Java Multithreading is mostly used in games, animation, etc.

Difference between Process and Thread:


Sl.No. Process Thread
1 Heavy weight tasks Light weight tasks
2 Require their own separate address They share the same address space of process.
spaces
3 Inter process communication Inter thread communication is inexpensive.
is expensive and limited.
4 Context switching from one process to Context switching from one thread to the next is low
another is also costly. cost.

Difference between Multi-processing and Multithreading:


Sl.No. Multiprocessing Multithreading
1 Several programs are executed concurrently Several parts of same programs are executed
concurrently
2 CPU switches between multiple programs threading CPU switches between multiple threads
to complete their execution of the same program
3 Context switching from one process to Context Switching from one thread to the next is
another is also costly. low cost.
4 Inter process communication Inter thread communication is inexpensive.
is expensive and limited.
5 Require more overhead Require less over head

THREAD LIFECYCLE
 The term Threads in Java is a lightweight process that allows multiple tasks to be executed
simultaneously within a single program, thus improving the system’s performance.
 The life cycle of the thread in java is controlled by JVM.
 The java thread states are as follows:
 New Born
 Runnable
 Running
 Non-Runnable (Blocked/Waiting/sleep)
 Terminated/Dead

New Born:
 The thread enters the new born state as soon as it is created. At new born state, the thread is
considered not alive/Inactive.
 The thread is created using the new operator.
Classname threadname = new classname();  Newborn state
 From the new born state the thread can go to ready to run mode or dead state.
 If start( ) method is called then the thread goes to ready to run mode. If the stop( ) method is called
then the thread goes to dead state.
Ready to run mode (Runnable Mode)
 A thread first enters the runnable state when the start() method is invoked, but a thread can also return
to the runnable state after either running or coming back from a blocked, waiting, or sleeping state.
 When the thread is in the runnable state, it is considered alive/active.
 In the runnable environment, the thread is ready for execution and is awaiting the processor's
availability (CPU time). That is, the thread has entered the queue (line) of threads waiting for
execution.
 The process of allotting time for the threads is called time slicing.

Running:
 The processor (CPU) has assigned a time slot to the thread for execution.
 A thread keeps running until the following condition occurs
 The thread can also be forced to give up the control when one of the following conditions arise
 A thread can be suspended by suspend( ) method. A suspended thread can be revived by using the
resume() method.
 A thread can be made to sleep for a particular time by using the sleep(milliseconds) method. The
sleeping method re-enters runnable state when the time elapses.
 A thread can be made to wait until a particular event occur using the wait() method, which can be run
again using the notify( ) method.
 A thread is pre-empted by a higher priority thread

Waiting/blocked/sleeping:
 This is the state when the thread is still alive, but is currently not eligible to run.
 Here, three states combined into one, but they all have one thing in common: the thread is still alive,
but is currently not eligible to run.
 In other words, it is not runnable, but it might return to a runnable state later if a particular event occurs.
 A thread may be blocked waiting for a resource (like I/O or an object's lock), in which case the event
that sends it back to runnable is the availability of the resource.
 A thread may be sleeping because the thread's run code tells it to sleep for some period of time, in which
case the event that sends it back to runnable is that it wakes up because its sleep time has expired.
 A thread may be waiting, because the thread’s run code causes it to wait, in which case the event that
sends it back to runnable is that another thread sends a notification that it may no longer be necessary
for the thread to wait.
Dead
 A thread will be in Terminated State, due to the below reasons:
 Termination is achieved by a Thread when it finishes its task Normally.
 Sometimes Threads may be terminated due to unusual events like segmentation faults,
exceptions…etc. and such kind of Termination can be called Abnormal Termination.
 A terminated Thread means it is dead and no longer available.
 Once a thread is dead, it can never be brought back to life.
 If you invoke start() on a dead Thread instance, you'll get a runtime (not compiler) exception.

Note:
Waiting
If there are two threads, T1 and T2 where T1 needs to communicate to the camera and the other thread T2
already using a camera to scan then T1 waits until T2 Thread completes its work, at this state T1 is parked in
waiting for the state.
Blocked State
The user called two Threads T2 and T3 with the same functionality and both had same time slice given by
Thread Scheduler then both Threads T1, T2 is in a blocked state.
Sleep
There are two threads T1, T2 waiting for CPU and T1 is undergoing a Critical Coding operation and if it does
not exist the CPU until its operation gets executed then T2 will be exposed to longer waiting with undetermined
certainty, In order to avoid this starvation situation, we had Timed Waiting for the state to avoid that kind of
scenario as in Timed Waiting, each thread has a time period for which sleep() method is invoked and after the
time expires the Threads starts executing its task.

How to Create Threads using Java Programming Language?


We can create Threads in java using two ways, namely :
1. Extending Thread Class
2. Implementing a Runnable interface
By Extending Thread Class
 We can run Threads in Java by using Thread Class, which provides constructors and methods for
creating and performing operations on a Thread
 We use the following constructors for creating the Thread:
 Thread - Which will be execute to set the predefined name for newly created thread, these
names aregenerally in the form of thread -0, thread -1.
 Thread(Runnable r) - Which can be used to provide default name for newly created user
defined thread.
 Thread(String name) - Which can be used to provide user defined name for newly created
thread.
 Thread(Runnable r, String name) - Which will be used to provide user defined name for the
newly created user defined thread.
 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 static void sleep(long millis) throws InterruptedException : 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 final void join() throws InterruptedException: waits for a thread to die for the specified
miliseconds.
 public int getPriority(): returns the priority of the thread.
 public final void setPriority(intnewPriority): 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 static 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.
 Commonly used methods of Object class:
 public final void wait() throws InterruptedException
 public final void notify()
 public final void notifyAll()

Steps to create the thread Using thread class


Create user defined class and make that one as a derived class of thread
class Class_Name extends Thread
{
........
}
Override run() method of Thread class .(It contains the logic of perform any operation)
Create an object for user-defined thread class : Class_Name obj=new Class_Name ( );
Call start() method of thread class to execute run() method: obj.start( );
 Save the program with filename.java

Example:
import java.io.*;
import java.util.*;

public class ABC extends Thread {


// initiated run method for Thread
public void run()
{
System.out.println("Thread Started Running...");
}
public static void main(String[] args)
{
ABC obj = new ABC();

// Invoking Thread using start() method


obj.start();
}
}
Output

Example2: /*Multithreaded program By Extending Thread */


class MyThread extends Thread
{
// The code inside the run method will be executed by multiple threads concurrently.
public void run()
{
for (int x = 1; x < 5; x++)
{
System.out.println("Run by "+ Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
System.out.println("Exception Caught" + ex);
}
}
}

public static void main (String [] args)


{
// Creating Thread objects

MyThread t1= new MyThread();


MyThread t2 = new MyThread();
MyThread t3 = new MyThread();

//Starting the thread


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

Runnable interface:
 The Runnable interface should be implemented by any class whose instances are intended to be executed
by a thread.
 Runnable interface have only one method named run().
public void run(): is used to perform action for a thread.
steps to create the thread using Runnable interface
Create any user defined class and implements runnable interface
class class_Name implements Runnable
{
........
}
Override run() method within the user defined class.
Create an object for user-defined thread class and attached that object to predefined thread class.
Class_Name obj=new Class_Name ( );
Thread t=new Thread(obj )
Call start() method of thread class to execute run() method.
t.start( );
Save the program with filename.java

Example:
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);
t1.start();
}
}

Output

Example 2: /*Multithreaded program By implementing Runnable */


class MyRunnable implements Runnable
{
// The code inside the run method will be executed by multiple threads concurrently.
public void run()
{
for (int x = 1; x < 5; x++)
{
System.out.println("Run by "+ Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
System.out.println("Exception Caught" + ex);
}
}
}

public static void main (String [] args)


{

// Make one reference to Runnable


MyRunnable r = new MyRunnable();
// Create Thread objects
Thread t1 = new Thread(r,"Thread-A");
Thread t2 = new Thread(r,"Thread-B");
Thread t3 = new Thread(r,"Thread-C");
//Start the threads
t1.start();
t2.start();
t3.start();
}
}
Output:

Difference between sleep(), yield(), join()


sleep():
 public static void sleep(long millis) throws InterruptedException
 The sleep() method suspend the execution for at least the specified number of milliseconds and move
the thread to waiting state.
 The sleep() method is a static method of class Thread.
try {
Thread.sleep(5*60*1000); // Sleep for 5 minutes
} catch (InterruptedException ex) { }

yield( ):
 It make the currently running thread head back to runnable to allow other threads of the same priority
to get their turn.
 A yield() won't go to the waiting/sleeping/ blocking state.

join():
 one thread "join onto the end “of another thread.
 If you have a thread_B that can't do its work until another thread_A has completed its work, then you
want thread_B to "join" thread_A. This means that thread_B will not become runnable until thread_A
has finished (and entered the dead state).
Thread t = new Thread();
t.start();
t.join();

SYNCHRONIZING THREADS
 When multiple threads can access the same resource can produce corrupted data or inconsistent data.
 At a time when more than one thread try to access a shared resource, we need to ensure that resource
will be used by only one thread at a time. The process by which this is achieved is called
synchronization. T
 Synchronization is the process by which it ensure that the shared resource will be used by only one
thread at a time. This can be achieved using synchronized keyword.
 While a thread is inside a synchronized method, all other threads that try to call it (or any other
synchronized method) on the same instance have to wait.
 It reduces the level of concurrency.
Why use Synchronization
The synchronization is mainly used to
1. To prevent thread interference.
2. To prevent consistency problem.
Thread Synchronization
There are two types of thread synchronization mutual exclusive and inter-thread communication.
1. Mutual Exclusive
1. synchronized method.
2. synchronized block.
3. static synchronization.
2. Cooperation (Inter-thread communication in java)
Mutual Exclusive:
 The objective of mutual exclusion is to maintain data integrity and preserve the consistency of shared
resources in multi-threaded or multi-process environments.
 When multiple processes or threads attempt to access the same resource simultaneously, there is a risk
of conflicting operations leading to incorrect results or unpredictable behavior.
 Mutual exclusion provides a mechanism to control access to the shared resource, ensuring that only one
entity can operate on it at a time.
 To achieve mutual exclusion, synchronization mechanisms like locks, semaphores, and critical sections are
employed.
1. Synchronized Methods
syntax:
accessspecifier synchronozied return-type method-name(list of arg)
{
}

if a thread invokes a synchronized method on an object , the lock of that object is first acquired , the method
body executed and then the lock released. Another thread invoking synchronized method on that same object
will block until the lock is released. Lock is released as a soon as the method terminates.

Example program:
class SyncDemo implements Runnable
{
public void run()
{
display();

synchronized void display() // synchronized method can aceesed by only one thread at a time
{
for (int x = 1; x < 5; x++)
{
System.out.println("Run by "+ Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
System.out.println("Exception Caught" + ex);
}
}
}
public static void main (String [] args)
{
// Make one Runnable
SyncDemo nr = new SyncDemo();
Thread one = new Thread(nr,"Thread-A");
Thread two = new Thread(nr,"Thread-B");
Thread three = new Thread(nr,"Thread-C");
//Start the thread
one.start();
two.start();
three.start();
}
}
Output :
Note : Notice the output , As Synchronized method allow only one thread to be executed at a time , all the
three threads are executed serially, that is one after another , not concurrently.

2.The synchronized block:


This is the general form of the synchronized statement:
synchronized(object)
{
// statements to be synchronized
}
Here, object is a reference to the object being synchronized. A synchronized block ensures that a call to a
method that is a member of object occurs only after the current thread has successfully entered object’s
monitor.

Example program:
class SyncDemo implements Runnable
{
public void run()
{
synchronized(this)
{
for (int x = 1; x < 5; x++)
{
System.out.println("Run by "+ Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
System.out.println("Exception Caught" + ex);
}
}
}
}
}
class Main
{
public static void main (String [] args)
{
// Make one Runnable
SyncDemo nr = new SyncDemo();
Thread one = new Thread(nr,"Thread-A");
Thread two = new Thread(nr,"Thread-B");
Thread three = new Thread(nr,"Thread-C");

//Start the thread


one.start();
two.start();
three.start();
}
}

Output:

3. static synchronization.
 If you make any static method as synchronized, the lock will be on the class not onobject.
 Use synchronized keyword on the static method to perform static synchronization.
Syntax:
synchronozied static return-type method-name(list of arg)
{
---------------
}
Example:
class SyncDemo implements Runnable
{
public void run()
{
SyncDemo.display();

synchronized static void display() // synchronized method can aceesed by only one thread at a time
{
for (int x = 1; x < 5; x++)
{
System.out.println("Run by "+ Thread.currentThread().getName());
try
{
Thread.sleep(1000);
}
catch (InterruptedException ex)
{
System.out.println("Exception Caught" + ex);
}
}
}
public static void main (String [] args)
{
// Make one Runnable
SyncDemo nr = new SyncDemo();
Thread one = new Thread(nr,"Thread-A");
Thread two = new Thread(nr,"Thread-B");
Thread three = new Thread(nr,"Thread-C");
//Start the thread
one.start();
two.start();
three.start();
}
}

Output:
INTER-THREAD COMMUNICATION

 Inter-thread communication is important when you develop an application where two or more threads
communicate to each other in order to exchange some information.
How to Achieve Inter Thread Communication in Java
 Inter-thread communication is achieved by using the wait(), notify(), and notifyAll() methods of
the Object class.
Methods used for Inter-thread Communication
 There are three simple methods and a little trick which makes thread communication possible. All the
three methods are listed below −

 These methods have been implemented as final methods in Object, so they are available in all the
classes. All three methods can be called only from within a synchronized context.

Example for Inter-Thread Communication (Producer ConsumerProblem)


 Producer-consumer problem (also known as the bounded-buffer 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
 The consumer is consuming the data (i.e. removing it from the buffer), one piece at a time.
 Figure depicts the Producer-Consumer Problem

Figure : Producer-Consumer Problem

While implementing, the following two conditions should be satisfied:


 Producer should not try to add data into the buffer when it is full
 Consumer should not try to remove data from an empty buffer

Drawback
Scenario-1: producer adding items in a queue but consumer not taking items

Scenario- 2: consumer want the item, but the queue is empty

Solution: While implementing producer consumer problem , above two drawbacks have to solve, first chance
will be given to the producer(producer or consumer), producer have to insert only one item in a queue, until
consumer consumes the item, producer cannot add the second item in a queue

Example program:

public class Main


{
public static void main(String[] args)
{
Buffer c = new Buffer();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}

class Buffer
{
private int contents;
private boolean available = false;

public synchronized void put(int value)


{
while (available == true)
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
contents = value;
available = true;
notifyAll();
}

public synchronized int get()


{
while (available == false)
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
available = false;
notifyAll();
return contents;
}
}

class Producer extends Thread


{
private Buffer buff;
private int number;

public Producer( Buffer c, int number)


{
buff = c;
this.number = number;
}

public void run()


{
for (int i = 0; i < 5; i++)
{
buff.put(i);
System.out.println("Producer put: " + i);
try
{
sleep((int)(Math.random() * 100));
}
catch (InterruptedException e) { }
}
}
}

class Consumer extends Thread


{
private Buffer buff;
private int number;
public Consumer( Buffer c, int number)
{
buff = c;
this.number = number;
}
public void run()
{
int value = 0;
for (int i = 0; i < 5; i++)
{
value = buff.get();
System.out.println("Consumer got: " + value);
}
}
}

Output:

THREAD PRIORITIES
 Thread priority in Java is a number assigned to a thread that is used by Thread scheduler to decide
which thread should be allowed to execute.
 In other words, thread priority is a feature in Java that helps the thread scheduler to determine the order
in which threads are executed.
 Each thread is assigned a different priority in Java that will decide the order (preference) in which it is
scheduled for running.
 Thread priorities are represented by a number from 1 to 10 that specifies the relative priority of one
thread to another. The thread with the highest priority is selected by the scheduler to be executed first.

Thread class in Java provides three priority constants to define the priority of a thread. These are:

1) Thread.MIN_PRIORITY = 1
2) Thread.NORM_PRIORITY = 5
3) Thread.MAX_PRIORITY = 10

 The Thread.MIN_PRIORITY represents the minimum priority level for a thread. Its value is 1.
 The Thread.NORM_PRIORITY represents the normal priority level for a thread. Its value is 5.
 The Thread.MAX_PRIORITY represents the maximum priority for a thread. Its value is 10.
 All these priority constants are public, final, and static members of the Thread class.
 The threads having equal priorities share the processor time on the first-come, first-serve basis.
 If any high priority thread enters into the runnable state, it will preempt the currently running thread
forcing it to move to the runnable state. Note that the highest priority thread always preempts any lower
priority thread.
How to Get Priority of Current Thread in Java?
syntax
ThreadName.getPriority();
Here, ThreadName represents the object reference variable of the Thread class.

Example 1:
public class A implements Runnable {
public void run()
{
System.out.println(Thread.currentThread()); // This method is static.
}
public static void main(String[] args)
{
A a = new A();
Thread t = new Thread(a, "NewThread");

System.out.println("Priority of Thread: " +t.getPriority());


System.out.println("Name of Thread: " +t.getName());
t.start();
}
}
Output:

In this example,
How to Set Priority of Thread in Java?
 The setPriority() accepts an integer value as an argument and sets that value as priority of a thread
through which it is called.
syntax
ThreadName.setPriority(n); // Here, n is an integer value which ranges from 1 to 10.

Example:
public class A implements Runnable {
public void run()
{
System.out.println(Thread.currentThread()); // This method is static.
}
public static void main(String[] args)
{
A a = new A();
Thread t = new Thread(a, "NewThread");
t.setPriority(2); // Setting the priority of thread.

System.out.println("Priority of Thread: " +t.getPriority());


System.out.println("Name of Thread: " +t.getName());
t.start();
}
}

Output:

Example:
In this example, we are setting priority of two thread and running them to see the effect of thread priority. Does
setting higher priority thread get CPU first. See the below example.

Program:
class MyThread extends Thread
{
public void run()
{
System.out.println("Thread Running... "+Thread.currentThread().getName());
}
public static void main(String[]args)
{
MyThread p1 = new MyThread();
MyThread p2 = new MyThread();

// Starting thread
p1.start();
p2.start();

// Setting priority
p1.setPriority(2);

// Getting -priority
p2.setPriority(1);
int p = p1.getPriority();
int p22 = p2.getPriority();

System.out.println("first thread priority : " + p);


System.out.println("second thread priority : " + p22);

}
}

Output:

Note: Thread priorities cannot guarantee that a higher priority thread will always be executed first than the
lower priority thread. The selection of the threads for execution depends upon the thread scheduler which is
platform dependent.

GENERIC PROGRAMMING
 Generic programming is important feature that were added to the Java 5 in 2004.
 With the help of generic programming concept developers can create programs that can handle many
data types.
 The term generics means parameterized types.
 The type parameters naming conventions are important to learn generics thoroughly. The common
type parameters are as follows:
 T - Type
 E - Element
 K - Key
 N - Number
 V - Value
 Parameterized types enable you to create a single class, interface, and method that can be used with
different types of data (objects).
 It is an effective strategy that enhances the readability, maintainability, and reusability of code.
 Note: Generics does not work with primitive types (int, float, char, etc).
Advantage of Java Generics
 Type Safety: The ability to create type-safe code in which type-mismatch errors are caught at compile
time is a key advantage of generics
 Reusability: Generic programming enables code to be written once and used for a variety of data types
 Improved Readability: Generics improve readability by making it explicit which data types a class or
method is meant to operate on. Developers will have an easier time understanding the code as a result,
which lowers the risk of mistakes.
Types of Java Generics
 Generic Methods
 Generic Classes

GENERIC METHODS
 Method that uses parameterized types are called Generic Method, Create a method that can be
used with any type of data. Such a method is known as Generics Method.
 It is possible to declare a generic method that uses one or more type parameters.
 It is also possible to create a generic method that is enclosed within a non-generic class.
Syntax: Declaring Generic method
<parameter_type> return_type method_name (parameter_type parameters_name)
{
...
}
How to call generic method

Objectname.<wrapper class>methodname(arguments);
Or
Objectnme.methodname(arguments);
Example1:Passing single parmeter
class DemoClass
{
// creae a generics method
<T> void genericsMethod(T data)
{
System.out.println("Generics Method:");
System.out.println("Data Passed: " + data);
}
}
class GenericMethod
{
public static void main(String[] args)
{
DemoClass demo = new DemoClass();

// generics method working with String


demo.<String>genericsMethod("Java Programming");

// generics method working with integer


demo.<Float>genericsMethod(2.5f);

// generics method working with integer


demo.genericsMethod(45);
}
}

Output:

Note:
 We can call the generics method without including the type parameter.
For example, demo.genericsMethod("Java Programming");
 In this case, the compiler can match the parameter type based on the value passed to the method.

Example2: Passing multiple parmeters of same type


class DemoClass
{
// creae a generics method
<T> void genericsMethod(T data1, T data2)
{
System.out.println("Generics Method:");
System.out.println("Data Passed: " + data1);
System.out.println("Data Passed: " + data2);
}
}
class GenericMethod
{
public static void main(String[] args)
{

// initialize the class with Integer data


DemoClass demo = new DemoClass();

// generics method working with String


demo.<String>genericsMethod("Java Programming","hai");

// generics method working with integer


demo.<Integer>genericsMethod(25,10);
}
}

Output:
Example3: Passing multiple parmeters of different type
class DemoClass
{
// creae a generics method
<T1,T2> void genericsMethod(T1 data1, T2 data2)
{
System.out.println("Generics Method:");
System.out.println("Data Passed: " + data1);
System.out.println("Data Passed: " + data2);
}
}
class GenericMethod
{
public static void main(String[] args)
{

// initialize the class with Integer data


DemoClass demo = new DemoClass();

// generics method working with String


demo.<String,Integer>genericsMethod("Java Programming",10);

// generics method working with integer


demo.<Integer,String>genericsMethod(25,"hai");
}
}

Output:
GENERIC CLASSES
 A class that can refer to any type is known as a generic class.
 Here, we are using the T type parameter to create the generic class of specific type.
 A generic class is defined just like a normal class, with the addition of a list of type parameters in angle
brackets <...> after the class name.
 The type parameters can then be used throughout the class definition to declare variables and specify
parameter types for methods.
 The type parameter section of a generic class can have one or more type parameters separated by
commas. These classes are known as parameterized classes or parameterized types because they accept
one or more parameters.

Syntax for declaring a generic class:


class class-name<type-param-list>
{
// body of the class
}

Syntax for declaring a reference to a generic class:


class-name<wrapper-class>ref-var-name =new class-name< wrapper-class >(arg-list);

Example1 Write a simple generics class with single type parameters.

class Box<T>
{
T a;
Box(T t)
{
a = t;
}
void print()
{
System.out.println("Value="+a);
}
}
class Main
{
public static void main(String[] args)
{
// Create a Gen reference for Integers.
Box<Integer> b1 = new Box<Integer>(10);
// Create a Gen reference for string.
Box<String> b2= new Box<String>(“Hello”);
b1.print();
b2.print();
}
}

Output:

Example 2: Write a simple generics class with two type parameters.


class Box< T, U >
{
T a;
U b;
Box(T x,U y)
{
a = x;
b = y;
}
public void print()
{
System.out.println("Integer Value :"+a);
System.out.println("String Value :"+b);
}
}
class Main
{
public static void main(String[] args)
{
Box<Integer,String> b1 = new Box<Integer,String>(10,"Hello World");
Box<Double,Integer> b2 = new Box<Double,Integer>(10.5,2);
b1.print();
b2.print();
}
}
Output:

BOUNDED TYPES
 Whenever you want to restrict the type parameter to subtypes of a particular class you can use the
bounded type parameter.
 If you just specify a type (class) as bounded parameter, only sub types of that particular class are
accepted by the current generic class. These are known as bounded-types in generics in Java.

Defining bounded-types for class


 You can declare a bound parameter just by extending the required class with the type-parameter, within
the angular braces as −
class classname <Typeparameter extends subtype>
 Here, subtype: Number/String

Example
 In the following Java example the generic class Sample restricts the type parameter to the sub classes of
the Number classes using the bounded parameter.
class Sample <T extends Number>
{
T data;
Sample(T data){
this.data = data;
}
public void display()
{
System.out.println("Data value is: "+data);
}
}
public class BoundsExample
{
public static void main(String args[])
{
Sample<Integer> obj1 = new Sample<Integer>(20);
obj1.display();
Sample<Double> obj2 = new Sample<Double>(20.22d);
obj2.display();
Sample<Float> obj3 = new Sample<Float>(125.332f);
obj3.display();
}
}

Output

Now, if you pass other types as parameters to this class (say, String for example) a compile time error will be
generated.

Example
public class BoundsExample {
public static void main(String args[]) {
Sample<Integer> obj1 = new Sample<Integer>(20);
obj1.display();
Sample<Double> obj2 = new Sample<Double>(20.22d);
obj2.display();
Sample<String> obj3 = new Sample<String>("Krishna");
obj3.display();
}
}

Compile time error


RESTRICTIONS AND LIMITATIONS
 In Java, generic types are compile time entities. The runtime execution is possible only if it is used
along with raw type.
 Primitive type parameters is not allowed for generic programming.
Example:
Stack<int> is not allowed.
 For the instances of generic class throw and catch instances are not allowed.
Example:
public class Test<T> extends Exception
{
//code // Error:can't extend the Exception class
}
 Type Parameters Can’t Be Instantiated : Can't create an instance of T.
Example:
class Gen<T>
{
T ob;
Gen()
{
T ob = new T(); // Illegal!!!
}
}
 Restrictions on Static Members : No static member can use a type parameter declared by the
enclosing class.
Example:
class Wrong<T>
{
// Wrong, no static variables of type T.
static T ob;
}
 Generic Array Restrictions : There are two important generics restrictions that apply to arrays. First,
you cannot instantiate an array whose base type is a type parameter. Second, you cannot create an
array of type specific generic references.

INTRODUCTION TO JDBC
 JDBC stands for Java Database Connectivity.
 JDBC is a Java API (Application Programming Interface) to connect and execute the query with the
database.

 Before JDBC, ODBC API was the database API to connect and execute the query with the database.
But, ODBC API uses ODBC driver which is written in C language (i.e. platform dependent and
unsecured). That is why Java has defined its own API (JDBC API) that uses JDBC drivers (written in
Java language).
 JDBC is platform independent
 We can use JDBC API to handle database using Java program and can perform the following
activities:
 Connect to the database
 Execute queries and update statements to the database
 Retrieve the result received from the database.
 JDBC is used to interact with various type of Database such as Oracle, MS Access, My SQL and SQL
Server.
 The JDBC classes are contained in the Java Package java.sql and javax.sql.
 The JDBC API supports both two-tier and three-tier processing models for database access but in
general, JDBC Architecture consists of two layers.

Two-tier model:
 A java application communicates directly to the data source.
 The JDBC driver enables the communication between the application and the data source.
 When a user sends a query to the data source, the answers for those queries are sent back to the user in
the form of results.
 The data source can be located on a different machine on a network to which a user is connected. This
is known as a client/server configuration, where the user’s machine acts as a client, and the machine
has the data source running acts as the server.
 Suitable for small applications with limited users, where database operations can be managed within
the client.

Advantage
 It is easy to maintain and modification also easy
 Communication is faster.
Disadvantage
 Application performance will be degrade based on increasing users

Three-tier model:
 In this, the user’s queries are sent to middle-tier services, from which the commands are again sent to
the data source. The results are sent back to the middle tier, and from there to the user.

JDBC components
 The JDBC core comes with the following interfaces and classes:
 Driver: This is the interface that controls communication with the database server. It also withdraws
information associated with driver objects.
 Driver Manager: It manages any required set of JDBC drivers
 Connection: This is an interface or session that houses all the methods to connect to any database.
 Statements: This is used to carry out a static SQL statement
 ResultSet: This is used to access the result row-by-row
JDBC DRIVERS AND ARCHITECTURE
JDBC ARCHITECTURE
 The architecture of JDBC follows a layered approach, consisting of three main layers: JDBC API,
JDBC Driver Manager, JDBC Drivers.
Java Application
 It is a java applet or a servlet that communicates with a data source.
JDBC API
 This layer provides a set of classes and interfaces that define the API for Java applications to interact
with databases.
 It includes classes for establishing connections, executing queries, and processing results.
JDBC Driver Manager
 The Driver Manager is responsible for loading and managing the JDBC drivers.
 It acts as a central component for managing the available drivers and creating connections to the
database.
JDBC Drivers
 To communicate with a data source through JDBC, you need a JDBC driver that intelligently
communicates with the respective data source.

JDBC DRIVERS TYPES


 While communicating with the database, we have to convert Java calls into database-specific calls and
database-specific calls into Java calls. To do this task, we require the JDBC Driver.
 JDBC driver implementations vary because of the wide variety of operating systems and hardware
platforms in which Java operates.
Types of JDBC Driver
 Drivers are classified into four types:
 Type-1 Driver or JDBC-ODBC bridge driver
 Type-2 Driver or Native-API driver
 Type-3 Driver or Network Protocol driver
 Type-4 Driver or Pure Java Direct-to-Database or Thin Driver
Type 1 − JDBC-ODBC Bridge Driver
 The Type-1 Driver converts JDBC calls into ODBC calls, and ODBC Driver converts the ODBC calls
into the database-specific calls.
 Open Database Connectivity (ODBC) is an open standard Application Programming Interface (API)
for accessing a database.
 ODBC is platform dependent as we can use ODBC only for windows platform.
 Type-1 Driver takes the support of the ODBC Driver to communicate with the database.
 The Type-1 Driver is provided by the Sun microsystems as part of the JDK.
 ODBC drivers need to be installed on client machine.
 From the figure below, we can see how the Type-1 Driver acts as a bridge between the JDBC and
ODBC Driver. Because of this, the Type-1 Driver is also known as the JDBC-ODBC Bridge Driver or
simply the Bridge Driver.

Advantages
 Easy to use and maintain.
 We can access any database.
 It is available as part of JDK and hence, we are not required to install it separately.
Disadvantage
 The performance is very less. Because, first it converts JDBC calls into ODBC calls and ODBC driver
converts ODBC calls into database specific calls
 It is not suitable for large scale applications
Type 2 − JDBC-Native API
 It is also known as native API partly java driver.
 Type-2 driver is similar to type-1 driver except that ODBC driver is replaced with database vendor
specific native library.
 Native libraries are set of functions written in non_java.
 We have to install vendor provided native libraries on the client machine
 Type-2 driver converts JDBC calls into vendor specific native library calls.
 The native library calls can be understandable directly by database

Advantage
 It provide better performance as compared to Type-1 driver because it required only one level
conversion from JDBC to native library calls.
Disadvantage
 It is database dependent driver, because it internally uses database native libraries
 Driver is platform dependent.
 Native driver needs to be installed on client machine.

Type 3 − JDBC-Net pure Java


 It follows 3-tier architecture where JDBC requests are passed through the network to the middle tier
server.
 The middleware that convert JDBC call directly or indirectly into vendor specific database protocol.
 The database server executes the request and gives back the result.
 Fully written in Java.
 Database specific coding to be done in middle tier.

Advantage
 No client side library is required.
 This driver is server based, so no need for vendor database library to present on the client machine.
Disadvantage
 Network support is required on client machine.
 Database specific coding is done in middleware.
 Maintenance of the middle tier becomes costly.

Type 4 − 100% Pure Java


 It is also known as pure java driver or thin driver.
 Driver uses database specific native protocol to communicate with the database.
 It Converts JDBC calls directly into vendor specific database protocol, So that client applications
communicate directly with the database server.
 It developed only in Java and hence it is called as pure java driver.
 It is platform independent driver.
 This driver wont requires any ODBC driver or native libraries or middle ware server at client side and
hence it is also called as thin driver.
 User needs different drivers for each database.
 Performance is good.
Advantage
 Performance is good as compared to other drivers. Because, it won’t require ODBC driver or native
libraries or middle ware server
 It is a platform independent driver.
Disadvantage
 The user needs a different types of drivers for different database.
 It is database dependent driver, because it communicates directly with the database.

ACCESSING DATABASE WITH JDBC


 Seven steps to connect to a PostgreSQL database from a Java application:
Step 1: Import Packages

 The java.sql package, which is used for database operations.


 Connection represents a connection to a database.
 DriverManager is used to manage the JDBC drivers.
 ResultSet represents the result of a database query.
 SQLException is an exception that is thrown when there is an error in a database operation.
 Statement represents a SQL statement that can be executed on a database.

Step 2: Register Drivers

 The Class.forName method is used to load the driver class, and the org.postgresql.Driver string specifies
the name of the driver class.

Step 3: Establish a Connection

 The dbUrl variable specifies the URL of the database, which includes the protocol (jdbc:postgresql),
the hostname (localhost), the port number (5432), and the database name (mydatabase).
 The username and password variables specify the credentials to use for the connection.
 The DriverManager.getConnection method is used to establish the connection, and it takes the database
URL, username, and password as parameters.
 The resulting connection is stored in the conn variable.

Step 4: Create a Statement

 This line creates a Statement object that can be used to execute SQL queries on the database.
 The conn.createStatement method is used to create the statement, and it returns a new Statement
object.
 The resulting statement is stored in the stmt variable.

Step 5: Execute the Query

 These lines execute a SQL query on the database.


 The query variable specifies the SQL query to execute, which is a SELECT statement that retrieves all
columns (*) from a table named mytable.
 The stmt.executeQuery method is used to execute the query, and it takes the query string as a parameter.
 The resulting query result is stored in the rs variable, which is a ResultSet object.

Step 6: Retrieve Results

 These lines retrieve the results of the query and print them to the console.
 The rs.next method is used to move to the next row in the result set, and it returns true if there is a next
row, or false if there are no more rows.
 The while loop iterates over the rows in the result set, and for each row, it prints the value of the first
column (getString(1)) to the console using System.out.println.

Step 7: Close the Connections

 These lines close the database connections and resources.


 The rs.close method is used to close the result set, which releases any system resources associated with
it.
 The stmt.close method is used to close the statement, which releases any system resources associated
with it.
 The conn.close method is used to close the database connection, which releases any system resources
associated with it.
 It's essential to close these resources to prevent resource leaks and ensure that the database connections
are released back to the pool.

Example:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class PostgreSQLJDBCConnection


{
// PostgreSQL connection details
private static final String DB_URL = "jdbc:postgresql://localhost:5432/vani";

private static final String USER = "postgres";


private static final String PASSWORD = "Newlife3456";

public static void main(String[] args)


{
// Load the PostgreSQL JDBC driver
try
{
Class.forName("org.postgresql.Driver");
}
catch (ClassNotFoundException e)
{
System.out.println("PostgreSQL JDBC driver not found.");
return;
}

// Connect to the PostgreSQL database


try (Connection connection = DriverManager.getConnection(DB_URL, USER, PASSWORD))
{
System.out.println("Connected to PostgreSQL database.");

// Create a statement to execute queries


try (Statement statement = connection.createStatement())
{
// Create a table
String createTableQuery = "CREATE TABLE IF NOT EXISTS person (name VARCHAR(50), dob
DATE, age INTEGER)";
statement.execute(createTableQuery);
System.out.println("Table created.");

// Insert data into the table


String insertQuery = "INSERT INTO person (name, dob, age) VALUES ('sreevani', '1989-10-16',
34)";
statement.execute(insertQuery);
System.out.println("Data inserted.");

// Retrieve data from the table


String selectQuery = "SELECT * FROM person";
try (ResultSet resultSet = statement.executeQuery(selectQuery))
{
while (resultSet.next())
{
String name = resultSet.getString("name");
String dob = resultSet.getString("dob");
int age = resultSet.getInt("age");
System.out.println("Name: " + name + ", DOB: " + dob + ", Age: " + age);
}
resultSet.close();
statement.close();
connection.close();
}
}
}
catch (SQLException e)
{
System.out.println("Error connecting to PostgreSQL database: " + e.getMessage());
}
}
}

You might also like