Java 此ConcurrentLinkedQueue/wait/notify算法正确吗?
我知道,通常对于这样的生产者/消费者对,应该使用阻塞队列。这里我只想了解Java中更好的内存一致性,并发数据结构和锁之间的交互,以及确定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 {
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();
}
}
您的问题的答案是肯定的。消费者将看到所有更新
然而:
BlockingQueue
代替,并使用blockingget()
方法
值得一提的是,您正在否定使用
ConcurrentLinkedQueue
的任何可能的可伸缩性优势,方法是使用queue对象作为互斥来执行等待/通知信令。(如果使用不同的对象作为互斥对象,这也适用。问题是互斥!)
notify()
比notifyAll()
更可取。只有一个使用者能够使用您添加到队列中的(单个)元素。唤醒所有消费者是不必要的
线程
不是一个好主意。更好的方法是将业务逻辑放入Runnable
(或lambda),作为线程
构造函数参数传递。阅读:
您还对以下方面感兴趣:
。。。确定
ConcurrentLinkedQueue
的大小时,不精确性到底是什么
答案在for
ConcurrentLinkedQueue
中:
请注意,与大多数集合不同,此方法不是固定时间操作。由于这些队列的异步性质,确定当前元素数需要进行O(n)遍历
此外,如果在执行此方法期间添加或删除元素,则返回的结果可能不准确。因此,此方法在并发应用程序中通常不太有用
换句话说,
ConcurrentLinkedQueue
统计队列元素,如果同时添加和删除元素,则不会给出准确的答案。您的问题的答案是肯定的。消费者将看到所有更新
然而:
BlockingQueue
代替,并使用blockingget()
方法
值得一提的是,您正在否定使用
ConcurrentLinkedQueue
的任何可能的可伸缩性优势,方法是使用queue对象作为互斥来执行等待/通知信令。(如果使用不同的对象作为互斥对象,这也适用。问题是互斥!)
notify()
比notifyAll()
更可取。只有一个使用者能够使用您添加到队列中的(单个)元素。唤醒所有消费者是不必要的
线程
不是一个好主意。更好的方法是将业务逻辑放入Runnable
(或lambda),作为线程
构造函数参数传递。阅读:
您还对以下方面感兴趣:
。。。确定
ConcurrentLinkedQueue
的大小时,不精确性到底是什么
答案在for
ConcurrentLinkedQueue
中:
请注意,与大多数集合不同,此方法不是固定时间操作。由于这些队列的异步性质,确定当前元素数需要进行O(n)遍历
此外,如果在执行此方法期间添加或删除元素,则返回的结果可能不准确。因此,此方法在并发应用程序中通常不太有用
换句话说,
ConcurrentLinkedQueue
对队列元素进行计数,如果同时添加和删除元素,则不会给出准确的答案。您的队列是线程安全的,不需要等待和通知。确实如此,但出于性能原因,我使用了wait()
。要回答您的问题,是的,消费者会的