0

2つの異なるテキストファイルに書き込む必要のあるスレッドがいくつかあります。これまでのところ、私はこのコードを持っています:

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");
        }
    }
}

これは、同時に1つのスレッドだけが同じファイルに書き込んでいることを確認するための許容可能な方法ですか?

スレッドがこれらのメソッドの1つを呼び出して同期ブロックに入ると、別のスレッドがやって来て同じメソッドを実行しようとするとどうなりますか。ローカル変数を使用しよう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

これはコード内の null ポインター例外です。静的メソッドで同期ブロックを使用するこの方法を試してください

   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 に答える