Search code examples
javaconcurrencyexecutorservicereentrantlock

Ordered write to the same file with ExecutorService


I'm trying to instantiate tasks in a ExecutorService that need to write to file in order,so if there exist 33 tasks they need to write in order...

I've tried to use LinkedBlockingQueue and ReentrantLock to guarantee the order but by what I'm understanding in fair mode it unlock to the youngest of the x threads ExecutorService have created.

private final static Integer cores =      Runtime.getRuntime().availableProcessors();
private final ReentrantLock lock = new ReentrantLock(false);
private final ExecutorService taskExecutor;

In constructor

taskExecutor = new ThreadPoolExecutor
        (cores, cores, 1, TimeUnit.MINUTES, new LinkedBlockingQueue());

and so I process a quota of a input file peer task

if(s.isConverting()){
   if(fileLineNumber%quote > 0) tasks = (fileLineNumber/quote)+1;
   else tasks = (fileLineNumber/quote);
   for(int i = 0 ; i<tasks || i<1 ; i++){
      taskExecutor.execute(new ConversorProcessor(lock,this,i));
   }
}

the task do

public void run() {
    getFileQuote();
    resetAccumulators();
    process();
    writeResult();
}

and my problem ocurre here:

private void writeResult() {
    lock.lock();
    try {
        BufferedWriter bw = new BufferedWriter(new FileWriter("/tmp/conversion.txt",true));
        Integer index = -1;
        if(i == 0){
            bw.write("ano dia tmin tmax tmed umid vento_vel rad prec\n");
        }
        while(index++ < getResult().size()-1){
            bw.write(getResult().get(index) + "\n");
        }
        if(i == controller.getTasksNumber()){ 
            bw.write(getResult().get(getResult().size()-1));
        }
        else{ 
            bw.write(getResult().get(getResult().size()-1) + "\n");
        }
        bw.close();
    } catch (IOException ex) {
        Logger.getLogger(ConversorProcessor.class.getName()).log(Level.SEVERE, null, ex);
    } finally { 
        lock.unlock(); 
    }

}

Solution

  • It appears to me that everything needs to be done concurrently except the writing of the output to file, and this must be done in the object creation order.

    I would take the code that writes to the file, the writeResult() method, out of your threading code, and instead create Futures that returned Strings that are created by the process() method, and load the Futures into an ArrayList<Future<String>>. You then could iterate through the ArrayList, in a for loop calling get() on each Future, and writing the result to your text file with your BufferedWriter or PrintWriter.