java - 为什么我的程序有时会卡住?

标签 java multithreading infinite-loop producer-consumer monitors

所以我使用监视器在java中编写了一个有界缓冲区问题,但我无法弄清楚我的程序出了什么问题。有时它会在第三个循环结束之前继续无限循环运行。大多数时候它运行得很好。 该程序很简单,涉及一个生产者和多个消费者。我将不胜感激任何帮助。这是我的 github 的链接,您可以在其中找到完整的代码。 the full code

有界缓冲区

public class BoundedBuffer {
    public BoundedBuffer ()
    {
        int numWorms = 10;
        int numBirds = 5;

        Dish dish = new Dish (numWorms);
        Parent parent = new Parent(dish);
        parent.start();
        Child child[] = new Child[numBirds];
        for (int i = 0; i < numBirds; i++)
        {
            child[i] = new Child (dish);
            child[i].start();
        }       
        for (int i = 0; i < numBirds; i++)
        {
            try {child[i].join();}
            catch (Exception ie) {System.out.println (ie.getMessage());}
        }

        System.out.println("bids done eating :D");
    }
}

菜品

public class Dish 
{
    int worms;
    int copy;
    public Dish (int worms)
    {
        this.worms = worms;
        copy = worms;
    }
    public synchronized void eat ()
    {
        if (worms <= 0)
        {

            waitForFull();
        }
        worms --;
        System.out.println("Bird " + Thread.currentThread().getName() + " has 
eaten."
                        + " The number of worms left is " + worms);

    }
    public synchronized void fill()
    {
        if (worms > 0)
        {
            waitForEmpty();
        }
        worms = copy;
        System.out.println ("Parent filled the dish");
        notifyAll();
    }
    public synchronized void waitForEmpty ()
    {
        while (worms > 0)
        {
            notifyAll();
            try {wait();}
            catch (Exception ie) {System.out.println (ie.getMessage());}
            }
}
    public synchronized void waitForFull ()
    {
        while (worms <= 0)
        {
            notifyAll();
            try {wait();}
            catch (Exception ie) {System.out.println (ie.getMessage());}
        }
    }
}

最佳答案

我无法重现卡住的情况。但我在您的代码中发现了一些其他问题:

  • Parent 在三个循环后立即设置 done = 1,此时 此时,中仍然有蠕虫
  • waitForEmptyfill 不是自动的,这可能会导致 有些不一致。
  • waitForFulleat 不是自动的,这可能会导致 有些不一致。

两个解决这些问题,我认为你需要:

  • waitForEmptyfill 以及 waitForFulleat 合并为单个方法。
  • 使用 shutdownisTerminate 作为信号。 Parent关闭 Dish,而最后一个Child终止 >菜

这是代码:

主要

public class Main {
    public static void main(String[] args) {
        new BoundedBuffer ();
    }
}

有界缓冲区

public class BoundedBuffer {
    public BoundedBuffer () {
        int numWorms = 10;
        int numBirds = 5;

        Dish dish = new Dish (numWorms);
        Parent parent = new Parent(dish);
        parent.start();
        Child child[] = new Child[numBirds];
        for (int i = 0; i < numBirds; i++) {
            child[i] = new Child (dish);
            child[i].start();
        }       
        for (int i = 0; i < numBirds; i++) {
            try {child[i].join();}
            catch (Exception ie) {System.out.println (ie.getMessage());}
        }

        System.out.println("bids done eating :D");
    }
}

菜品

public class Dish {
    int worms;
    int copy;
    boolean shutDown;
    boolean isTerminated;

    public Dish (int worms) {
        this.worms = worms;
        copy = worms;
    }

    public synchronized void waitForEmptyToFill() {
        while (worms > 0) {
            try {
                notifyAll();
                wait();
            } catch (Exception ie) {
                System.out.println (ie.getMessage());
            }
        }
        worms = copy;
        System.out.println ("Parent filled the dish");
        notifyAll();
    }

    public synchronized void waitForFullToEat () {
        while (worms <= 0 && !isTerminated()) {
            try {
                notifyAll();
                wait();
            } catch (Exception ie) {
                System.out.println (ie.getMessage());
            }
        }
        if (worms > 0) {
            worms--;
            System.out.println("Bird " + Thread.currentThread().getName() + " has eaten."
                    + " The number of worms left is " + worms);
            if (worms == 0 && isShutDown()) {
                setTerminated(true);
                notifyAll();
            }
        }
    }


    public synchronized boolean isShutDown() {
        return shutDown;
    }

    public synchronized void setShutDown(boolean shutDown) {
        this.shutDown = shutDown;
    }

    public synchronized boolean isTerminated() {
        return isTerminated;
    }

    public synchronized void setTerminated(boolean terminated) {
        isTerminated = terminated;
    }
}

父级

public class Parent extends Thread {

    private Dish dish;

    public Parent (Dish dish) {
        this.dish = dish;
    }

    public void run() {
        for (int i = 0; i < 3; i++) {
            dish.waitForEmptyToFill();
        }
        dish.setShutDown(true);
    }
}

child

public class Child extends Thread {
    private Dish dish;
    public Child (Dish dish)
    {
        this.dish = dish;
    }
    public void run () {
        while (!dish.isTerminated()) {
            dish.waitForFullToEat();
            try {
                sleep(100);
            } catch (Exception ie) {
                System.out.println (ie.getMessage());
            }
        }
    }
}

输出:

Bird Thread-4 has eaten. The number of worms left is 9
Bird Thread-3 has eaten. The number of worms left is 8
Bird Thread-2 has eaten. The number of worms left is 7
Bird Thread-5 has eaten. The number of worms left is 6
Bird Thread-1 has eaten. The number of worms left is 5
Bird Thread-2 has eaten. The number of worms left is 4
Bird Thread-3 has eaten. The number of worms left is 3
Bird Thread-4 has eaten. The number of worms left is 2
Bird Thread-1 has eaten. The number of worms left is 1
Bird Thread-5 has eaten. The number of worms left is 0
Parent filled the dish
Bird Thread-4 has eaten. The number of worms left is 9
Bird Thread-5 has eaten. The number of worms left is 8
Bird Thread-3 has eaten. The number of worms left is 7
Bird Thread-1 has eaten. The number of worms left is 6
Bird Thread-2 has eaten. The number of worms left is 5
Bird Thread-4 has eaten. The number of worms left is 4
Bird Thread-5 has eaten. The number of worms left is 3
Bird Thread-1 has eaten. The number of worms left is 2
Bird Thread-2 has eaten. The number of worms left is 1
Bird Thread-3 has eaten. The number of worms left is 0
Parent filled the dish
Bird Thread-1 has eaten. The number of worms left is 9
Bird Thread-5 has eaten. The number of worms left is 8
Bird Thread-3 has eaten. The number of worms left is 7
Bird Thread-2 has eaten. The number of worms left is 6
Bird Thread-4 has eaten. The number of worms left is 5
Bird Thread-2 has eaten. The number of worms left is 4
Bird Thread-3 has eaten. The number of worms left is 3
Bird Thread-1 has eaten. The number of worms left is 2
Bird Thread-5 has eaten. The number of worms left is 1
Bird Thread-4 has eaten. The number of worms left is 0
Parent filled the dish
Bird Thread-2 has eaten. The number of worms left is 9
Bird Thread-3 has eaten. The number of worms left is 8
Bird Thread-1 has eaten. The number of worms left is 7
Bird Thread-5 has eaten. The number of worms left is 6
Bird Thread-4 has eaten. The number of worms left is 5
Bird Thread-2 has eaten. The number of worms left is 4
Bird Thread-3 has eaten. The number of worms left is 3
Bird Thread-1 has eaten. The number of worms left is 2
Bird Thread-5 has eaten. The number of worms left is 1
Bird Thread-4 has eaten. The number of worms left is 0
bids done eating :D

关于java - 为什么我的程序有时会卡住?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49004043/

相关文章:

java - Hibernate 条件与 Distinct 和 order by

java - 将文件中的对象添加到程序中

java - 如何在 ListIterator(反向)迭代期间正确添加对象?

向后打印字符串中每个单词的c程序

Java 集合。为什么没有原始类型?

java - 如何在 Vaadin 中映射表项

Java 6 线程 - "implements Runnable"和 "extends Thread"的不同行为

.net - 将记录标记为 'in use' 以支持多线程

python - fork 后正在运行的线程会发生什么情况?

java, spring boot 在运行时自动生成 getter 和 setter