Сохранить стек вызовов, Timer.schedule в java - PullRequest
0 голосов
/ 09 апреля 2020

У меня запущен поток демона, который вызывает функцию (prepareOrder), когда повар не занят и есть заказы, которые необходимо доставить. PrepareOrder вызывает функцию orderComplete через определенный интервал времени, в зависимости от времени, необходимого для выполнения заказа. Теперь проблема, с которой я сталкиваюсь, заключается в том, что только последний вызов prepareOrder отображается в sout.

Демон

package ui;
import Model.takeOrderModel;
public class daemonThread extends Thread{
    //call this method in the main method of driving fucntion
    private  takeOrderModel orderModel;
    daemonThread(takeOrderModel orderModel){
        this.orderModel = orderModel;
    }
    public void assignCook(){
        while(true){
            int toComplete = orderModel.toCompleteOrders.size();
            if ( !orderModel.cookBusy && toComplete>0 ) orderModel.prepareOrder();
        }
    }
}

Функция подготовки заказа.

 public void prepareOrder(){
    // pick the last element from list
    if (toCompleteOrders.size() > 0){
        String nextPrepare = toCompleteOrders.get(toCompleteOrders.size()-1);
        order orderToComplete = allOrdersPlaced.get(nextPrepare);
        completeOrder(orderToComplete);
        toCompleteOrders.remove(nextPrepare);
        }
    }

    //Helper function to prepareOrder moves an order from toComplete to prepared order
    private void completeOrder(order orderToComplete){
        changeCookState();
        new java.util.Timer().schedule(
                new java.util.TimerTask(){
                    @Override
                    public void run() {
                        changeCookState();
                        preparedOrders.add(orderToComplete.id);
                        deliverOrder(orderToComplete.id);
                    }
                }, (long) (orderToComplete.timeToComplete*60)
        );
    }

    public void changeCookState(){
        this.cookBusy = !cookBusy;
    }

    // MODIFIES removes a order from the prepared list and puts it in delivered list
    public String deliverOrder(String completedOrder){
        preparedOrders.remove(completedOrder);
        deliveredOrders.add(completedOrder);
        System.out.println(String.format("The order of %s is here", allOrdersPlaced.get(completedOrder).customerName));
        return String.format("The order of %s is here", allOrdersPlaced.get(completedOrder).customerName);
    }

Основная функция управляющего кода.

orderMachine.takeNewOrder(fullMeal, "Tom");
orderMachine.takeNewOrder(halfMeal, "Bob");
daemonThread backThread = new daemonThread(orderMachine);
backThread.setDaemon(true);
backThread.assignCook();

Теперь только для меня последний размещенный ордер («Боб») печатается на sout. Как все вызовы, созданные с помощью Timer.schedule, могут оставаться в стеке.


Изменения

Функция получения нового заказа.

public boolean takeNewOrder(List<item> itemsInOrder, String customerName){
        try {
            order newOrder = new order(itemsInOrder, customerName);
            allOrdersPlaced.put(newOrder.id, newOrder);
            toCompleteOrders.add(newOrder.id);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

Редактировать 2

- репозиторий c, содержащий полный код https://github.com/oreanroy/Share_code_samples/tree/master/takeOrder

1 Ответ

1 голос
/ 09 апреля 2020

Проблема в этом коде - ошибка параллелизма - переменная cookBusy записывается из двух разных потоков. Чтобы исправить это, используйте AtomicBoolean вместо boolean, так как это потокобезопасно.

AtomicBoolean cookBusy = new AtomicBoolean(false);

Используйте compareAndSet, чтобы перед общедоступной переменной было установлено известное значение перед ее обновлением.

    public void changeCookState(boolean busy){
        if (!this.cookBusy.compareAndSet(!busy, busy))
        {
            throw new RuntimeException("shared variable set to unexpected value");
        }
    }
...