BHARAT KHANNA
BHARAT KHANNA

Reputation: 3

One thread does not run till the other one is ended

I am making a simple producer consumer problem. The waiter is the producer and the chef is the consumer. I have implemented it such that the Chef thread waits till Waiter notifies it of an incoming order in the Queue.

public class Main {

    public static void main(String args[]) {
        final Queue<Integer> sharedQ = new LinkedList<Integer>();
        Thread waiter = new Waiter(sharedQ);
        Thread chef = new Chef(sharedQ);
        waiter.start();
        chef.start();
    }
}

class Items{
    String[] items = {" ", "Sandwich",  "Cereal", "Coffee", "Pizza"};
    int[] time = {0,5,3,3,7};

    String getItem(int value){
        return items[value];
    }

    int getTime(int value){
        return time[value];
    }
}

class Waiter extends Thread{
    private final Queue<Integer> sharedQ;
    static int ord = 0;
    Items item = new Items();
    SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss aa");
    public Waiter(Queue<Integer> sharedQ) {
        super("Waiter");
        this.sharedQ = sharedQ;
    }

    @Override
    public void run() {
        int choice = 1;
        Scanner in = new Scanner(System.in);
        while(choice >= 1 && choice <= 4) {
            synchronized (sharedQ) {
                System.out.print("Enter item id :");
                choice = in.nextInt();
                if(choice >= 1 && choice <= 4){
                    ord++;
                    System.out.println("Order Number: ORD"+ord+" for " + item.getItem(choice)+" has been placed at +"+dateFormat.format(new Date()).toString());
                    sharedQ.add(choice);
                    sharedQ.notifyAll();
                }
            }
        }
    }
}

class Chef extends Thread{
    private final Queue<Integer> sharedQ;
    Items item = new Items();
    static int ord = 0;
    SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss aa");
    public Chef(Queue<Integer> sharedQ) {
        super("Chef");
        this.sharedQ = sharedQ;
    }

    @Override
    public void run() {
        int choice;
        while(true) {
            try{
                synchronized (sharedQ) {
                //waiting condition - wait until Queue is not empty
                    while (sharedQ.size() == 0) {
                        sharedQ.wait();
                    }
                    System.out.println(sharedQ.size());
                    choice = sharedQ.poll();
                    System.out.println("abc");
                    ord++;
                    System.out.println("Chef : Picked up ORD"+ord+" at "+ dateFormat.format(new Date()).toString());
                    System.out.println("Chef: Cooking "+item.getItem(choice));
                    Thread.sleep(60*1000*item.getTime(choice));
                    System.out.println("Chef : Finished making "+item.getItem(choice)+" at "+ dateFormat.format(new Date()).toString());
                    sharedQ.notify();
                }
            }
            catch (InterruptedException ex) {
                System.out.println("Exception in chef function");
            }
        }
    }
}

However, the Chef thread does not respond till the Waiter thread ends. Any leads?

Upvotes: 0

Views: 136

Answers (2)

talex
talex

Reputation: 20455

Try to move

System.out.print("Enter item id :");
choice = in.nextInt();

out of synchronized section.

Problem occur because Waiter thread spend most of it's time in in.nextInt() method waiting for user input. Lock is acquired all that time. When user enter number and lock is released it almost immediately acquired back for next iteration. Scheduler which decide which thread will get lock next if more then one thread try to get it is not perfect so it is wake up Chef thread but do not acquire lock immediately. And we have situation when both thread try to get lock. If you enter several number you will see that Chef get lock some time, but not always.

Upvotes: 1

erickson
erickson

Reputation: 269697

The problem is that the Waiter never releases the lock on the shared queue, so the Chef can never read from it.

What would work better is to use a BlockingQueue implementation, like LinkedBlockingQueue, removing the use of synchronized blocks in your program.

For new applications, using intrinsic locks (synchronized blocks), Thread instances, and wait()/notify() calls should be avoided, preferring the use of ExecutorService and the utilities in the java.util.concurrent package.

Upvotes: 3

Related Questions