同步静态类中的文件输出

时间:2012-05-13 02:40:53

标签: java multithreading

我有几个线程需要写入两个不同的文本文件。到目前为止,我有这段代码:

public class Logger {

    public static void printToGameLog(String value){
        Writer writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("GameLog.txt", true), "utf-8"));
            synchronized(writer){
                writer.write(outputString + "\r\n");
            }
        } catch (IOException ex){
            System.out.println("cannot create log file");
        } 
    }


    public static void printToServerLog(String value){
        Writer writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream("serverLog.txt", true), "utf-8"));
            synchronized(writer){
                writer.write(outputString + "\r\n");
            }
        } catch (IOException ex){
            System.out.println("cannot create log file");
        }
    }
}

这是否是一种可接受的方法,可以确保不会有多个线程同时写入同一个文件?

如果一个线程调用其中一个方法并进入同步块,那么如果另一个线程出现并尝试执行相同的方法会发生什么。当它尝试使用局部变量writer时,它是否会尝试获取另一个线程锁定的相同对象并因此阻塞?我本以为它会简单地创建自己独立的变量,这意味着我应该让编写器成为静态类变量?

3 个答案:

答案 0 :(得分:1)

由于存在单独的日志文件,我不明白为什么需要进行类级同步。似乎是一个不必要的瓶颈。我会分别为每个方法提供同步(因为他们可以同时点击单独的文件):

public class Logger
{
    private static final Object GAME_LOG_LOCK = new Object();
    private static final Object SERVER_LOG_LOCK = new Object();

    public static void printToGameLog(String value){
        synchronized (GAME_LOG_LOCK) {
            Writer writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("GameLog.txt", true), "utf-8"));
                writer.write(outputString + "\r\n");
            } catch (IOException ex){
                System.out.println("cannot create log file");
            } 
        }
    }

    public static void printToServerLog(String value){
        synchronized (SERVER_LOG_LOCK) {   
            Writer writer = null;
            try {
                writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream("serverLog.txt", true), "utf-8"));
                writer.write(outputString + "\r\n");
            } catch (IOException ex){
                  System.out.println("cannot create log file");
            }
        }
    }
}

答案 1 :(得分:0)

这是代码中的空指针异常,尝试在静态方法上使用synchronized块的方法

   synchronized(Logger.class){

或其他替代方法是将整个方法设置为同步,如此

public static synchronized void printToGameLog(String value){

public static synchronized void printToServerLog(String value){

我不相信你在这里需要同步,如果你有一个从多个线程读/写的状态,你只需要同步。

答案 2 :(得分:0)

这是对你的问题的另一种看法。它使用单个线程来写日志文件,只有这个线程可以访问这些文件。必须记录针对BlockingQueue写入的内容的线程:

public class ThreadedLog {

    //This is some code to test the logger
    public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {

        ThreadedLog log = new ThreadedLog("/tmp/test.txt");
        // Start 100 thread that write against the log
        for (int i = 0; i < 100; i++) {
            new Thread(new TestLogger(log)).start();
        }
    }

    private static class TestLogger implements Runnable {

        private ThreadedLog log;

        public TestLogger(ThreadedLog log) {
            this.log = log;
        }

        @Override
        public void run() {
            for (int i = 0; i < 5000; i++) {
                try {
                    log.log("This is entry " + i + " from thread " + Thread.currentThread().getId());
                } catch (InterruptedException ex) {
                }
            }
            System.out.println(Thread.currentThread().getId() + " is done");
        }
    }
     //________________________________________________________________________________________________
    /*
     * This is the code for the actual logger
     *
     */
    private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10000);
    private String fileName;
    private Thread thread;
    private Writer writer;

    public ThreadedLog(String fileName) throws UnsupportedEncodingException, FileNotFoundException {
        this.fileName = fileName;
        thread = new Thread(new LoggingThread());
        writer = new BufferedWriter(new OutputStreamWriter(
            new FileOutputStream(fileName, true), "utf-8"));
        thread.start();
    }

    private class LoggingThread implements Runnable {

        @Override
        public void run() {

            try {
                for (;;) {
                    ThreadedLog.this.writer.write(queue.take() + "\r\n");
                    ThreadedLog.this.writer.flush();
                }
            } catch (InterruptedException | IOException e) {
                e.printStackTrace();
                try {
                    ThreadedLog.this.writer.close();
                } catch (Exception ex) {
                }
            }
        }
    }

    public void log(String string) throws InterruptedException {
        queue.put(string);
    }
}