为什么我会陷入僵局

时间:2012-04-04 17:40:08

标签: java

我无法理解为什么我在这个简单的样本中遇到了死锁。它出了什么问题?

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");
        }
    }

5 个答案:

答案 0 :(得分:3)

有两个问题。

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

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");
        }
    }

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

答案 1 :(得分:2)

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

答案 2 :(得分:2)

消费者和生产者具有单独的数据字段,因此消费者永远不会获得任何数据。

此外,在字段上对消费者/制作人进行自动锁定通常不是一个好主意,您 更好地使用互斥锁或信号量来表示可用性数据/发布的可能性。如果这不仅仅是搜索知识的测试,那么你应该真正了解如何使用这两者。

答案 3 :(得分: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对象中的引用。

答案 4 :(得分: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的基础知识,因为您的示例中的主要错误(单独的数据字段)非常基础。