Monday, April 07, 2014

WBUT 5 years java solutions for BCA,BTech & MCA Course

1.         What do you mean by subclass constructor method? 
If your method overrides one of its superclass's methods, you can invoke the overridden method through the use of the keyword super. You can also use super to refer to a hidden field (although hiding fields is discouraged). Consider this class, Superclass:
public class Superclass {

    public void printMethod() {
        System.out.println("Printed in Superclass.");
    }
}
Here is a subclass, called Subclass, that overrides printMethod():
public class Subclass extends Superclass {

    // overrides printMethod in Superclass
    public void printMethod() {
        super.printMethod();
        System.out.println("Printed in Subclass");
    }
    public static void main(String[] args) {
        Subclass s = new Subclass();
        s.printMethod();   
    }
}
Within Subclass, the simple name printMethod() refers to the one declared in Subclass, which overrides the one in Superclass. So, to refer to printMethod() inherited from Superclass, Subclass must use a qualified name, using super as shown. Compiling and executing Subclass prints the following:
Printed in Superclass.
Printed in Subclass

2.         Describe Inter-thread communication.
     
  • The communication between one thread to another thread is called inter-thread communication

We can achieve this by using
  1. wait()
  1. notify()
  1. notifyAll() Methods

We have a classic 'Producer-Consumer' problem to explain the use of Inter-Thread communications in java,where one thread is producing some data and another is consuming it .The producer has to wait until the consumer is finished before it generates more data.

Let us start with an incorrect implementation of  Producer-Consumer problem, where we are just using the mercy of synchronized method .


// An incorrect implementation of a producer and consumer.
class Q {
    int n;

    synchronized int get() {
        System.out.println("Got: " + n);
        return n;
    }

    synchronized void put(int n) {
        this.n = n;
        System.out.println("Put: " + n);
    }
}


class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(++i);
        }
    }
}

class Consumer implements Runnable {
    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class Main {

    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
    }
}

Although the put( ) and get( ) methods on are synchronized, nothing stops the producer from producing more things than the consumer can use and nothing stops the consumer from using the same product more than once.
Thus,you will get a wrong output as shown below.

Put: 1
Got: 1 Got: 1
Got: 1
Put: 2
Put: 3
Put: 4
Put: 5
Put: 6 
Got: 6

Here Consumer used the same product, product-1 thrice and Consumer didn't get a chance to use the products, Product-2,Product-3,Product-4 and Product-5.

Now we came to know that ,with the only use of synchronized, can't do proper communication between multiple threads.Don't worry ,java is rich enough to provide a solution for this issue,providing three methods ,wait(),notify() and notifyAll() for Inter-Thread Communication.

Let us try the Producer-Consumer problem with the wait() and notify() methods.

// A correct implementation of a producer and consumer.
class Q {
    int n;
    boolean isQueueEmpty = true;

    synchronized int get() {
        if (isQueueEmpty)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        System.out.println("Got: " + n);
        isQueueEmpty = true;
        notify();
        return n;
    }

    synchronized void put(int n) {
        if (!isQueueEmpty)
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println("InterruptedException caught");
            }
        this.n = n;
        isQueueEmpty = false;
        System.out.println("Put: " + n);
        notify();
    }
}

class Producer implements Runnable {
    Q q;

    Producer(Q q) {
        this.q = q;
        new Thread(this, "Producer").start();
    }

    public void run() {
        int i = 0;
        while (true) {
            q.put(i++);
        }
    }
}

class Consumer implements Runnable {
    Q q;

    Consumer(Q q) {
        this.q = q;
        new Thread(this, "Consumer").start();
    }

    public void run() {
        while (true) {
            q.get();
        }
    }
}

public class Main {

    public static void main(String args[]) {
        Q q = new Q();
        new Producer(q);
        new Consumer(q);
    }
}

Here you will get the expected result as shown below

Put: 1
Got: 1
Put: 2
Got: 2
Put: 3
Got: 3
Put: 4
Got: 4
Put: 5
Got: 5

We can see that Producer is not overrunning the Consumer and the Consumer is not using the same product twice.

No comments:

Post a Comment