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