设置阅读器,解码器和消费者线程

时间:2013-06-11 07:01:09

标签: java multithreading

我有一个相当标准的生产者和消费者线程:

  • producer将文件中的字节读取并解码为阻塞队列。
  • 消费者正在从队列中轮询项目

Happenes认为解码过程是瓶颈,可能会因拥有更多CPU而受益。这是制片人时间的70%。如果我介绍“解码器”线程,我会获得任何显着的性能吗?

  • producer将文件中的字节读取到阻塞的“对象”队列
  • 解码器将字节对象解码为项目
  • 消费者正在轮询“已解码”的项目

由于内存占用,我需要使用一个队列 - 无法承受两个队列(字节/项),所以我猜对象“cast”开销会出现吗?

关于如何实现这个3线程解决方案的任何想法?

谢谢!

2 个答案:

答案 0 :(得分:0)

您应该为生产者和消费者调整线程池 - 例如,如果消费者对生产者来说太快,那么它的线程池可以分配比生产者线程池更少的线程。这应该导致吞吐量的显着增加。应调整生产者与消费者线程的比例(例3:1)。

在类似的行上,您可以有三个线程池,其中Producer(Reader)和Consumer具有较少的线程,而解码器(转换器)线程池具有更多的线程。我不确定您是否需要代码示例,在这种情况下您应该分享您目前拥有的代码。我将从生产者和消费者的大小为1的线程池和变换器(解码器)的大小5开始,然后测量瓶颈是什么(如果那时吞吐量符合您的期望)

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ProducerDecoderConsumer {
    /**
     * @param args
     */
    public static void main(String[] args) {
        BlockingQueue<Integer> inputQueue = new PriorityBlockingQueue<Integer>();
        BlockingQueue<String> outputQueue = new PriorityBlockingQueue<String>();
        ExecutorService reader = Executors.newSingleThreadExecutor();
        reader.submit(new Producer(inputQueue));
        ExecutorService decoder = Executors.newFixedThreadPool(5);
        decoder.submit(new Transformer(inputQueue, outputQueue));
        ExecutorService writer = Executors.newSingleThreadExecutor();
        writer.submit(new Consumer(outputQueue));

    }

    private static class Producer implements Callable<Void> {
        final BlockingQueue<Integer> queue;

        public Producer(final BlockingQueue<Integer> pQueue) {
            queue = pQueue;
        }

        @Override
        public Void call() throws Exception {
            try {
                Random random = new Random();
                while (true) {
                    queue.put(random.nextInt());
                }
            } catch (Exception e) {

            }
            return null;
        }
    }

    private static class Transformer implements Callable<Void> {
        final BlockingQueue<Integer> inputQueue;

        final BlockingQueue<String> outputQueue;

        public Transformer(final BlockingQueue<Integer> pInputQueue, final BlockingQueue<String> pOutputQueue) {
            inputQueue = pInputQueue;
            outputQueue = pOutputQueue;
        }

        @Override
        public Void call() throws Exception {
            try {
                while (true) {
                    Integer input = inputQueue.take();
                    String output = String.valueOf(input); // decode input to output
                    outputQueue.put(output); // output
                }
            } catch (Exception e) {

            }
            return null;
        }
    }

    private static class Consumer implements Callable<Void> {
        final BlockingQueue<String> queue;

        public Consumer(final BlockingQueue<String> pQueue) {
            queue = pQueue;
        }

        @Override
        public Void call() throws Exception {
            try {
                while (true) {
                    System.out.println(queue.take());
                }
            } catch (Exception e) {

            }
            return null;
        }
    }
}

我添加了一些代码来说明这个想法 - 我使用两个阻塞队列,不像你问题中提到的单个队列,因为我不认为只是有额外队列的开销 - 我会建议使用分析器来演示这样的事情。但是,我希望你发现它很有用,如果你真的觉得有需要,可以将它改装成单队列模型。

答案 1 :(得分:0)

2个队列,一个用于保存多个消费者解码的未解码对象。

多个消费者会将解码后的对象解码并写入第二个队列,最终消费者将从中消费。

确保避免死锁(使用notifyAll()而非notify(),除非您真的知道自己在做什么)