为什么我的消费者不会消耗整数值? (生产者 - 消费者等待和通知)

时间:2017-01-31 16:51:36

标签: java multithreading

我有两个主题。一个是生产者(for i in range(0, cols): for j in range(0, rows): x = np.append(a[i][j], b, axis = 1) ),第二个是消费者(class Deliver)。我想模仿门生产者。因此,生产者提供消费者可以生产门的木材。但我真的不知道如何在这两个线程之间进行通信。现在,当我运行我的程序时,只交付木材但不生产门。我不明白为什么。

class Produce

4 个答案:

答案 0 :(得分:1)

  

现在,当我运行我的程序时,只交付木材但不生产门。我不明白为什么

您的代码存在多个问题:

  1. 当您将实例方法标记为synchronized时,进入该方法的任何线程都将获得this上的锁定(即调用该方法的实例)。由于this中的Deliver引用了Deliver个实例,this中的Produce引用了Produce个实例,waitnotify调用在这种情况下几乎没用,因为他们对相同的对象不感兴趣。
  2. Java 中要记住的黄金法则是它使用按值传递语义。因此,原始值和引用始终按值传递。虽然您可能会认为DeliverProduce都将修改Integer传递给他们的同一main,但事实并非如此。
  3. 那就是说,我强烈建议您考虑使用像ArrayBlockingQueue之类的东西来解决这个问题,而不是使用waitnotify重新发明轮子。

答案 1 :(得分:0)

更改

if (wood == 10) { 

if (wood >= 10) { 

如果线程在== 10

时没有捕获它

答案 2 :(得分:0)

需要注意的是Integer是不可变的。

当您更改对整数的引用时,您正在创建一个与前一个对象无关的新对象。

你想要这个在两个线程之间共享的对象,所以当你改变值(而不是引用)时,它们会看到相同的值。

e.g。

wood -= 10;

相同
wood = Integer.valueOf(wood.intValue() - 10);

我建议您使用AtomicInteger并对其final进行引用,以确保您不会意外尝试更改参考。

安德鲁詹金斯建议;如果你锁定,通知/等待不相关的对象,你就没有任何线程安全。拥有共享对象后,您必须锁定,通知/等待该共享对象。

答案 3 :(得分:0)

考虑到Peter Lawrey关于使用AtomicInteger的建议,我会把我的解决方案放到混合中。

import java.util.concurrent.atomic.AtomicInteger;

public class Main {

    public static void main(String[] args) {
        AtomicInteger wood = new AtomicInteger(0);
        new Deliver(wood);
        new Produce(wood);
    }
}

public class Deliver implements Runnable {

    private static int MAX_STOCKPILE = 15;

    private final AtomicInteger wood;

    public Deliver(AtomicInteger wood) {
        this.wood = wood;
        new Thread(this, "Deliver").start();
    }

    public void deliver() throws InterruptedException{

        Thread.sleep(500);
        synchronized(wood) {
            if (wood.intValue() < MAX_STOCKPILE) {
                wood.addAndGet(1);
                System.out.println("Wood delivered" + " | Wood stockpile: " + wood);
                wood.notify();
            } else {
                wood.wait();
            }
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                deliver();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class Produce implements Runnable{

    private final AtomicInteger wood;

    public Produce(AtomicInteger wood) {
        this.wood = wood;
        new Thread(this, "Produce").start();
    }

    public void produce() throws InterruptedException{
        synchronized(wood) {
            if (wood.intValue() >= 10) {
                wood.addAndGet(-10); //produce
                System.out.println("Doors produced");
                wood.notify();
            }
            else {
                wood.wait();
            }
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                produce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

主要变化:

  • 我们使用可变对象在线程(AtomicInteger)之间进行通信。
  • 我们同步可变对象,而不是正在运行的线程。