And I also don't think you are consuming the data very efficiently. You are consuming the data in the order in which they are submitted, rather than the order in which they return. Perhaps
you should change the way the tasks object is used. For example, make it a BlockingQueue implementation, and pass it to both the producer and consumer. The Producer can then put tasks into the queue directly, and the consumer takes tasks in the order they are available which may decrease time spent waiting for a specific producer.
One last thing... you might consider working on the balance between Producer and Consumer as well. Starting with your current
thread pool, turn your consumer into a Runnable which gets executed in the pool (takes one Thread from the Producer) and measure the results. Then add a second Consumer, and a third, etc... and see if there is some balance which optimizes performance. If the Consumer's job is processor-intensive, it could be that having multiple running while each producer is waiting on the database may provide better performance. And you don't necessarily have to limit yourself to 16 threads total. If your DB task is talking to a remote DB, and the DB operation takes some time then the Producers aren't using the processors while they wait on the DB - perfect time to allow something else to use the processor, like perhaps a Consumer or another Producer.