0

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

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时,它是否会尝试获取已被另一个线程锁定的相同对象并因此阻塞?我原以为它会简单地创建自己的单独变量,这意味着我应该让 writer 成为静态类变量?

4

3 回答 3

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");
            }
        }
    }
}
于 2012-05-13T03:16:02.563 回答
0

这是您的代码中的空指针异常,请尝试在静态方法上使用同步块的这种方式

   synchronized(Logger.class){

或者另一种选择是将整个方法设置为同步,就像这样

public static synchronized void printToGameLog(String value){

public static synchronized void printToServerLog(String value){

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

于 2012-05-13T02:51:26.680 回答
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);
    }
}
于 2012-05-13T16:04:15.837 回答