简体   繁体   English

Java线程项目怪异的行为,同时增加了线程数

[英]Java thread project weird behavior while increasing num of threads

I created a project for studying purposes that simulates a restaurant service using Threads. 我创建了一个用于研究目的的项目,该项目使用Threads模拟餐厅服务。 There is a Thread for Cook(s) to prepare a meal and another Thread for Waiter(s) to serve the meal. 有一个线程供厨师准备饭菜,还有一个线程供服务员提供饭菜。 When I tested it with 1 cook and 5 waiters, it worked fine. 当我与1位厨师和5位侍者一起测试时,它工作正常。 But when I increase the number of cooks, the program runs indefinitely. 但是,当我增加厨师人数时,该程序将无限期运行。 What is wrong? 怎么了? Here is the code: 这是代码:

Class Main 主班

package restaurant;

import java.util.concurrent.Semaphore;

public class Main {

    public static int MAX_NUM_MEALS = 5;
    public static int OLDEST_MEAL = 0;
    public static int NEWEST_MEAL = -1;
    public static int DONE_MEALS = 0;

    public static int NUM_OF_COOKS = 1;
    public static int NUM_OF_WAITERS = 5;

    public static Semaphore mutex = new Semaphore(1);

    static Cook cookThreads[] = new Cook[NUM_OF_COOKS];
    static Waiter waiterThreads[] = new Waiter[NUM_OF_WAITERS];

    public static void main(String[] args) {
        for(int i = 0; i < NUM_OF_COOKS; i++) {
            cookThreads[i] = new Cook(i);
            cookThreads[i].start();
        }

        for(int i = 0; i < NUM_OF_WAITERS; i++) {
            waiterThreads[i] = new Waiter(i);
            waiterThreads[i].start();
        }
        try {

            for(int i = 0; i < NUM_OF_COOKS; i++) {
                cookThreads[i].join();
            }

            for(int i = 0; i < NUM_OF_WAITERS; i++) {
                waiterThreads[i].join();
            }

        }catch(InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("All done");

    }


}

Class Cook 班级厨师

package restaurant;

public class Cook extends Thread{

    private int id;

    public Cook(int id) {
        this.id = id;
    }

    public void run() {
        while(true) {
            System.out.println("Cook " + id + " is prepearing meal");
            try {
                Thread.sleep(1000);

                Main.mutex.acquire();
                Main.NEWEST_MEAL++;
                Main.mutex.release();

                Main.mutex.acquire();
                Main.DONE_MEALS++;
                Main.mutex.release();

                System.out.println("Cook " + id + " has finished the meal");

                if(Main.DONE_MEALS == 5) {
                    System.out.println("Cook " + id + " has finished his job");
                    break;
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Class Waiter 班级服务员

package restaurant;

public class Waiter extends Thread{
    private int id;

    public Waiter(int id) {
        this.id = id;
    }

    public void run() {
        while(true) {
            System.out.println("Waiter " + id + " will check if there is any meal to serve");
            if(Main.NEWEST_MEAL >= Main.OLDEST_MEAL) {
                try {
                    Main.mutex.acquire();
                    Main.OLDEST_MEAL++;
                    Main.mutex.release();

                    System.out.println("Waiter " + id + " is picking up meal");

                    Thread.sleep(500);

                    System.out.println("Waiter " + id + " has delivered the meal to client");                   

                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if(Main.DONE_MEALS == 5) {
                System.out.println("Waiter " + id + " has finished his job");
                break;
            }
            System.out.println("No meal to serve. Waiter " + id + " will come back later");

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

Two issues: 两个问题:

  1. Because you have two cooks, one of your cooks likely won't see Main.DONE_MEALS == 5 . 因为您有两名厨师,所以您的一名厨师可能看不到Main.DONE_MEALS == 5 It will jump from 4 to 6 because of the other cook. 由于有其他厨师,它将从4跳到6。 Instead, check for Main.DONE_MEALS >= 5 . 相反,请检查Main.DONE_MEALS >= 5
  2. There is no guarantee that the cook or waiter threads will see the updates to Main.DONE_MEALS . 无法保证厨师线程或服务员线程将看到Main.DONE_MEALS的更新。 Instead, consider having a private static final AtomicInteger field. 相反,请考虑使用private static final AtomicInteger字段。 The AtomicInteger class is a thread-safe integer implementation that enables other threads to see it in a thread-safe way. AtomicInteger类是一个线程安全的整数实现,使其他线程能够以线程安全的方式查看它。

The traditional fix would be: 传统的解决方法是:

a) You have to use the lock (mutex) not only when you write, but also when you read - otherwise it won't work correctly. a)您不仅必须在写时使用锁(互斥锁),而且在阅读时也必须使用锁-否则它将无法正常工作。 Just imagine you agreed on a signal to indicate if the bathroom is busy, but some just decide to ignore it - won't work!. 试想一下,如果您同意一个信号以指示浴室是否忙碌,但有些人只是决定忽略它-则行不通!

b) Check the condition before you do something. b)在做某事之前,请检查条件。
Once you acquire the lock, you don't know the state so you should first check it before you proceed to make another meal. 一旦获得了锁,您就不会知道状态,因此您应该先检查一下它,然后再做一顿饭。 If you first check if there are already 5 done meals and only produce meals if there aren't yet 5, it should fix this problem, and you should only ever see done_meals <= 5 (you should review other parts of the code because it has similar problems, though). 如果您首先检查是否已经做过5顿饭,而仅在没有5 done_meals <= 5 ,那应该可以解决此问题,并且您应该只看到done_meals <= 5 (您应该查看代码的其他部分,因为它有类似的问题)。

Like others have mentioned, there are cleaner ways to write this but IMO your code is very suited for practice and understanding, so I'd try that rather than jumping for things like AtomicInteger. 就像其他人提到的那样,有一些更干净的方法可以编写此代码,但是IMO您的代码非常适合实践和理解,因此我会尝试这样做,而不是像AtomicInteger这样跳槽。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM