简体   繁体   English

批量Java生产者使用者

[英]java producer consumer in batches

I am facing a problem in producer - consumer. 我在生产者-消费者中面临一个问题 My requirement is: 我的要求是:

Producer produces 100 objects together and wait for consumer to consume. 生产者共同生产100个对象,并等待消费者消费。 Then Consumer consumes those 100 objects and wait for producer to produce. 然后,消费者消耗这100个对象并等待生产者生产。 And this process repeats. 并重复此过程。

The condition is that, producer should not produce until objects size is 0, and consumer should not consume until objects size is 100. ie . 条件是,生产者在对象大小为0之前不应该生产,而消费者在对象大小为100之前不应该消费。 producing and consuming in batches of size 100 only. 仅批量生产和消费100。

class Producer extends Thread {
private Queue<Integer> queue;
private int maxSize;

public Producer(Queue<Integer> queue, int maxSize, String name) {
    super(name);
    this.queue = queue;
    this.maxSize = maxSize;
}

@Override
public void run() {
    while (true) {
        synchronized (queue) {
            while (queue.size() == maxSize) {
                try {
                    System.out.println("Queue is full, "
                            + "Producer thread waiting for "
                            + "consumer to take something from queue");
                    queue.wait();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            Random random = new Random();
            int i = random.nextInt();
            System.out.println("Producing value : " + i);
            queue.add(i);
            queue.notifyAll();
        }
    }
}

} }

class Consumer extends Thread {
private Queue<Integer> queue;
private int maxSize;

public Consumer(Queue<Integer> queue, int maxSize, String name) {
    super(name);
    this.queue = queue;
    this.maxSize = maxSize;
}

@Override
public void run() {
    while (true) {
        synchronized (queue) {
            while (queue.isEmpty()) {
                System.out.println("Queue is empty,"
                        + "Consumer thread is waiting"
                        + " for producer thread to put something in queue");
                try {
                    queue.wait();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
            System.out.println("Consuming value : " + queue.remove());
            queue.notifyAll();
        }
    }
}

} }

public class ProdConsReference {
public static void main(String args[]) { 
    Queue<Integer> buffer = new LinkedList<Integer>(); 
    int maxSize = 10; 
    Thread producer = new Producer(buffer, maxSize, "PRODUCER"); 
    Thread consumer = new Consumer(buffer, maxSize, "CONSUMER"); 
    producer.start(); 
    consumer.start(); 
    }
}

output : 输出:

      Queue is empty,Consumer thread is waiting for producer thread to put                             something in queue
      Producing value : 52648529
      Consuming value : 52648529
      Queue is empty,Consumer thread is waiting for producer thread to put something in queue
      Producing value : -2128028718
      Consuming value : -2128028718

Can anybody point out what I am exactly missing. 谁能指出我到底想念什么。 Thanks in advance 提前致谢

I am assuming an excercise, so this is my 2 cents: 我正在做运动,所以这是我的2美分:

You are notifying the other thread after each add/remove. 每次添加/删除后,您将通知另一个线程。 You should not do that. 你不应该那样做。

What you want to do is: 您想要做的是:

Producer: 制片人:

  1. Check if Queue is empty. 检查队列是否为空。
  2. If yes : Produce 100 items (not 1!) , then notify consumers, jump to 4. 如果是:生产100件商品(不是1!),然后通知消费者,跳到4。
  3. If not: Wait to be notified 如果没有,请等待通知
  4. Loop to 1. (not 2.!) 循环到1.(不是2.!)

Consumer: 消费者:

  1. Check if Queue is full. 检查队列是否已满。
  2. If yes: Consume until Queue is empty , then notify producers. 如果是:消费直到Queue为空 ,然后通知生产者。 jump to 4. 跳到4。
  3. If not: Wait to be notified 如果没有,请等待通知
  4. Loop to 1. (not 2.!) 循环到1.(不是2.!)

You may want to use Conditions . 您可能要使用条件

If this is not an exercise / assignment 如果这不是练习/作业

Then you should take a look at zapl's approach, he gave in comment: Use a Queue of Lists which represent batches of 100 items. 然后,您应该看看zapl的方法,他在评论中说道:使用代表100个批次的列表列表。

Shared: Have work queue (threadsafe Datastructure, I suggest a blocking one). 共享:有工作队列(线程安全数据结构,我建议阻塞一个)。

Producer: 制片人:

  • Take Batchsize and total of "Tasks" or Items to be processed. 取Batchsize和“任务”或要处理项目的总数。 I am assuming that total is divisible be batchsize. 我假设总数是整除的批大小。 Otherwise you'll have to take that into account when producing. 否则在制作时必须考虑到这一点。
  • Produce <batchsize> Items into a List (=batch) 将<batchsize>个项目产生到一个列表中(= batch)
  • Enqueue the batch (List of items) in workQueue 将批处理(项目列表)放入workQueue
  • Repeat the former 2 steps until total is reached. 重复前两个步骤,直到达到总数。

Consumer(s): 消费者:

  • Take batch from workqueue (if/as soon as available) 从工作队列中进行批量处理(如果有/尽快)
  • Process all items in batch 批量处理所有项目

Mind that if you must keep the order you can either only use one consumer or take extra effort to enforce sorting of the result. 请注意,如果您必须保留订单,则只能使用一位消费者,也可以花费额外的精力来对结果进行排序。

Thnx for your valuable comments and suggestions. 感谢您的宝贵意见和建议。 I cannot understand why LinkedList usage is discouraged here. 我不明白为什么不鼓励使用LinkedList。 In my real time project, my productionCount will be more than millions, and this I have to process in batches of 10000. Below link was also helpful. 在我的实时项目中,我的productionCount将超过数百万,并且我必须按10000的批次进行处理。下面的链接也有帮助。 How to know if other threads have finished? 如何知道其他线程是否已完成?

Here is my implementation using only 2 threads. 这是我仅使用2个线程的实现。 One Producer & other main thread itself as Consumer 一个生产者和其他主线程本身作为消费者

            package threading;

            import java.util.LinkedList;
            import java.util.Queue;
            import java.util.Set;
            import java.util.concurrent.CopyOnWriteArraySet;


            public class ProdConsumerApp implements ThreadCompleteListener{
                boolean isProductionOver;
                public static void main(String args[]) {
                    ProdConsumerApp prodConsumerApp = new ProdConsumerApp();
                    prodConsumerApp.procudeAndConsume();
                }

                private void procudeAndConsume(){
                    Queue<Integer> buffer = new LinkedList<Integer>(); 
                    int maxSize = 100; 
                    int productionCount = 1000;

                    Producer producer = new Producer(buffer, maxSize, "PRODUCER", productionCount); 
                    producer.addListener(this);
                    producer.start(); 
                    consume(buffer);

                    System.out.println("Bye");
                }

                public void consume(Queue<Integer> queue){
                    while(!isProductionOver){//check whether production completed?
                        synchronized (queue) {
                            //when queue size is 0, notify and wait.
                            while(queue.isEmpty()){
                                try {
                                    queue.notify();
                                    queue.wait();
                                } catch (Exception ex) {
                                    ex.printStackTrace();
                                }
                            }
                            //consume until queue is empty.
                            while(!queue.isEmpty()){
                                System.out.println("Consuming value : " + queue.remove());
                            }
                        }
                    }
                }

                @Override
                public void notifyOfThreadComplete(Thread thread) {
                    System.out.println("notified");
                    isProductionOver = true;
                }

            }

            class Producer extends Thread {
                private Queue<Integer> queue;
                private int maxSize;
                private int productionCount;

                public Producer(Queue<Integer> queue, int maxSize, String name, int productionCount) {
                    super(name);
                    this.queue = queue;
                    this.maxSize = maxSize;
                    this.productionCount = productionCount;
                }

                private final Set<ThreadCompleteListener> listeners = new CopyOnWriteArraySet<ThreadCompleteListener>();

                public final void addListener(final ThreadCompleteListener listener) {
                    listeners.add(listener);
                }
                public final void removeListener(final ThreadCompleteListener listener) {
                    listeners.remove(listener);
                }
                private final void notifyListeners() {
                    for (ThreadCompleteListener listener : listeners) {
                        listener.notifyOfThreadComplete(this);
                    }
                }

                @Override
                public void run() {
                    synchronized (queue) {
                        for(int i=1;i<=productionCount;i++){
                            System.out.println("Producing value : " + i);
                            queue.add(i);

                            //when queue size is maxSize, notify and wait.
                            while(queue.size() == maxSize){
                                try {
                                    queue.notify();
                                    if(i==productionCount){
                                        //if last item is produced, notify listeners that production is completed.
                                        notifyListeners();
                                        //exit from while() and later for() and thereby terminating Producer.
                                        break;
                                    }
                                    queue.wait();
                                } catch (Exception ex) {
                                    ex.printStackTrace();
                                }
                            }
                        }           
                    }
                }

            }


            interface ThreadCompleteListener {
                void notifyOfThreadComplete(final Thread thread);
            }

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

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