0

I'm trying to simulate a bank's service. So far I can randomly generate customers with random times, and the cashiers will serve them if they are not busy. My problem comes when the simulation is supposed to end...it won't. Customers stop being generated, but the cashier keep waiting for customers. I've tried different approaches, but failed. This is the code before attempting different solutions.

This is the CustomerGenerator:

    @Override
public void run() {
    while (currentTime != openTime) {
        double accept = Math.random();
        if (accept >= 0.6) {
            addCustomerToQueue();
            System.out.println("Customer in line.");
        } else {
            System.out.println("Waiting for a customer.");
        }
        try {
            currentTime += 1000;
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

private synchronized void addCustomerToQueue() {
    Customer customer = new Customer(placeInLine + 1);
    this.customerLinkedList.add(customer);
    placeInLine++;
    notify();
}

synchronized Customer getNextCustomer() throws InterruptedException {
    notify();
    while (customerLinkedList.size() == 0) {
        wait();
    }
    return customerLinkedList.poll();
}

This is the Cashier:

    @Override
public void run() {
    try {
        while (true) {
            Customer customer = generator.getNextCustomer();
            int customerServingNumber = customer.getServingNumber();
            double customerServingTime = customer.getServingTime();
            System.out.println(cashierName + " serving " + customerServingNumber + " for " + getServingTime(customerServingTime));
            Thread.sleep(customerServingNumber * 1000);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Alonso Moreno
  • 33
  • 1
  • 3
  • As written, the only way to stop the cashier thread is to interrupt it. So do that -- or provide another way to stop it, like some condition that it checks for. – David Conrad Jun 09 '18 at 01:50
  • Possible duplicate of [How to properly stop the Thread in Java?](https://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-java) – 0xCursor Jun 09 '18 at 01:50
  • Is there any specific condition when you say: "when the simulation is supposed to end." – Aman Chhabra Jun 09 '18 at 01:51

2 Answers2

1

The Cashier thread only terminates after being interrupted (which occurs after Thread.interrupt is invoked directly or via another function like ExecutorService.shutdownNow). You would have to arrange for the thread to be interrupted, break if a certain condition such as a boolean flag is set, or pass in a special empty object that tells the thread to exit on its own.

While it's possible to model this using wait and notify as you've done, it's simpler to implement a producer-consumer workflow using a BlockingQueue. Have your producer thread(s) put elements into the queue and have consumer thread(s) take from the queue. When there are no more elements to produce, add a special empty object to the queue which acts as a signal for the consumer to exit, or simply interrupt the threads.

jspcal
  • 50,847
  • 7
  • 72
  • 76
  • I think adding a special empty object can also be done in current implementation without calling Thread.interrupt as the interrupt is never a preferred way to close. – Aman Chhabra Jun 09 '18 at 02:04
  • There are times when `Thread.interrupt` is the only option (such as when a thread blocks on an interruptible channel). – jspcal Jun 09 '18 at 02:14
  • No @IMustBeSomeone, the loop condition is never evaluated while the thread is blocked. – jspcal Jun 09 '18 at 19:26
  • 1
    @IMustBeSomeone, this answer solves the problem. What OP chooses to do next is up to them. – jspcal Jun 09 '18 at 19:55
0

This worked, but i wonder if its an appropiate solution:

CustomerGenerator:

synchronized Customer getNextCustomer() throws InterruptedException {
    notify();
    while (customerLinkedList.size() == 0) {
        if (currentTime == openTime){
            return null;
        }
        wait();
    }
    return customerLinkedList.poll();
}

Cashier:

@Override
public void run() {
    try {
        Customer customer = generator.getNextCustomer();
        while (customer != null) {
            int customerServingNumber = customer.getServingNumber();
            double customerServingTime = customer.getServingTime();
            System.out.println(cashierName + " serving " + customerServingNumber + " for " + getServingTime(customerServingTime));
            customer = null;
            Thread.sleep(customerServingNumber * 1000);
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Alonso Moreno
  • 33
  • 1
  • 3
  • 1
    You have to be careful to handle the error path and make sure the threads are properly signalled even if there was error generating the next customer object. – jspcal Jun 09 '18 at 19:58