生产者消费者 - ExecutorService& ArrayBlockingQueue

时间:2012-05-01 02:30:18

标签: java multithreading concurrency producer-consumer blockingqueue

我想通过使用ExecutorService&amp ;;来了解我对生产者消费者设计的理解是否正确。 ArrayBlockingQueue。我知道有不同的方法来实现这个设计,但我想,最后,它取决于问题本身。

我不得不面对的问题是:我有一个生产者从大文件中读取(6GB);它逐行读取并将每一行转换为一个对象。它将对象放在ArrayBlockingQueue中。

消费者(少数)从ArrayBlockingQueue中获取对象并将其持久保存到数据库中。

现在,显然制作人比消费者快得多;将每一行转换为一个对象需要几分之一秒,但对于消费者来说需要更长的时间。

所以...如果我希望通过这样做来加速这个过程:我创建了两个分类为'ProducerThread'和'ConsumerThread'的共享ArrayBlockingQueue。在2之间协调的线程如下所示:

@Override
public void run()
{
    try{

        ArrayBlockingQueue<Ticket> queue = new ArrayBlockingQueue<Ticket>(40);
        ExecutorService threadPool = Executors.newFixedThreadPool(8);

        threadPool.execute(new SaleConsumerThread("NEW YORK", queue)); 
        threadPool.execute(new SaleConsumerThread("PARIS", queue));
        threadPool.execute(new SaleConsumerThread("TEL AVIV", queue));
        threadPool.execute(new SaleConsumerThread("HONG KONG", queue));
        threadPool.execute(new SaleConsumerThread("LONDON", queue));
        threadPool.execute(new SaleConsumerThread("BERLIN", queue));
        threadPool.execute(new SaleConsumerThread("AMSTERDAM", queue));

        Future producerStatus = threadPool.submit(new SaleProducerThread(progressBar, file, queue)); 
        producerStatus.get(); 
        threadPool.shutdown();   

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

我的问题是:

  1. 上面的设计是否会实际使用每个线程并发?我的电脑是两个2.4GHz四核。

  2. 我不确定Future和.get()的用途是什么?

  3. 顺便说一句,结果是快速的(考虑第一个版本是连续的,需要3小时)现在需要大约40分钟(但也许还有改进的余地)。

    感谢任何指针

2 个答案:

答案 0 :(得分:3)

我会看看等待IO花了多少时间以及CPU花费了多少时间。我怀疑你的主要瓶颈是数据库,你需要看看如何使导入更有效。您可以尝试对更新进行批处理,因为这可以提高吞吐量。

答案 1 :(得分:1)

数目:

  1. 我不确定“同时使用每个线程”是什么意思。但当然所有线程都可以并发执行。您的性能取决于您拥有的线程数以及数据的分区方式。您可以尝试使用线程数来尝试获得更好的结果,而不是为每个城市分配线程,也许您可​​以使用记录编号并将每个线程分配给记录编号的模数。假设您有10个线程,记录1,11,21等将转到线程1,2,22等线程2。这样,每个线程将获得相同数量的事务,因此您将完全利用线程,直到完成为止。
  2. Future是允许代码在事件完成时阻止。在这种情况下,get方法会返回SaleProducerThread的结果。