The fact that it works at all is more luck than anything else.
A big part of the problem is that you're passing the same list instance to every asynchronous task handler and clearing it instead of creating a new one. So not only does every handler work with the same list of lines, the lines are cleared at the same time that the processing begins.
Let's first create a reusable collector that will batch your lines:
You can then very easily achieve what you want with the following code: