Java:每隔几秒钟创建一次文件

时间:2013-11-11 14:03:44

标签: java multithreading file-io concurrency thread-safety

我正在使用ScheduledThreadPoolExecutor在每个fileIntervalInSeconds秒内创建一个文件:

executorService = new ScheduledThreadPoolExecutor(1);
        executorService.scheduleAtFixedRate(new Runnable()
        {
            @Override
            public void run()
            {
                    File file = new File(fileName);
                    if (file.exists())
                    {
                        Log.debug("creating new file");
                        openFileWriter(file);
                    }

            }
        }, fileIntervalInSeconds, fileIntervalInSeconds, TimeUnit.SECONDS);
    }
private void openFileWriter() throws FileSystemNotificationException
{

        // 1 - close exist writer
        writer.close();
        // 2 - rename to backup file name
          ...
        // 3 - create new file      
        FileWriter writerFile = new FileWriter(fileName, true);
        writer = new PrintWriter(writerFile);

}

我一直在向文件写入警告消息:

private synchronized void writeLine(String line) throws InterruptedException
{
    writer.println(line);
}

我的问题是:

  1. 我怎样才能确保我在没有关闭时使用作家? (writer.close())
  2. 如何在开始编写之前等待ScheduledThreadPoolExecutor完成文件的创建

4 个答案:

答案 0 :(得分:4)

在写入文件之前检查文件是怎么回事。不需要后台线程或同步

private synchronized void writeLine(String line) {
    if (!file.exists())
       reopenWritingFile();
    writer.println(line);
}

答案 1 :(得分:0)

您有两种选择:

  1. 在关闭旧作家之前创建新作家。
  2. 在关闭写入时写入的作者之前建立锁定。
  3. 示例:

    volatile PrintWriter writer;
    ReadWriteLock lock = new ReentrantReadWriteLock();
    Lock writeLock = lock.writeLock();
    Lock readLock = lock.readLock();
    
    private void openFileWriterWithLock() throws IOException {
    
      if (writeLock.tryLock()) {
        try {
          // 1 - close exist writer
          writer.close();
          // 2 - rename to backup file name
          //...
          // 3 - create new file      
          FileWriter writerFile = new FileWriter(fileName, true);
          writer = new PrintWriter(writerFile);
        } finally {
          writeLock.unlock();
        }
      }
    
    }
    
    private synchronized void writeLineWithLock(String line) throws InterruptedException {
      readLock.lock();
      try {
        writer.println(line);
      } finally {
        readLock.unlock();
      }
    }
    
    private void openFileWriterWithoutLock() throws IOException {
      // 0. Note old file.
      PrintWriter oldWriter = writer;
      // 1. Create new file.
      FileWriter writerFile = new FileWriter(fileName, true);
      // 2. Swap the new one in.
      writer = new PrintWriter(writerFile);
      // 3 - close old writer
      oldWriter.close();
    }
    
    private synchronized void writeLineWithoutLock(String line) throws InterruptedException {
      writer.println(line);
    }
    

答案 2 :(得分:0)

您可以在write方法中每小时创建一个新文件。对于时间检查,您会有一些轻微的开销,但这应该可以忽略不计。下面的示例将每小时创建一个新的日志文件,并以毫秒为单位添加到文件名的前面。您可以格式化适合您的时间。

public class LogWriter {
    private long lastCreationTime;
    PrintWriter writer;
    String logFileName;

    public LogWriter(String logFileName) {
        this.logFileName = logFileName;
        createLogFile(logFileName);
    }

    private void createLogFile(String fileName) {
        if(writer != null) {
            writer.close();
        }
        lastCreationTime = System.currentTimeMillis();
        FileWriter writerFile;
        try {
            writerFile = new FileWriter(lastCreationTime + "_" + fileName, true);
            writer = new PrintWriter(writerFile);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private synchronized void writeLine(String line) {
        if(lastCreationTime < System.currentTimeMillis() - 3600000) {
            createLogFile(logFileName);
        }
        writer.write(line);
    }
}

答案 3 :(得分:0)

如何使用一个单独的线程来处理日志记录而不是那个相当复杂的构造?

public class Logger extends Thread {

private final LinkedBlockingQueue<String> linesToWrite = new LinkedBlockingQueue<>();
private final String filename;

private Logger(String filename) {
  super("Logging thread");
  this.filename = filename;
  this.setDaemon(true);
  this.setPriority(Thread.MIN_PRIORITY);
}

@Override
public void run() {
  try (BufferedWriter out = new BufferedWriter(new FileWriter(filename, true))) {

    String line;
    while (this.isInterrupted() == false) {
      line = linesToWrite.take();
      out.write(line);
      out.newLine();
      out.flush();
    }
  } catch (InterruptedException e) {
  } catch (IOException ex) {
    System.out.println("Failed to access log file: " + ex);
  }
}

public void log(final String line) {
  this.linesToWrite.add(line);
}

然后初始化记录器一次:

final Logger logger = new Logger("test.log");
logger.start();

然后你可以在线程安全的方式从任何地方使用它:

logger.log("Test message");

您无需停止记录器,因为Java将使用try构造确保文件已正确关闭。但是如果你愿意,你可以这样停止:

logger.interrupt();

现在您可以以单线程方式执行所有文件操作,因为任何时候只有一个线程可以访问日志文件。