0% found this document useful (0 votes)
4 views

module 5 multithreading

This document covers multithreaded programming in Java, explaining concepts such as threads, multitasking, thread creation, thread priorities, synchronization, and interthread communication. It details the Java thread model, including the use of the Thread class and Runnable interface, as well as methods for managing thread states and synchronization techniques. Additionally, it discusses issues like deadlock and the deprecated methods for suspending and resuming threads.

Uploaded by

kenkaneki6120
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)
4 views

module 5 multithreading

This document covers multithreaded programming in Java, explaining concepts such as threads, multitasking, thread creation, thread priorities, synchronization, and interthread communication. It details the Java thread model, including the use of the Thread class and Runnable interface, as well as methods for managing thread states and synchronization techniques. Additionally, it discusses issues like deadlock and the deprecated methods for suspending and resuming threads.

Uploaded by

kenkaneki6120
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/ 28

Object Oriented Programming using JAVA

UNIT IV

Multithreaded Programming

A multithreaded program contains two or more parts that can run concurrently.
Each part of such a program is called a thread, and each thread defines a separate
path of execution.
A thread introduces Asynchronous behaviour.

Multitasking
Two types:
1. Process based multitasking
2. Thread based multitasking

Process based multitasking Thread based multitasking

Process is a program under execution Thread is one part of a program.


Two or more programs run concurrently Two or more parts of a single program run
concurrently.

Heavyweight process. Lightweight process.

Programs requires separate address spaces Same address space is shared by threads.
Interprocess communication is expensive and Interthread communication is inexpensive.
limited.
Context switching from one process to Context switching from one thread to the next
another is also costly. is lower in cost.
May create more idle time. Reduces the idle time.
Ex: Running a Java compiler and Ex: We can format a text using a Text editor
downloading a file from a web site at the and printing the data at the same time.
same time
The Java Thread Model
The Java run-time system depends on threads for many things, and all the class libraries are
designed with multithreading in mind.

a) The Thread class and the Runnable Interface


Thread class, its methods, and its companion
interface, Runnable.

Thread class methods

Method Meaning
getName()
getPriority()
setName() Give a name to a thread
setPriority() Set the priority to a thread
isAlive() Determine if a thread is still running.
Join() Wait for a thread to terminate.
Run() Entry point for the thread.
Sleep() Suspend a thread for a period of time.
Start() Start a thread by calling its run method.
currentThread() returns a reference to the thread in which it is called

b) The Main thread


When a Java program starts up, one thread begins running immediately. This is usually
called the main thread of the program.
spawned.

// Controlling the main Thread.


class CurrentThreadDemo {
public static void main(String args[]) {
Thread t = Thread.currentThread();
System.out.println("Current thread: " + t);
// change the name of the thread
t.setName("My Thread");
System.out.println("After name change: " + t);

try {
for(int n = 5; n > 0; n--) {
System.out.println(n);
Thread.sleep(1000);
}
}
catch (InterruptedException e) {
System.out.println("Main thread interrupted");
}
}
}

Output:

Thread Group:
A thread group is a data structure that controls the state of a collection of threads as a whole.

Creating and Starting a Thread


Two ways to create a thread
1. By extending Thread class
2. By implementing Runnable interface
run() method is the entry point for another concurrent thread of execution in the
program.
1. By extending Thread class
The first way to create a thread is to create a new class that extends Thread,
and then to create an instance of that class.
The extending class must override the run( ) method, which is the entry point
for the new thread.
It must also call start( ) to begin execution of the new thread.
Example
class MultipleThreads extends Thread
{
MultipleThreads(String name)
{
super(name);
start();
}
public void run()
{
System.out.print(Thread.currentThread().getName());
System.out.println(" - Thread Demo");
}
public static void main(String ar[])
{
MultipleThreads t1 = new MultipleThreads("One");
MultipleThreads t2 = new MultipleThreads("Two");
MultipleThreads t3 = new MultipleThreads("Three");
}
}
2. By implementing Runnable interface
The easiest way to create a thread is to create a class that implements the
Runnable interface.
To implement Runnable, a class need only implement a single method called
run( ), which is declared like this:
public void run( )
Inside run( ), we will define the code that constitutes the new thread.
It is important to understand that run( ) can call other methods, use other
classes, and declare variables, just like the main thread can.
The only difference is that run( ) establishes the entry point for another,
concurrent thread of execution within your program. This thread will end
when run( ) returns.
Example
class RMultipleThreads implements Runnable
{
String tname;
Thread t;
RMultipleThreads(String name)
{
tname = name;
t = new Thread(this,tname);
t.start();
}
public void run()
{
System.out.println(Thread.currentThread().getName()+"- Thread Demo");
}
public static void main(String ar[])
{
RMultipleThreads t1 = new RMultipleThreads("One");
RMultipleThreads t2 = new RMultipleThreads("Two");
RMultipleThreads t3 = new RMultipleThreads("Three");
}
}
Which of the above two approaches is better?
The first approach is easier to use in simple applications, but is limited by the fact that

other class.
The second approach, which employs a Runnable object, is more general, because
the Runnable object can subclass a class other than Thread.

Thread Priorities, isAlive( ) and join( ) methods

Thread Priorities

1) Every thread has a priority that helps the operating system to determine the order in
which threads are scheduled for execution.
2) Thread priorities are integers that ranges between, 1 to 10.

MIN-PRIORITY (a constant of 1)

MAX-PRIORITY (a constant of 10)

3) By default every thread is given a NORM-PRIORITY(5). The main thread always have
NORM-PRIORITY.
4) Context Switch.

Context Switch
Switching from one running thread to the next thread is called as Context Switch.
Rules for Context Switch
1) A thread can voluntarily relinquish control: This is done by explicitly yielding,
sleeping, or blocking on pending I/O. In this scenario, all other threads are examined,
and the highest-priority thread that is ready to run is given the CPU.

2) A thread can be preempted by a higher-priority thread: In this case, a lower-priority


thread preempted by a higher-priority thread. This is called preemptive multitasking.
Note:
In windows, threads of equal priority are time-sliced automatically in round-robin
fashion.
For other types of operating systems, threads of equal priority must voluntarily
run.
final void setPriority(int level)

final int getPriority( )


By using getPriority(), we can obtain the current priority.

isAlive( ) & join( )


isAlive( ) -> The isAlive( ) method returns true if the thread upon which it is called is
still running. It returns false otherwise.
final boolean isAlive( )
join( ) -> This method waits until the thread on which it is called terminates.
final void join( ) throws InterruptedException

Example:
class ThreadDemo implements Runnable
{
public void run()
{
try
{
for(int i=0;i<3;i++)
{
System.out.println("Thread
Demo:"+Thread.currentThread().getName());
Thread.currentThread().sleep(1000);
}
}
catch(InterruptedException ie)
{
System.out.println("Thread interrupted");
}
}
}
class MultiThreadDemo{
public static void main(String ar[])
{
ThreadDemo r = new ThreadDemo();
Thread t1 = new Thread(r);
t1.setName("First Thread");
t1.setPriority(2);
t1.start();

Thread t2 = new Thread(r);


t2.setName("Second Thread");
t2.setPriority(7);
t2.start();

Thread t3 = new Thread(r);


t3.setName("Third Thread");
t3.setPriority(9);
t3.start();

System.out.println("Thread One is alive: "+ t1.isAlive());


System.out.println("Thread Two is alive: "+ t2.isAlive());
System.out.println("Thread Three is alive: "+ t3.isAlive());
// wait for threads to finish
try {
System.out.println("Waiting for threads to finish.");
t1.join();
t2.join();
t3.join();
}
catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Thread One is alive: "+ t1.isAlive());
System.out.println("Thread Two is alive: "+ t2.isAlive());
System.out.println("Thread Three is alive: "+ t3.isAlive());

System.out.println("Main thread exiting.");


}
}
Thread States / Life cycle of a thread

The life cycle of the thread in java is controlled by JVM. The java thread states are as follows:
1. New
2. Runnable
3. Running
4. Non-Runnable (Blocked)
5. Terminated

We can obtain the current state of a thread by calling the getState( ) method defined by Thread.
Thread.State getState( )
Value State
BLOCKED A thread that has suspended execution because it is waiting to acquire a
lock
NEW A thread that has not begun execution.
RUNNABLE A thread that either is currently executing or will execute when it gains
access to the CPU.
TERMINATED A thread that has completed execution.
TIMED_WAITING A thread that has suspended execution for a specified period of time,
such as when it has called sleep( ). This state is also entered when a
timeout version of wait( ) or join( ) is called.
WAITING A thread that has suspended execution because it is waiting for some
action to occur. For example, it is waiting because of a call to a non-
timeout version of wait( ) or join( ).
Synchronization
Definition:
When two or more threads need access to a shared resource, they need some way to
ensure that the resource will be used by only one thread at a time.
The process by which this is achieved is called synchronization.
Process behind Synchronization
Key to synchronization is the concept of the monitor.
A monitor is an object that is used as a mutually exclusive lock.
Only one thread can own a monitor at a given time.
When a thread acquires a lock, it is said to have entered the monitor.
All other threads attempting to enter the locked monitor will be suspended until the first
thread exits the monitor.
These other threads are said to be waiting for the monitor.

Synchronizing code
We can synchronize the code in two ways:
1. Using synchronized methods
synchronized void test( )
{
}
2.Using Synchronized statements (synchronized blocks)
synchronized statement
synchronized(objRef) {
// statements to be synchronized
}
Here, objRef is a reference to the object being synchronized

Example for Synchronization

class Account {
private int balance = 50;
public int getBalance()
{
return balance;
}
public void withdraw(int amount)
{
balance = balance - amount;
}
}
class AccountDanger implements Runnable
{
private Account acct = new Account();

public void run() {


for (int x = 0; x < 5; x++) {
makeWithdrawal(10);
if (acct.getBalance() < 0) {
System.out.println("account is overdrawn!");
}
}
}
private synchronized void makeWithdrawal(int amt) {
if (acct.getBalance() >= amt) {
System.out.println(Thread.currentThread().getName()+ " is going
to withdraw");
try {
Thread.sleep(500);
}
catch(InterruptedException ex) { }
acct.withdraw(amt);

System.out.println(Thread.currentThread().getName()+ "
completes the withdrawal");
}
else {
System.out.println("Not enough in account for " +
Thread.currentThread().getName()+ " to withdraw " + acct.getBalance());
}
}
}
public class SyncExample
{
public static void main (String [] args)
{
AccountDanger r = new AccountDanger();
Thread t1 = new Thread(r);
t1.setName("A");
Thread t2 = new Thread(r);
t2.setName("B");
t1.start();
t2.start();
}
}

Output
Interthread Communication
Java includes an elegant interprocess communication mechanism via the wait( ), notify ( ),
and notifyAll( ) methods.
These methods are implemented as final methods in Object, so all classes have them.
All three methods can be called only from within a synchronized context.

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

Example: Producer and Consumer Problem

Producer produces an item and consumer consumes an item produced by the producer
immediately. Producer should not produce any item until the consumer consumes the item.
Consumer should wait until producer produces a new item.

class Q
{
int n;
boolean valueSet = false;
synchronized int get() {
while(!valueSet)
try {
wait();
}
catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
System.out.println("Got: " + n);
valueSet = false;
notify();
return n;
}
synchronized void put(int n) {
while(valueSet)
try {
wait();
}
catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
this.n = n;
valueSet = true;
System.out.println("Put: " + n);
notify();
}
}
class Producer implements Runnable
{
Q q;
Producer(Q q)
{
this.q = q;
Thread t = new Thread(this, "Producer");
t.start();
}
public void run()
{
int i = 0;
while(i<10)
{
q.put(i++);
}
}
}
class Consumer implements Runnable
{
Q q;
Consumer(Q q)
{
this.q = q;
Thread t = new Thread(this, "Consumer");
t.start();
}
public void run()
{
int i = 0;
while(i < 10)
{
q.get();
}
}
}

class PC
{
public static void main(String args[])
{
Q q = new Q();
Producer p = new Producer(q);
Consumer c = new Consumer(q);
}
}
Deadlock
Deadlock describes a situation where two or more threads are blocked forever, waiting
for each other.

Example:

public class DeadlockThread {


public static Object Lock1 = new Object();
public static Object Lock2 = new Object();

public static void main(String args[]) {


ThreadDemo1 T1 = new ThreadDemo1();
ThreadDemo2 T2 = new ThreadDemo2();
T1.start();
T2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");

try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 1: Waiting for lock 2...");

synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try { Thread.sleep(10); }
catch (InterruptedException e) {}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
Suspending, Resuming, and Stopping Threads
Sometimes, suspending execution of a thread is useful.

Java 1.0 has methods for suspending,resuming and stopping threads.


Suspend() -> to pause a thread
Resume() -> to restart a thread
Stop() -> To stop the execution of a thread
But these methods are inherently unsafe.
Due to this, from Java 2.0, these methods are deprecated (available, but not
recommended to use them).

Example

// Suspending and resuming a thread the modern way.


class NewThread implements Runnable {
String name; // name of thread
Thread t;
boolean suspendFlag;

NewThread(String threadname) {
name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t);
suspendFlag = false;
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
for(int i = 3; i > 0; i--) {
System.out.println(name + ": " + i);
Thread.sleep(200);
synchronized(this) {
while(suspendFlag) {
wait();
}
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
}
System.out.println(name + " exiting.");
}
synchronized void mysuspend() {
suspendFlag = true;
}

synchronized void myresume() {


suspendFlag = false;
notify();
}
}
class SuspendResume {
public static void main(String args[]) {
NewThread ob1 = new NewThread("One");
NewThread ob2 = new NewThread("Two");

try {
Thread.sleep(1000);
ob1.mysuspend();
System.out.println("Suspending thread One");

Thread.sleep(1000);
ob1.myresume();
System.out.println("Resuming thread One");

ob2.mysuspend();
System.out.println("Suspending thread Two");
Thread.sleep(1000);
ob2.myresume();
System.out.println("Resuming thread Two");
}
catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}

// wait for threads to finish


try {
System.out.println("Waiting for threads to finish.");
ob1.t.join();
ob2.t.join();
}
catch (InterruptedException e) {
System.out.println("Main thread Interrupted");
}
System.out.println("Main thread exiting.");
}
}
Input and Output (I/O)
stream
Java programs perform I/O through streams.
A stream is an abstraction that either produces or consumes information.
A stream is linked to a physical device by the Java I/O system.
Java implements streams within class hierarchies defined in the java.io package.
Streams are two types:
Byte streams
Character Streams

Byte Streams
Byte streams provide a convenient means for handling input and output of bytes. Byte
streams are used, for example, when reading or writing binary data.

The Byte Stream classes

InputStream -> abstract class


OutputStream -> abstract class
BufferedInputStream
BufferedOutputStream
ByteArrayInputStream
ByteArrayOutputStream
DataInputStream
DataOutputStream
PrintStream
RandomAccessFile

Character Streams

Character streams provide a convenient means for handling input and output of
characters. They use Unicode and, therefore, can be internationalized. Also, in some
cases, character streams are more efficient than byte streams.
Character Stream classes

Character streams are defined by using two class hierarchies. At the top are two
abstract classes: Reader and Writer. These abstract classes handle Unicode character
streams.

Reader -> abstract class


Writer -> abstract class
BufferedReader
BufferedWriter
CharArrayReader
CharArrayWriter
FileReader
FileWriter
InputStreamReader -> translates bytes to characters
OutputStreamWriter -> translates characters to bytes
PrintWriter -> output stream contains print() and println() methods

The Predefined Streams


System class defines three predefined streams in,out, err
1) System.in is an object of type InputStream
2) System.out and System.err are objects of type PrintStream.
3) System.in refers to standard input, which is the keyboard by default.
4) System.out refers to the standard output stream.
5) System.err refers to the standard error stream, which also is the console by
default.

Reading Console Input reading characters & Strings


In Java, console input is accomplished by reading from System.in.
To obtain a characterbased stream that is attached to the console, wrap System.in in a
BufferedReader object.
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
To read a character from a BufferedReader, use read() method.
int read( ) throws IOException
Each time that read( ) is called, it reads a character from the input stream and returns it
as an integer value. It returns 1 when the end of the stream is encountered.

Example

// Use a BufferedReader to read characters from the console.


import java.io.*;
class BRRead {
public static void main(String args[]) throws IOException {
char c;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
System.out.println("Enter characters, 'q' to quit.");
// read characters
do {
c = (char) br.read();
System.out.println(c);
} while(c != 'q');
}
}
Applet Fundamentals
An applet is a GUI based program. Applets are event driven programs. applets do not
contain main() method
Two types:
AWT based
SWING based

applets are small applications that are accessed on an Internet server, transported over the
Internet, automatically installed, and executed by Java compatible web browser or
appletviewer.

Applet Lifecycle / Applet Skeleton


When an applet begins, the following methods are called, in this sequence:
1. init( )
2. start( )
3. paint( )
When an applet is terminated, the following sequence of method calls takes place:
1. stop( )
2. destroy( )
init() : The init( ) method is the first method to be called. This is where you should initialize
variables. This method is called only once during the run time of your applet.
start() : The start( ) method is called after init( ). It is also called to restart an applet after it has
document is displayed onscreen.
So, if a user leaves a web page and comes back, the applet resumes execution at start( ).
stop(): The stop( ) method is called when a web browser leaves the HTML document
containing the applet when it goes to another page.
destroy(): The destroy( ) method is called when the environment determines that your applet
needs to be removed completely from memory. The stop( ) method is always called before
destroy( ).

AppletSkel.java
// An Applet skeleton.
import java.awt.*;
import java.applet.*;

public class AppletSkel extends Applet {


String s;
// Called first.
public void init() {
// initialization
s = "WELCOME TO JAVA APPLET";
}

/* Called second, after init(). Also called whenever the applet is restarted. */
public void start() {
// start or resume execution
System.out.println("START");
}

// Called when the applet is stopped.


public void stop() {
// suspends execution
System.out.println("STOPPED");
}

/* Called when applet is terminated. This is the last method executed. */


public void destroy() {
// perform shutdown activities
System.out.println("DESTROY");
}

public void paint(Graphics g) {


// redisplay contents of window
g.setColor(Color.red);
g.drawString(s,20,20);
}
}

RunApplet.html

<applet code="AppletSkel.class" width=200 height=60> </applet>

Applet Program with Parameters


import java.awt.*;
import java.applet.*;

public class SimpleApplet extends Applet {


public void paint(Graphics g) {
String myFont = getParameter("font");
String myString = getParameter("string");
int mySize = Integer.parseInt(getParameter("size"));
Font f = new Font(myFont, Font.BOLD, mySize);
g.setFont(f);
g.setColor(Color.red);
g.drawString(myString, 20, 20);
}
}
RunApplet.html
<applet code="SimpleApplet.class" width=200 height=60>
<PARAM NAME="font" VALUE="Dialog">
<PARAM NAME="size" VALUE="24">
<PARAM NAME="string" VALUE="Hello, world...It's Java Applet">
</applet>

Enumerations
a) An enumeration is a list of named constants.
b) Java enumerations are class types.
c) Each enumeration constant is an object of its enumeration type.
d) Each enumeration constant has its own copy of any instance variables defined by the
enumeration.
e) All enumerations automatically inherit one: java.lang.Enum.
// An enumeration of apple varieties.
enum Apple {
A, B, C, D, E
}
The identifiers Jonathan, GoldenDel, and so on, are called enumeration constants.
Each is implicitly declared as a public, static, final member of Apple.
In the language of Java, these constants are called self-typed.

Built-in Methods of ENUM


2 methods: values() and valueOf()

You might also like