java多线程生产者-消费者混淆结果

问题描述 投票:0回答:1

我是Java多线程的初学者。这里有一个关于生产者-消费者模型和

wait
notifyAll
方法的演示代码,但是我发现结果很难理解。

public class ProducerConsumerExample {
    public static void main(String[] args) {

        SharedResource sharedResource = new SharedResource();

        Thread producerThread = new Thread(new Producer(sharedResource));
        Thread consumerThread = new Thread(new Consumer(sharedResource));

        producerThread.start();
        consumerThread.start();

    }
}


class SharedResource {
    private int content;

    private boolean available = false;


    public synchronized void put(int value) {
        while (available) {
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        content = value;
        available = true;
        notifyAll();
    }

    public synchronized int get() {
        while (!available) {
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        available = false;
        notifyAll();
        return content;
    }

}

class Producer implements Runnable {

    private final SharedResource resource;

    Producer(SharedResource resource) {
        this.resource = resource;
    }


    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            resource.put(i);
            System.out.println("Produced: " + i);
        }


    }
}


class Consumer implements Runnable {

    private final SharedResource resource;

    Consumer(SharedResource resource) {
        this.resource = resource;
    }


    @Override
    public void run() {

        for (int i = 0; i < 10; i++) {
            System.out.println("Consumed: " + resource.get());
        }

    }
}

实际运行结果如下

Produced: 0
Produced: 1
Consumed: 0
Consumed: 1
Produced: 2
Produced: 3
Consumed: 2
Consumed: 3
Consumed: 4
Produced: 4
Produced: 5
Produced: 6
Consumed: 5
Consumed: 6
Consumed: 7
Produced: 7
Consumed: 8
Produced: 8
Produced: 9
Consumed: 9

这样的结果令人愤慨。我相信结果应该是生产者的

put
和消费者的
get
连续执行。换句话说,结果应该是这样的。

Produced: 0
Consumed: 0
Produced: 1
Consumed: 1
...

我认为流程应该是这样的:

  • 生产者执行

    put(0)
    ,

  • 此时

    available
    false
    。然后,
    available
    设置为
    true
    ,内容的值也设置为
    0

  • 接下来,

    notifyAll()
    被执行。

  • 此时,消费者线程可能还没有进入等待状态,但这不会对结果产生太大影响。

  • 接下来,应该执行

    put(1)
    。此时,由于
    available
    的值为
    true
    ,因此进入while循环,然后执行
    wait()
    方法。

  • 此时,生产者线程进入等待状态并释放锁。消费者线程在获取锁并看到

    available
    true
    后,不会进入 while 循环。

  • 然后将

    available
    设置为
    false
    并调用
    notifyAll()
    将生产者线程置于阻塞状态,同时返回内容的值。

  • 假设生产者线程此时获得了锁并继续执行

    put(1)
    (即使消费者线程获得了锁并执行
    get(1)
    ,也没有关系,因为它会进入while循环并调用
     wait()
    方法,让生产者线程继续执行
    put(1)
    ),

如此循环。

此外,还有更离谱的结果;这次,消费者线程的结果甚至被先打印出来,像这样:

Consumed: 0
Produced: 0
Produced: 1
Produced: 2
Consumed: 1
Consumed: 2
Consumed: 3
...

有人可以解释一下这些结果到底是怎么回事吗?为什么和我想象的不一样?

java multithreading
1个回答
0
投票

问题的答案不是

synchronized
方法内部发生的事情 - 而是这些方法之外发生的事情。

synchronized
方法之外的操作在线程之间不排序。

一个可能的有效序列是:

  • 生产者线程调用
    put(0)
    ,然后写出“Produced:0”,然后调用
    put(1)
    并且必须等待消费者
  • 消费者调用
    get()
    ,但从
    get()
    返回后立即被暂停 - 在它可以打印任何内容之前
  • 生产者完成
    put(1)
    ,然后写出“Produced:1”,然后调用
    put(2)
    并且必须再次等待消费者
  • 现在消费者可以写出“Consumed: 0”

另一个可能的有效序列是:

  • 生产者线程调用
    put(0)
    ,之后它在打印任何内容之前被挂起
  • 消费者线程调用
    get()
    ,然后写出“Consumed:0”,然后再次调用
    get()
    并且必须等待生产者
  • 生产者现在已恢复,打印出“Produced: 0”,然后调用
    put(1)
© www.soinside.com 2019 - 2024. All rights reserved.