简体   繁体   中英

How do I output from multiple threads to a .txt file?

This is my current thread, I use it to stress test the CPU, I need to output the "Hcount" every hour to a .txt file, currently, it will print it but only from one thread ,when another hour passes it deletes what is written on the .txt file and rewrite the new "Hcount" I'm Running 3 threads.

import java.util.Random;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class MyThread extends Thread{
    public void run() {
        String B;//Will hold the value of Cpointer
        String A;//will hold the string value of Hcount
        Path fileName =
                Path.of("D:/EEoutput/Out.txt");
        Random rand = new Random();
        long Hcount = 0;//counts the number of iterations in an hour
        long t = System.currentTimeMillis();
        long end = t + 3800000*5;//a minute
        double a1 = 0; //random holder 1
        double a2 = 0;//random holder 2
        double answer = 0; // answer placeholder
        Long hour = System.currentTimeMillis()+3600000;//will be used to say when are we outputing the number of iterations to the file
        int Cpointer = 1;//will tell how many hours has passed
        while (System.currentTimeMillis() < end) {
            a1 = rand.nextDouble();
            a2 = rand.nextDouble();
            answer = a1 * 23 / (a2 + a1) + a2;
            Hcount++;
            if (System.currentTimeMillis() >= hour)// checks if the program needs to
            {
                 B = String.valueOf(Cpointer);
                 A=String.valueOf(Hcount);
                try {
                    Files.writeString(fileName, A);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                hour = System.currentTimeMillis()+3600000;//sets stop to next hour
                Cpointer++;//declares that another hour has passed, will be used to tell how many iterations are there in a certain hour
                Hcount = 0;
            }
        }

    }
}
'''

Writing into file from multiple threads is a bad idea. I suggest you create a queue (even if just in memory queue) and have all your threads writing the info that they want to write into your file into this queue. In other words your queue will have multiple producers. And than have a single consumer on your queue that will read from the queue and write it into your file. This way you will have only one thread writing into file

You have two separate issues here.

  • Files.writeString replaces content by default. You want Files.writeString(fileName, A, StandardOpenOption.APPEND) .
  • Writing to the same file from simultaneous threads isn't going to work (think about it. The OS cannot promise that your write will be atomic, that should be obvious). So even if you fix it, it'll seem to work but every so often fail on you: A race condition.

The usual strategy to work around that last part is to use locks of some kind. If a single JVM is the only one doing those file writes, you can use whatever you like that java offers: synchronized , for example. Or an ReadWriteLock from the juconcurrent package.

But, this does mean your CPU stresser thread will be doing the waiting for the lock. You may instead want to start a separate thread, and have a single ConcurrentBlockingQueue. Your CPU stress testers send log messages to the queue, and your log writer thread will just be doing a 5-liner loop: Endlessly, fetch an item from the queue (this blocks until there is something), write it to the file, flush the stream, and loop.

This solves a bunch of problems, given that now only one thread writes.

If it's multiple JVMs, that's trickier - then lock with a .lock file. You can use Files.createFile() to create logfile.lock ; this will fail if the file is already there. Then wait some time (you can't ask the OS to tell you when the file is deleted, so you have to wait half a second or so and check again, forever, until the file is gone), until it succeeds, then write, then delete the lock file.

A major downside to .lock files is: If your process hard-crashes, the lock file sticks around. Which you don't want. One solution to that is to write your own PID (Process ID) to it, and thus anybody doing a check can at least see that the process it belongs to is dead. Except this is tricky; modern OSes don't just let you check for existence, neccessarily, and it's all very OS-dependent (no java libraries that automate this stuff, as far as I know). This all gets quite complicated, so, let's keep it simple:

If you want to write to the same file simultaneously from different JVMs / processes on the same system, you can do that 'safely', but it is rather complicated.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM