Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用多个线程(在池中)访问BlockingQueue未按预期并行工作_Java_Thread Safety_Java Threads_Blockingqueue - Fatal编程技术网

Java 使用多个线程(在池中)访问BlockingQueue未按预期并行工作

Java 使用多个线程(在池中)访问BlockingQueue未按预期并行工作,java,thread-safety,java-threads,blockingqueue,Java,Thread Safety,Java Threads,Blockingqueue,所以我有一个阻塞队列实现。其中一个调度程序以1秒的延迟向队列中放入一个随机数,我已经实现了另一个调度程序,其中包含10个线程池,用于从消息队列中调用take() 重要的是,我试图实现的场景是,在从队列中取出一个项目后,线程等待20秒(线程睡眠),我的理解是线程池中的其他9个线程将开始并行工作,而第一个线程等待20秒(其他线程也会等待20秒)但事实并非如此。池中的其他线程似乎根本没有启动。我是阻止队列的新手,任何帮助都将不胜感激 我的代码如下 公共类阻塞队列impl{ public Queue&l

所以我有一个阻塞队列实现。其中一个调度程序以1秒的延迟向队列中放入一个随机数,我已经实现了另一个调度程序,其中包含10个线程池,用于从消息队列中调用take()

重要的是,我试图实现的场景是,在从队列中取出一个项目后,线程等待20秒(线程睡眠),我的理解是线程池中的其他9个线程将开始并行工作,而第一个线程等待20秒(其他线程也会等待20秒)但事实并非如此。池中的其他线程似乎根本没有启动。我是阻止队列的新手,任何帮助都将不胜感激

我的代码如下

公共类阻塞队列impl{

public Queue<Integer> messageQueue = new ConcurrentLinkedDeque();

private void putNumber(Integer number){
   try{
       System.out.println("putting number to the queue: " + number);
       messageQueue.add(number);
       System.out.println("size of the queue: " +messageQueue.size());

   } catch (Exception e){
       e.printStackTrace();
   }
}

private void getNumber(){

}


private class RunnableGetImpl implements Runnable {

    @Override
    public void run() {
        try{
            Integer num = messageQueue.poll();
            System.out.println("Polling from queue, number - "+ num);
            if(num!=null){
                System.out.println("Sleeping thread for 20 sec"+Thread.activeCount());
                Thread.sleep(20000);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


private class RunnablePutImpl implements Runnable {

    @Override
    public void run() {
        Random rand = new Random();
        int n = rand.nextInt(100);
        n += 1;
        putNumber(n);


    }


}

public static void main(String[] args){

    BlockingQueueImpl blockingQueue = new BlockingQueueImpl();


    ScheduledExecutorService executor1 = Executors.newScheduledThreadPool(1);
    executor1.scheduleAtFixedRate(blockingQueue.new RunnablePutImpl(), 0, 1000, TimeUnit.MILLISECONDS);

    ScheduledExecutorService executor2 = Executors.newScheduledThreadPool(20);
    executor2.scheduleAtFixedRate(blockingQueue.new RunnableGetImpl(), 0, 100, TimeUnit.MILLISECONDS);

}
public Queue messageQueue=new concurrentlinkedque();
专用无效putNumber(整数){
试一试{
System.out.println(“将编号放入队列:“+number”);
messageQueue.add(编号);
System.out.println(“队列的大小:+messageQueue.size());
}捕获(例外e){
e、 printStackTrace();
}
}
私有void getNumber(){
}
私有类RunnableGetImpl实现Runnable{
@凌驾
公开募捐{
试一试{
整数num=messageQueue.poll();
System.out.println(“来自队列的轮询,编号-”+num);
如果(num!=null){
System.out.println(“休眠线程20秒”+thread.activeCount());
睡眠(20000);
}
}捕获(例外e){
e、 printStackTrace();
}
}
}
私有类RunnablePutImpl实现Runnable{
@凌驾
公开募捐{
Random rand=新的Random();
int n=兰特·耐克斯汀(100);
n+=1;
putNumber(n);
}
}
公共静态void main(字符串[]args){
BlockingQueueImpl blockingQueue=新建BlockingQueueImpl();
ScheduledExecutorService executor1=执行者。newScheduledThreadPool(1);
Executor 1.scheduleAtFixedRate(blockingQueue.new RunnablePutImpl(),0,1000,时间单位为毫秒);
ScheduledExecutorService executor2=执行者。newScheduledThreadPool(20);
executor2.scheduleAtFixedRate(blockingQueue.new RunnableGetImpl(),0100,TimeUnit.millides);
}

}来自
ScheduledThreadPoolExecutor.scheduleAtFixedRate的JavaDoc:

如果此任务的任何执行时间超过其周期,则 后续执行可能会延迟开始,但不会同时执行 执行

因此,您需要启动(安排)您想要/需要的工人数量

在寻找更好的解决方案时,请注意您实际上并没有使用
阻塞队列

您没有实现
java.util.concurrent.Blockingqueue
,也没有使用它的实现。
concurrentLinkedQueue
只是一个集合,它甚至没有实现
Queue

ConcurrentLinkedQue.poll()
不会阻塞,如果队列为空,则只返回
null

以下是用于
BlockingQueue
接口的JavaDocs:

使用
put()
向队列提供一个值。如果
BlockingQueue
已达到其最大容量,则该操作将被阻止。 使用
take()

正确使用这些类将提高应用程序的性能,因为您不会一直轮询某个值

关于类似问题的答案中提供了更多详细信息:

更新:具有多个生产者/消费者的示例代码

以下示例代码复制自我与之无任何关联的代码:

下面的代码展示了多个生产者/消费者程序。生产者线程和消费者线程共享同一个全局队列

import java.util.concurrent.*;
import java.util.Random;

public class ProducerConsumerWithES {
    public static void main(String args[]) {
        BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();
         
        ExecutorService pes = Executors.newFixedThreadPool(2);
        ExecutorService ces = Executors.newFixedThreadPool(2);
          
        pes.submit(new Producer(sharedQueue, 1));
        pes.submit(new Producer(sharedQueue, 2));
        ces.submit(new Consumer(sharedQueue, 1));
        ces.submit(new Consumer(sharedQueue, 2));
         
        pes.shutdown();
        ces.shutdown();
    }
}

/* Different producers produces a stream of integers continuously to a shared queue, 
which is shared between all Producers and consumers */

class Producer implements Runnable {
    private final BlockingQueue<Integer> sharedQueue;
    private int threadNo;
    private Random random = new Random();
    public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
        this.threadNo = threadNo;
        this.sharedQueue = sharedQueue;
    }
    @Override
    public void run() {
        // Producer produces a continuous stream of numbers for every 200 milli seconds
        while (true) {
            try {
                int number = random.nextInt(1000);
                System.out.println("Produced:" + number + ":by thread:"+ threadNo);
                sharedQueue.put(number);
                Thread.sleep(200);
            } catch (Exception err) {
                err.printStackTrace();
            }
        }
    }
}
/* Different consumers consume data from shared queue, which is shared by both producer and consumer threads */
class Consumer implements Runnable {
    private final BlockingQueue<Integer> sharedQueue;
    private int threadNo;
    public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
        this.sharedQueue = sharedQueue;
        this.threadNo = threadNo;
    }
    @Override
    public void run() {
        // Consumer consumes numbers generated from Producer threads continuously
        while(true){
            try {
                int num = sharedQueue.take();
                System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
            } catch (Exception err) {
               err.printStackTrace();
            }
        }
    }   
}
请注意如何将多个生产者和消费者添加到池中—您需要尽可能多的生产者和消费者才能并行工作。这是您的代码缺少的关键—多个工作者。调度程序将对其进行调度,但不会神奇地将您要求它调度的单个实例相乘


显然,您需要根据您的需求调整生产者和消费者的数量。

您正在执行
new BlockingQueueImpl()
两次,这样这些可运行程序就不会共享封闭类的同一个实例,所以它们不会使用同一个队列。@michalk即使我使用同一个BlockingQueueImpl实例,问题仍然是一样的。您介意更新您的问题以反映对@michalk的评论所做的代码更改吗?@ThomasTimbul It is Edit:)来自
scheduleAtFixedRate
的JavaDoc:“如果此任务的任何执行时间超过其周期,则后续执行可能会延迟开始,但不会同时执行。”我明白了,那么实现我正在尝试的任务的方法是什么。我有一个场景,特别是计划任务是一个阻塞操作,需要一些时间才能完成。是否有任何其他实现可以用于使用线程池并发处理队列,而不会仅仅因为线程池阻塞而阻塞所有其他线程
Produced:69:by thread:2
Produced:553:by thread:1
Consumed: 69:by thread:1
Consumed: 553:by thread:2
Produced:41:by thread:2
Produced:796:by thread:1
Consumed: 41:by thread:1
Consumed: 796:by thread:2
Produced:728:by thread:2
Consumed: 728:by thread:1