繁体   English   中英

java中线程的等待和通知顺序

[英]sequence of wait and notify of threads in java

我写了一个生产者/消费者程序,如下所示。

 package com.myjava.concurrency.basics.waitnotify;
 import java.util.PriorityQueue;
 import java.util.Queue;

public class SharedObject {

private Queue<String> dataObject;

private final Object objLock = new Object();

public SharedObject() {
    dataObject = new PriorityQueue<String>(1);
}

public void writeData(String data) {
    synchronized (objLock) {
        while (!dataObject.isEmpty()) {
            System.out.println("Producer:Waiting");
            try {
                objLock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        dataObject.offer(data);
        System.out.println(String.format("%s : %s", 
        Thread.currentThread().getName(), data));
        objLock.notify();
    }
}

public String readData() {
    String result = null;
    synchronized (objLock) {
        while (dataObject.isEmpty()) {
            System.out.println("Consumer:Waiting");
            try {
                objLock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        result = dataObject.poll();
        System.out.println(String.format("%s : %s", 
        Thread.currentThread().getName(), result));
        objLock.notify();
    }
    return result;
}
}


 package com.myjava.concurrency.basics.waitnotify;

 import java.util.Arrays;
 import java.util.List;

 public class TestWaitNotify {

public static void main(String[] args) {

    SharedObject sharedObject = new SharedObject();

    List<String> fruitsList = Arrays.asList("Apple", "Banana", "Orange");
    int listSize = fruitsList.size();

    Thread producer = new Thread(() -> {
        System.out.println("producer thread started");
        fruitsList.forEach(p -> {
            sharedObject.writeData(p);
        });
    }, "producer");

    Thread consumer = new Thread(() -> {
        System.out.println("consumer thread started");
        for (int i = 0; i < listSize; i++) {
            sharedObject.readData();
        }
    }, "consumer");

    consumer.start();
    producer.start();

}
}

我得到了输出,如下所示:

 producer thread started
 consumer thread started
 Consumer:Waiting
 producer : Apple
 Producer:Waiting
 consumer : Apple
 Consumer:Waiting
 producer : Banana
 Producer:Waiting
 consumer : Banana
 Consumer:Waiting
 producer : Orange
 consumer : Orange

这是我的问题:

我预计以下顺序,与这个程序:

     producer thread started
     consumer thread started
     Consumer:Waiting  // assuming consumer thread begins first
     producer : Apple
     consumer : Apple
     producer : Banana
     consumer : Banana
     producer : Orange
     consumer : Orange

只有消费者线程应该只进入等待模式一次。 第一次通知后,线程不应该进入while循环,因为当生产者线程有对象锁时,消费者应该等待锁,当消费者释放锁时,生产者应该获取锁。

任何帮助表示赞赏。

Object.notify() 将唤醒一个等待锁的线程,但它不一定优先获取下一个,并且 javadoc 识别了这种行为:

被唤醒的线程将无法继续,直到当前线程放弃对该对象的锁定。 被唤醒的线程将以通常的方式与可能正在积极竞争以同步此对象的任何其他线程进行竞争; 例如,被唤醒的线程在成为下一个锁定该对象的线程方面没有可靠的特权或劣势

可能正在发生的事情是刚刚放弃锁的线程立即在您期望的线程之前再次获取它。 如果您在通知之后(但不在同步块中)休眠,您可能会看到您期望的输出。 在这个原因中,您强制该线程有效地让位于已通知的另一个线程。

检查本教程可能会对您有所帮助,它似乎与您的问题非常相似,即使它与您的示例的唯一区别是方法标志他们顺便说一下synchronized关键字。

https://www.tutorialspoint.com/javaexamples/thread_procon.htm

这里:

while (dataObject.isEmpty()) {
  System.out.println("Consumer:Waiting");

消费者消费一个条目。 但与此同时,队列被锁定,因此在此期间不能添加任何内容。

所以生产者必须等待消费者消费,然后消费者必须等待生产者放入新的东西。

因此下面的假设

只有消费者线程应该只进入等待模式一次。

是错的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM