Java 此ConcurrentLinkedQueue/wait/notify算法正确吗?

Java 此ConcurrentLinkedQueue/wait/notify算法正确吗?,java,concurrency,locking,java.util.concurrent,Java,Concurrency,Locking,Java.util.concurrent,我知道,通常对于这样的生产者/消费者对,应该使用阻塞队列。这里我只想了解Java中更好的内存一致性,并发数据结构和锁之间的交互,以及确定ConcurrentLinkedQueue大小时的不精确性 问题是,下面的算法是否确保生成的任何东西都会被消耗,就像在普通的非线程安全队列中一样?注意:我运行了好几次,始终如此 import java.util.concurrent.ConcurrentLinkedQueue; public class Produce extends Thread {

我知道,通常对于这样的生产者/消费者对,应该使用阻塞队列。这里我只想了解Java中更好的内存一致性,并发数据结构和锁之间的交互,以及确定
ConcurrentLinkedQueue
大小时的不精确性

问题是,下面的算法是否确保生成的任何东西都会被消耗,就像在普通的非线程安全队列中一样?注意:我运行了好几次,始终如此

import java.util.concurrent.ConcurrentLinkedQueue;

public class Produce extends Thread {
    @Override
    public void run() {
        synchronized(Main.queue) {
            Main.queue.add(1);
            Main.queue.notifyAll();
        }
    }
}
public class Consume extends Thread {
    @Override
    public void run() {
        synchronized(Main.queue) {
            while(true) {
                while(!Main.queue.isEmpty()) {
                    Main.queue.poll();
                    System.out.println("consumed");
                }
                System.out.println("empty");
                try {
                    Main.queue.wait();
                } catch(InterruptedException e) {
                }
            }
        }
    }
}
public class Main {
    public static final ConcurrentLinkedQueue<Integer> queue =
            new ConcurrentLinkedQueue();
    public static void main(String[] args) {
        (new Consume()).start();
        (new Produce()).start();
    }
}
import java.util.concurrent.ConcurrentLinkedQueue;
公共类生成扩展线程{
@凌驾
公开募捐{
已同步(Main.queue){
Main.queue.add(1);
Main.queue.notifyAll();
}
}
}
公共类使用扩展线程{
@凌驾
公开募捐{
已同步(Main.queue){
while(true){
而(!Main.queue.isEmpty()){
Main.queue.poll();
系统输出打印项次(“已消耗”);
}
System.out.println(“空”);
试一试{
Main.queue.wait();
}捕捉(中断异常e){
}
}
}
}
}
公共班机{
公共静态最终ConcurrentLinkedQueue队列=
新建ConcurrentLinkedQueue();
公共静态void main(字符串[]args){
(新消费()).start();
(新产品()).start();
}
}

您的问题的答案是肯定的。消费者将看到所有更新

然而:

  • 这不是一个明智的实施。看起来您正在对wait/notify使用轮询方法,这样您就不需要一个繁忙的循环来等待队列变为非空。但更好(更简单、更有效)的方法是使用
    BlockingQueue
    代替,并使用blocking
    get()
    方法


    值得一提的是,您正在否定使用
    ConcurrentLinkedQueue
    的任何可能的可伸缩性优势,方法是使用queue对象作为互斥来执行等待/通知信令。(如果使用不同的对象作为互斥对象,这也适用。问题是互斥!)

  • 如果您打算这样做(无论出于何种原因),则
    notify()
    notifyAll()
    更可取。只有一个使用者能够使用您添加到队列中的(单个)元素。唤醒所有消费者是不必要的

  • 扩展
    线程
    不是一个好主意。更好的方法是将业务逻辑放入
    Runnable
    (或lambda),作为
    线程
    构造函数参数传递。阅读:


  • 您还对以下方面感兴趣:


    。。。确定
    ConcurrentLinkedQueue
    的大小时,不精确性到底是什么


    答案在for
    ConcurrentLinkedQueue
    中:

    请注意,与大多数集合不同,此方法不是固定时间操作。由于这些队列的异步性质,确定当前元素数需要进行O(n)遍历

    此外,如果在执行此方法期间添加或删除元素,则返回的结果可能不准确。因此,此方法在并发应用程序中通常不太有用


    换句话说,
    ConcurrentLinkedQueue
    统计队列元素,如果同时添加和删除元素,则不会给出准确的答案。

    您的问题的答案是肯定的。消费者将看到所有更新

    然而:

  • 这不是一个明智的实施。看起来您正在对wait/notify使用轮询方法,这样您就不需要一个繁忙的循环来等待队列变为非空。但更好(更简单、更有效)的方法是使用
    BlockingQueue
    代替,并使用blocking
    get()
    方法


    值得一提的是,您正在否定使用
    ConcurrentLinkedQueue
    的任何可能的可伸缩性优势,方法是使用queue对象作为互斥来执行等待/通知信令。(如果使用不同的对象作为互斥对象,这也适用。问题是互斥!)

  • 如果您打算这样做(无论出于何种原因),则
    notify()
    notifyAll()
    更可取。只有一个使用者能够使用您添加到队列中的(单个)元素。唤醒所有消费者是不必要的

  • 扩展
    线程
    不是一个好主意。更好的方法是将业务逻辑放入
    Runnable
    (或lambda),作为
    线程
    构造函数参数传递。阅读:


  • 您还对以下方面感兴趣:


    。。。确定
    ConcurrentLinkedQueue
    的大小时,不精确性到底是什么


    答案在for
    ConcurrentLinkedQueue
    中:

    请注意,与大多数集合不同,此方法不是固定时间操作。由于这些队列的异步性质,确定当前元素数需要进行O(n)遍历

    此外,如果在执行此方法期间添加或删除元素,则返回的结果可能不准确。因此,此方法在并发应用程序中通常不太有用


    换句话说,
    ConcurrentLinkedQueue
    对队列元素进行计数,如果同时添加和删除元素,则不会给出准确的答案。

    您的队列是线程安全的,不需要等待和通知。确实如此,但出于性能原因,我使用了
    wait()
    。要回答您的问题,是的,消费者会的