Sunday, 20 June 2021

Inter Thread Communication in java

multithreading replaces event loop programming by dividing your

tasks into discrete, logical units. Threads also provide a secondary benefit: they do away

with polling. Polling is usually implemented by a loop that is used to check some condition

repeatedly. Once the condition is true, appropriate action is taken. This wastes CPU time.

For example, consider the classic queuing problem, where one thread is producing some

data and another is consuming it. To make the problem more interesting, suppose that the

producer has to wait until the consumer is finished before it generates more data. In a polling system, the consumer would waste many CPU cycles while it waited for the producer to

produce. Once the producer was finished, it would start polling, wasting more CPU cycles

waiting for the consumer to finish, and so on. Clearly, this situation is undesirable.

To avoid polling, 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. Although conceptually advanced from a computer science

perspective, the rules for using these methods are actually quite simple:

• 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( )

Additional forms of wait( ) exist that allow you to specify a period of time to wait.

Before working through an example that illustrates interthread communication, an

important point needs to be made. Although wait( ) normally waits until notify( ) or

notifyAll( ) is called, there is a possibility that in very rare cases the waiting thread could be

awakened due to a spurious wakeup. In this case, a waiting thread resumes without notify( )

or notifyAll( ) having been called. (In essence, the thread resumes for no apparent reason.)

Because of this remote possibility, Sun recommends that calls to wait( ) should take place

within a loop that checks the condition on which the thread is waiting. The following

example shows this technique.

 //Inter Thread Communication in java

class Shared

{

int n;

boolean available=false;

Shared(int x)

{

n=x;

}

synchronized void produce(int x)

{

while(available)

{

try

{

wait();

}

catch(InterruptedException e){}

}

n=x;

available=true;

notify();

}

synchronized int consume()

{

while(!available)

{

try

{

wait();

}

catch(InterruptedException e){}

}

available=false;

notify();

return n;

}

}

class Producer implements Runnable

{

Shared s;

Producer(Shared s1)

{

s=s1;

}

public void run()

{

for(int i=1;i<=10;i++)

{

s.produce(i);

System.out.println("Produced "+i);

}

}

}

class Consumer implements Runnable

{

Shared s;

Consumer(Shared s1)

{

s=s1;

}

public void run()

{

for(int i=1;i<=10;i++)

{

System.out.println("Consumed "+s.consume());

}

}

}

class InterThreadComDemo

{

public static void main(String args[])

{

Shared ob=new Shared(-1);

Producer p=new Producer(ob);

Consumer c=new Consumer(ob);

Thread t1=new Thread(p);

Thread t2=new Thread(c);

t1.start();

t2.start();

}

}

Deadlocks in JAVA

A special type of error that you need to avoid that relates specifically to multitasking is

deadlock, which occurs when two threads have a circular dependency on a pair of synchronized

objects. For example, suppose one thread enters the monitor on object X and another thread

enters the monitor on object Y. If the thread in X tries to call any synchronized method on Y,

it will block as expected. However, if the thread in Y, in turn, tries to call any synchronized

method on X, the thread waits forever, because to access X, it would have to release its own

lock on Y so that the first thread could complete. Deadlock is a difficult error to debug for

two reasons:

• In general, it occurs only rarely, when the two threads time-slice in just the right way.

• It may involve more than two threads and two synchronized objects

//Deadlocks in java

 class DeadLockDemo

{

public static void main(String args[])

{

String r1="Resource 1";

String r2="Resource 2";

Thread t1=new Thread()

{

public void run()

{

synchronized(r1)

{

System.out.println("Locked R1");

try

{

Thread.sleep(300);

}

catch(Exception e){}

synchronized(r2)

{

System.out.println("Locked R2");

}

}

}

};

Thread t2=new Thread()

{

public void run()

{

synchronized(r2)

{

System.out.println("Locked R2");

try

{

Thread.sleep(300);

}

catch(Exception e){}

synchronized(r1)

{

System.out.println("Locked R1");

}

}

}

};

t1.start();

t2.start();

}

}

Rethrowing Exception in JAVA

 A Java exception is an object that describes an exceptional (that is, error) condition that has

occurred in a piece of code. When an exceptional condition arises, an object representing

that exception is created and thrown in the method that caused the error. That method may

choose to handle the exception itself, or pass it on. Either way, at some point, the exception

is caught and processed. Exceptions can be generated by the Java run-time system, or they

can be manually generated by your code. Exceptions thrown by Java relate to fundamental

errors that violate the rules of the Java language or the constraints of the Java execution

environment. Manually generated exceptions are typically used to report some error condition

to the caller of a method.

Java exception handling is managed via five keywords: try, catch, throw, throws, and

finally. Briefly, here is how they work. Program statements that you want to monitor for

exceptions are contained within a try block. If an exception occurs within the try block, it is

thrown. Your code can catch this exception (using catch) and handle it in some rational manner.

System-generated exceptions are automatically thrown by the Java run-time system. To

manually throw an exception, use the keyword throw. Any exception that is thrown out of

a method must be specified as such by a throws clause. Any code that absolutely must be

executed after a try block completes is put in a finally block.

//Rethrowing Exception in JAVA

class ExceptionDemo

{

static void divide(int a,int b)

{

try

{

System.out.println("a/b = "+a/b);

}

catch(ArithmeticException e)

{

System.out.println("ArithmeticException caught in divide");

System.out.println("Rethrowing e");

throw e;

}

}

public static void main(String args[])

{

try

{

divide(10,2);

divide(20,0);

}

catch(ArithmeticException e)

{

System.out.println("ArithmeticException Caught in main");

}

}

}

User Defined Exception in JAVA

Although Java’s built-in exceptions handle most common errors, you will probably want

to create your own exception types to handle situations specific to your applications. This

is quite easy to do: just define a subclass of Exception (which is, of course, a subclass of

Throwable). Your subclasses don’t need to actually implement anything—it is their existence

in the type system that allows you to use them as exceptions.

The Exception class does not define any methods of its own. It does, of course, inherit

those methods provided by Throwable. Thus, all exceptions, including those that you create,

have the methods defined by Throwable available to them.Exception defines four constructors. Two were added by JDK 1.4 to support chained

exceptions, described in the next section. The other two are shown here:

Exception( )

Exception(String msg)

The first form creates an exception that has no description. The second form lets you specify

a description of the exception.

Although specifying a description when an exception is created is often useful, sometimes

it is better to override toString( ). Here’s why: The version of toString( ) defined by Throwable

(and inherited by Exception) first displays the name of the exception followed by a colon, which

is then followed by your description. By overriding toString( ), you can prevent the exception

name and colon from being displayed. This makes for a cleaner output, which is desirable in

some cases.


 //User defined exception when radius of circle is negative

class MyException extends Exception

{

MyException()

{

//Empty Constructor must be there

}

MyException(String str)

{

super(str);

}

}

class DemoException

{

static double area(double r) throws MyException

{

if(r<0)

throw new MyException("Radius cannot be negative");

return 3.14*r*r;

}

public static void main(String args[])

{

try

{

System.out.println("Area is "+area(-10.0));

}

catch(MyException e)

{

//e.printStackTrace();

                        System.out.println(e.getMessage());//It will print Radius cannot be negative 

}

finally

{

System.out.println("Inside Finally");

}

System.out.println("Program Ends");

}

}