0

我不明白为什么我在这个简单的示例中陷入僵局。它有什么问题?

public static void main(String[] args) {
        Object data = null;
        new Thread(new Producer(data)).start();
        new Thread(new Consumer(data)).start();
    }
}

class Producer implements Runnable {
    private Object data;

    public Producer(Object data) {
        this.data = data;
    }

    @Override
    public void run() {
        while (true) {
            while (data != null) {}
            data = new Object();
            System.out.println("put");
        }
    }
}

class Consumer implements Runnable {
    private Object data;

    public Consumer(Object data) {
        this.data = data;
    }

    @Override
    public void run() {
        while (true) {
            while (data == null) {  }
            data = null;
            System.out.println("get");
        }
    }
4

5 回答 5

3

有两个问题。

1:您有两个独立的 Runnable,每个都有自己的私有内部成员,名为 data。对其中一个所做的更改对另一个不可见。如果要在两个线程之间传递数据,则需要将其存储在它们都可以访问它的公共位置。您还需要围绕访问同步或使引用易变。

2:您的支票似乎倒转了。您可能想在它不为空时将其设为空,并在它为空时创建一个?很难说出你想要它在那里实际做什么!:)

public static volatile Object data;

public static void main(String[] args) {
        data = null;
        new Thread(new Producer(data)).start();
        new Thread(new Consumer(data)).start();
    }
}

class Producer implements Runnable {

    public Producer(Object data) {
        this.data = data;
    }

    @Override
    public void run() {
        while (true) {
            while (data == null) {}
            data = new Object();
            System.out.println("put");
        }
    }
}

class Consumer implements Runnable {

    public Consumer(Object data) {
        this.data = data;
    }

    @Override
    public void run() {
        while (true) {
            while (data != null) {  }
            data = null;
            System.out.println("get");
        }
    }

(此外,这并不是我们定义为死锁的经典示例,其中两个线程无法继续,因为它们都想要另一个锁。这里没有锁。这是两个无限循环的示例只是什么都不做。)

于 2012-04-04T17:46:30.940 回答
2

每个实例都有自己的data字段。
消费者永远不会看到生产者的变化。

于 2012-04-04T17:44:09.660 回答
2

消费者和生产者有不同的数据字段,所以消费者永远不会得到任何数据来消费。

此外,在字段上自旋锁定消费者/生产者通常不是一个好主意,最好使用互斥锁或信号量来表示数据的可用性/发布的可能性。如果这不仅仅是搜索知识的测试,那么您应该真正阅读如何使用这两者。

于 2012-04-04T17:44:53.453 回答
1

当您生产的“生产”时,它所做的只是将自己的data引用指向新对象,而消费者无法知道发生了什么。你可以做的就是制作另一个课程

class Data {
    private Object data = null;
    synchronized void set( Object data ){ this.data = data; }
    synchronized Object get(){ return data; }
}

然后在你的主要做

Data data = new Data();

将“数据”对象传递给消费者和生产者,并使用 get/set 方法而不是赋值。

这样,消费者和生产者都将指向同一个Data对象,当生产者生产或消费者消费时,他们将更改他们正在共享的 Data 对象中的引用。

于 2012-04-04T17:51:30.943 回答
1

我认为这应该做你想要的(它仍然是糟糕的代码):

public class Example {
    public static void main(String[] args) {
        Consumer consumer = new Consumer();
        new Thread(new Producer(consumer)).start();
        new Thread(consumer).start();
    }
}

class Producer implements Runnable {
    private final Consumer consumer;

    public Producer(Consumer consumer) {
        this.consumer = consumer;
    }

    @Override
    public void run() {
        while (true) {
            while (consumer.data != null) {}
            consumer.data = new Object();
            System.out.println("put");
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    public volatile Object data;

    @Override
    public void run() {
        while (true) {
            while (data == null) {}
            data = null;
            System.out.println("get");
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我认为您应该关注 Java 的基础知识,然后再学习诸如并行编程之类的高级主题,因为示例中的主要错误(单独的数据字段)非常基础。

于 2012-04-04T18:00:41.433 回答