0% found this document useful (0 votes)
39 views32 pages

OOC Module 4

Uploaded by

Vinayak Telsang
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)
39 views32 pages

OOC Module 4

Uploaded by

Vinayak Telsang
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/ 32

18CS45

MODULE:IV

Packages in JAVA

 A java package is a group of similar types of classes, interfaces and sub-


packages.
 Package in java can be categorized in two form,
o built-in package and
o user-defined package.

There are many built-in packages such as java, lang, awt, javax, swing, net, io, util, sql
etc.

Advantage of Java Package

1) Java package is used to categorize the classes and interfaces so that they can be easily
maintained.

2) Java package provides access protection.

3) Java package removes naming collision.

The package keyword is used to create a package in java.

//save as Simple.java
package mypack;
public class Simple
{
public static void main(String args[])
{
System.out.println("Welcome to package");
}
}
How to access package from another package?

There are three ways to access the package from outside the package.

1. import package.*;
2. import package.classname;
3. fully qualified name.

1
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

1) Using packagename.*

If you use package.* then all the classes and interfaces of this package will be
accessible but not subpackages.

The import keyword is used to make the classes and interface of another package accessible
to the current package.

Example of package that import the packagename.*


//save by A.java
package pack;
public class A
{
public void msg(){System.out.println("Hello");}
}

//save by B.java
package
mypack; import
pack.*;

class B
{
public static void main(String args[])
{
A obj = new A();
obj.msg();
}
}
Output:Hello

2) Using packagename.classname

If you import package.classname then only declared class of this package will be
accessible.

Example of package by import package.classname


//save by A.java
package pack;
public class A{
public void msg(){System.out.println("Hello");
}}
2
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

//save by B.java
package
mypack; import
pack.A;

class B
{
public static void main(String args[])
{
A obj = new A();
obj.msg();
}
}
Output:Hello

3) Using FUlly QUalified name

If you use fully qualified name then only declared class of this package will be
accessible. Now there is no need to import. But you need to use fully qualified name
every time when you are accessing the class or interface.

It is generally used when two packages have same class name e.g. java.util and java.sql
packages contain Date class.

Example of package by import fully qualified name


//save by A.java
package pack;
public class A
{
public void msg()
{
System.out.println("Hello");
}
}

//save by B.java
package
mypack; class B
{
public static void main(String args[])

3
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

{
pack.A obj = new pack.A();//using fully qualified name
obj.msg();
}
}
Output:Hello

Access Modifiers/Specifiers

The access modifiers in java specify accessibility (scope) of a data member, method,
constructor or class.

There are 4 types of java access modifiers:

1. private
2. default
3. protected
4. public

1) private access modifier


The private access modifier is accessible only within class.

2) default access modifier


If you don't use any modifier, it is treated as default by default. The default modifier
is accessible only within package.

3) protected access modifier

The protected access modifier is accessible within package and outside the package
but through inheritance only.

The protected access modifier can be applied on the data member, method and
constructor. It can't be applied on the class.

4) public access modifier


The public access modifier is accessible everywhere. It has the widest scope among
all other modifiers.

4
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

Understanding all java access modifiers by a simple table.

Access within within outside package by outside


Modifier class package subclass only package
Private Y N N N
Default Y Y N N
Protected Y Y Y N
Public Y Y Y Y

Interface in java

 An interface in java is a blueprint of a class. It has static final variables and


abstract methods.
 The interface in java is a mechanism to achieve abstraction. There can be only
abstract methods in the java interface does not contain method body. It is used to
achieve abstraction and multiple inheritance in Java.
 It cannot be instantiated just like abstract class.
 Interface fields are public, static and final by default, and methods are public and
abstract.

There are mainly three reasons to use interface. They are given below.

 It is used to achieve abstraction.


 By interface, we can support the functionality of multiple inheritance.

Understanding relationship between classes and interfaces

As shown in the figure given below, a class extends another class, an interface
extends another interface but a class implements an interface.

5
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

Example 1

In this example, Printable interface has only one method, its implementation is
provided in the Pgm1 class.

interface printable
{
void print();
}

class Pgm1 implements printable


{
public void print()
{
System.out.println("Hello");
}
}

class IntefacePgm1
{
public static void main(String args[])
{
Pgm1 obj = new Pgm1
(); obj.print();
}
}

6
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

Output:

Hello

Example 2

In this example, Drawable interface has only one method. Its implementation is provided
by Rectangle and Circle classes. In real scenario, interface is defined by someone but
implementation is provided by different implementation providers. And, it is used by
someone else. The implementation part is hidden by the user which uses the interface.
//Interface declaration: by first user
interface Drawable
{
void draw();
}
//Implementation: by second user

class Rectangle implements Drawable


{
public void draw()
{
System.out.println("drawing rectangle");
}
}

class Circle implements Drawable


{
public void draw()
{
System.out.println("drawing circle");
}
}
//Using interface: by third user
class TestInterface1
{
public static void main(String args[])
{
//In real scenario, object is provided by method e.g. getDrawable()
Drawable d=new Circle();

d.draw();
}
}

7
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

Output:

drawing circle

Multiple inheritance in Java by interface

 If a class implements multiple interfaces, or an interface extends multiple


interfaces i.e. known as multiple inheritance.

Example
interface Printable
{
void print();
}

interface Showable
{
void show();
}

class Pgm2 implements Printable,Showable


{
public void print()
{
System.out.println("Hello");
}

public void show()


{
System.out.println("Welcome");
8
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

}
}

Class InterfaceDemo
{
public static void main(String args[])
{
Pgm2 obj = new Pgm2 ();
obj.print();
obj.show();
}
}

Output:
Hello
Welcome

Multiple inheritance is not supported through class in java but it is possible by


interface, why?

 As we have explained in the inheritance chapter, multiple inheritance is not


supported in case of class because of ambiguity.
 But it is supported in case of interface because there is no ambiguity as
implementation is provided by the implementation class. For example:

Example

interface Printable
{
void print();
}

interface Showable
{
void print();
}

class InterfacePgm1 implements Printable, Showable


{
public void print()
{
System.out.println("Hello");
}
}

9
Dept. of CSE, BGMIT OOC (Module 4)
18CS45

class InterfaceDemo
{
public static void main(String args[])
{
InterfacePgm1 obj = new InterfacePgm1
(); obj.print();
}
}

Output:

Hello
 As you can see in the above example, Printable and Showable interface have same
methods but its implementation is provided by class TestTnterface1, so there is no
ambiguity.

Interface inheritance
 A class implements interface but one interface extends another interface . interface
Printable
{
void print();
}

interface Showable extends Printable


{
void show();
}

class InterfacePgm2 implements Showable


{
public void print()
{
System.out.println("Hello");
}
public void show()
{
System.out.println("Welcome");
}

Class InterfaceDemo2
{
public static void main(String args[])
{
InterfacePgm2 obj = new InterfacePgm2 ();
obj.print();
10
Dept. of CSE, BGMIT OOC (Module 4)
obj.show();
}
}

Output:

Hello Welcome

What are threads?

 Java provides built-in support for 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. Thus,
multithreading is a specialized form of multitasking.
 Multithreading enables you to write very efficient programs that make maximum use of
the CPU, because idle time can be kept to a minimum. Multitasking threads require less
overhead than multitasking processes.

The Thread Class and the Runnable Interface

 Java’s multithreading system is built upon the Thread class, its methods, and its
companion interface, Runnable.
 The Thread class defines several methods that help manage threads (shown below)

The Main Thread

When a Java program starts up, one thread begins running immediately. This is usually called the
main thread of your program, because it is the one that is executed when your program begins.
The main thread is important for two reasons:
• It is the thread from which other “child” threads will be spawned.
• Often, it must be the last thread to finish execution because it performs various shutdown
actions.
Although the main thread is created automatically when your program is started, it can be
controlled through a Thread object. To do so, you must obtain a reference to it by calling the
method currentThread( ), which is a public static member of Thread. Its general form is
Dept. of CSE, BGMIT OOC (Module 4)
shown here:
static Thread currentThread( )

Dept. of CSE, BGMIT OOC (Module 4)


This method returns a reference to the thread in which it is called. Once you have a reference to
the main thread, you can control it just like any other thread.

Example:

 In this program, a reference to the current thread (the main thread, in this case) is
obtained by calling currentThread( ), and this reference is stored in the local variable t.
 Next, the program displays information about the thread. The program then calls
setName( ) to change the internal name of the thread. Information about the thread is
then redisplayed.
 Next, a loop counts down from five, pausing one second between each line.
 The pause is accomplished by the sleep( ) method. The argument to sleep( ) specifies the
delay period in milliseconds.
Output:

Current thread: Thread[main,5,main]


After name change: Thread[My Thread,5,main]
5
4
3
2
1

Dept. of CSE, BGMIT OOC (Module 4)


These displays, in order: the name of the thread, its priority, and the name of its group. By
default, the name of the main thread is main. Its priority is 5, which is the default value, and
main is also the name of the group of threads to which this thread belongs.
The general form of sleep() is:

static void sleep(long milliseconds) throws InterruptedException

The number of milliseconds to suspend is specified in milliseconds. This method may throw an
InterruptedException.
Creating a Thread
There are two different ways to create threads.

• You can implement the Runnable interface.


• You can extend the Thread class, itself.

Implementing Runnable

The easiest way to create a thread is to create a class that implements the Runnable interface.
You can construct a thread on any object that implements Runnable. To implement Runnable, a
class need only implement a single method called run( ), which is declared like this:
public void run( )
run( ) establishes the entry point for another, concurrent thread of execution within your
program. This thread will end when run( ) returns.
Thread defines several constructors.
Thread(Runnable threadOb, String threadName)
In this constructor, threadOb is an instance of a class that implements the Runnable interface.
This defines where execution of the thread will begin. The name of the new thread is specified
by threadName.
After the new thread is created, it will not start running until you call its start( ) method, which
is declared within Thread. In essence, start( ) executes a call to run( ). The start( ) method is
shown here:
void start( )

Dept. of CSE, BGMIT OOC (Module 4)


Example:

a new Thread object is created by the following statement:

t = new Thread(this, "Demo Thread");

Next, start( ) is called, which starts the thread of execution beginning at the run( ) method. This
causes the child thread’s for loop to begin. After calling start( ), NewThread’s constructor

Dept. of CSE, BGMIT OOC (Module 4)


returns to main( ). When the main thread resumes, it enters its for loop. Both threads continue
running, sharing the CPU, until their loops finish.

Output:

Child thread: Thread[Demo Thread,5,main]


Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

Dept. of CSE, BGMIT OOC (Module 4)


Extending Thread Class

The second 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:

The child thread is created by instantiating an object of NewThread, which is derived from
Thread.
Notice the call to super( ) inside NewThread. This invokes the following form of the Thread
constructor:
public Thread(String threadName)
Here, threadName specifies the name of the thread.
Creating Multiple Threads
For example, the following program creates three child threads:
Dept. of CSE, BGMIT OOC (Module 4)
Dept. of CSE, BGMIT OOC (Module 4)
As you can see, once started, all three child threads share the CPU. Notice the call to
sleep(10000) in main( ). This causes the main thread to sleep for ten seconds and ensures that it
will finish last.

Using isAlive( ) and join( )


To make main to finish last First, you can call isAlive( )
on the thread. This method is defined by Thread, and its general form is shown here:
final boolean isAlive( )
The isAlive( ) method returns true if the thread upon which it is called is still running. It returns
false otherwise.
While isAlive( ) is occasionally useful, the method that you will more commonly use to
wait for a thread to finish is called join( ), shown here:
final void join( ) throws InterruptedException
This method waits until the thread on which it is called terminates.
Here is an improved version of the preceding example that uses join( ) to ensure that the main
thread is the last to stop. It also demonstrates the isAlive( ) method.

Dept. of CSE, BGMIT OOC (Module 4)


Output:
New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Dept. of CSE, BGMIT OOC (Module 4)
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread exiting.
As you can see, after the calls to join( ) return, the threads have stopped executing.

Thread Priorities
Thread priorities are used by the thread scheduler to decide when each thread should be allowed
to run. In theory, higher-priority threads get more CPU time than lower-priority threads. In
practice, the amount of CPU time that a thread gets often depends on several factors besides its
priority.
To set a thread’s priority, use the setPriority( ) method, which is a member of Thread.
This is its general form:
final void setPriority(int level)
Here, level specifies the new priority setting for the calling thread. The value of level must be
within the range MIN_PRIORITY and MAX_PRIORITY. Currently, these values are 1 and
10, respectively. To return a thread to default priority, specify NORM_PRIORITY, which is
currently 5. These priorities are defined as static final variables within Thread.

You can obtain the current priority setting by calling the getPriority( ) method of Thread,
shown here:
final int getPriority( )

Dept. of CSE, BGMIT OOC (Module 4)


The following example demonstrates two threads at different priorities, One thread is set two
levels above the normal priority, as defined by Thread.NORM_
PRIORITY, and the other is set to two levels below it. The threads are started and allowed to
run for ten seconds. Each thread executes a loop, counting the number of iterations. After ten
seconds, the main thread stops both threads. The number of times that each thread madeit
through the loop is then displayed.

Dept. of CSE, BGMIT OOC (Module 4)


The higher-priority thread got the majority of the CPU time.
Low-priority thread: 4408112
High-priority thread: 589626904

Synchronization
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.
Key to synchronization is the concept of the monitor (also called a semaphore). A monitor is an
object that is used as a mutually exclusive lock, or mutex. Only one thread can own a monitor at
a given time. When a thread acquires a lock, it is said to have entered the monitor. 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.
Using Synchronized Methods
To enter an object’s monitor, just call a method that has been modified with the 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. To exit the monitor and
relinquish control of the object to the next waiting thread, the owner of the monitor simply
returns from the synchronized method.
The following program has three simple classes. The first one, Callme, has a single method
named call( ). The call( ) method takes a String parameter called msg. This method tries to print
the msg string inside of square brackets. The interesting thing to notice is that after call( ) prints
the opening bracket and the msg string, it calls Thread.sleep(1000), which pauses the current
thread for one second.
The constructor of the next class, Caller, takes a reference to an instance of the Callme class and
a String, which are stored in target and msg, respectively. The constructor also creates a new
thread that will call this object’s run( ) method. The thread is started immediately. The run( )
method of Caller calls the call( ) method on the target instance of Callme, passing in the msg
string. Finally, the Synch class starts by creating a single instance of Callme, and three instances
of Caller, each with a unique message string. The same instance of Callme is passed to each
Caller.

Dept. of CSE, BGMIT OOC (Module 4)


Dept. of CSE, BGMIT OOC (Module 4)
As you can see, by calling sleep( ), the call( ) method allows execution to switch to another
thread. This results in the mixed-up output of the three message strings. In this program, nothing
exists to stop all three threads from calling the same method, on the same object, at the same
time. This is known as a race condition, because the three threads are racing each other to
complete the method.

To fix the preceding program, you must serialize access to call( ). That is, you must restrict its
access to only one thread at a time. To do this, you simply need to precede call( )’s definition
with the keyword synchronized, as shown here:
class Callme {
synchronized void call(String msg) {
...
After
synchronized has been added to call( ), the output of the program is as follows:
[Hello]
[Synchronized]
[World]
The synchronized Statement
You simply put calls to the methods defined by this class inside a 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.
Here is an alternative version of the preceding example, using a synchronized block within the
run( ) method:
Dept. of CSE, BGMIT OOC (Module 4)
Dept. of CSE, BGMIT OOC (Module 4)
Interthread Communication

Java supports interprocess communication mechanism via the wait( ), notify( ), and notifyAll( )
methods.
• 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( ).
• notify( ) wakes up a thread that called wait( ) on the same object.
• notifyAll( ) wakes up all the threads that called wait( ) on the same object. One of the
threads will be granted access.
These methods are declared within Object, as shown here:
final void wait( ) throws InterruptedException
final void notify( )
final void notifyAll( )
The following sample program that incorrectly implements a simple form of the producer/
consumer problem. It consists of four classes: Q, the queue that you’re trying to synchronize;
Producer, the threaded object that is producing queue entries; Consumer, the threaded object
that is consuming queue entries; and PC, the tiny class that creates the single Q, Producer, and
Consumer.

Dept. of CSE, BGMIT OOC (Module 4)


Although the put( ) and get( ) methods on Q are synchronized, nothing stops the producer from
overrunning the consumer, nor will anything stop the consumer from consuming the same queue
value twice. Thus, you get the erroneous output shown here.
Put: 1
Got: 1
Got: 1
Got: 1
Got: 1
Got: 1
Put: 2
Put: 3
Put: 4
Put: 5
Put: 6
Put: 7
Got: 7
As you can see, after the producer put 1, the consumer started and got the same 1 five times in a
row. Then, the producer resumed and produced 2 through 7 without letting the consumer have a
chance to consume them.

Dept. of CSE, BGMIT OOC (Module 4)


The proper way to write this program in Java is to use wait( ) and notify( ) to signal in both
directions, as shown here:

Dept. of CSE, BGMIT OOC (Module 4)


Inside get( ), wait( ) is called. This causes its execution to suspend until the Producer notifies
you that some data is ready. When this happens, execution inside get( ) resumes. After the data
has been obtained, get( ) calls notify( ). This tells Producer that it is okay to put more data in the
queue. Inside put( ), wait( ) suspends execution until the Consumer has removed the item from
the queue. When execution resumes, the next item of data is put in the queue, and notify( ) is
called. This tells the Consumer that it should now remove it.

Dept. of CSE, BGMIT OOC (Module 4)


Here is some output from this program:
Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4

Dept. of CSE, BGMIT OOC (Module 4)


Got: 4
Put: 5
Got: 5

Dept. of CSE, BGMIT OOC (Module 4)

You might also like