0

java.io.Fileオブジェクトで同期を使用するのは良いですか。2 つのスレッド (読み取り用と書き込み用) を使用して、そのファイル オブジェクトの読み取りと書き込みを交互に行いたい場合。

public class PrintChar {
    File fileObj;
    public void read() {

    while (true) {
        synchronized (this) {
            readFile();
            notifyAll();
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()
                        + " throws Exception");
                e.printStackTrace();
            }
        }
    }
}

public void write(String temp) {

    while (true) {
        synchronized (this) {
            writeFile(temp);
            notifyAll();
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName()
                        + " throws Exception");
                e.printStackTrace();
            }
        }
    }
}

public void setFileObj(File fileObj) {
    this.fileObj = fileObj;
}

public void readFile() {
    InputStream inputStream;
    try {
        inputStream = new FileInputStream(fileObj);
        // Get the object of DataInputStream
        DataInputStream in = new DataInputStream(inputStream);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String strLine;
        // Read File Line By Line
        while ((strLine = br.readLine()) != null) {
            // Print the content on the console
            System.out.println(strLine);
        }
        in.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void writeFile(String temp) {
    BufferedWriter bw;
    try {
        bw = new BufferedWriter(new FileWriter(fileObj, true));
        bw.write(temp);
        bw.newLine();
        bw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public static void main(String args[]) {

    final PrintChar p = new PrintChar();
    p.setFileObj(new File("C:\\sunny.txt"));

    Thread readingThread = new Thread(new Runnable() {
        @Override
        public void run() {
            p.read();
        }
    });
    Thread writingThread = new Thread(new Runnable() {
        @Override
        public void run() {
            p.write("hello");
        }
    });

    Thread Randomizer = new Thread(new Runnable() {
        @Override
        public void run() {
            while (true)
                try {
                    Thread.sleep(500000);
                } catch (InterruptedException e) {
                    System.out.println(Thread.currentThread().getName()
                            + " throws Exception");
                    e.printStackTrace();
                }
        }
    });

    readingThread.start();
    writingThread.start();
    Randomizer.start();
}

}

上記のコードでは、Synchronized(this) を使用しましたが、Synchronise(fileObj) を使用できますか??

教授の 1 人から得たもう 1 つの解決策は、オブジェクトの読み取りと書き込みをカプセル化し、すべての操作の後にそれらを fifo にプッシュすることです。

4

4 に答える 4

3

編集:

コードを追加したので、変更されていない場合にのみロックできます。fileObj私はそれをコンストラクターに移動しfinal、誰かがsetFileObj不適切に呼び出さないようにするために作成します。それか、そうthis.fileObjでない場合は例外をスローしますnull

他のいくつかのコメント:

  • notifyAll()本当に複数のスレッドに通知する必要がない限り、使用しないでください。
  • キャッチInterruptedExceptionしたら、ループする代わりにスレッドを終了します。印刷してループするだけでInterruptedExceptionなくキャッチについて常に適切な決定を下してください。
  • あなたin.close();finallyブロックにいる必要があります。

両方のスレッドが同じ定数オブジェクトをロックしている限り、任意のオブジェクトをロックできます。private finalたとえば、次のようなオブジェクトを使用するのが一般的です。

  private final File sharedFile = new File(...);

  // reader
  synchronized (sharedFile) {
       // read from file
  }
  ...

  // writer
  synchronized (sharedFile) {
       // write to file
  }

両方が同じファイルを指している場合でも、2つの異なるオブジェクトをロックすることはできません。たとえば、File次は機能しません。

  private static final String SHARED_FILE_NAME = "/tmp/some-file";

  // reader
  File readFile = new File(SHARED_FILE_NAME);
  synchronized (readFile) {
      ...
  }

  // writer
  File writeFile = new File(SHARED_FILE_NAME);
  synchronized (writeFile) {
      ...
  }

また、同じFileオブジェクトをロックしているからといって、コードの読み取りと書き込みがスレッド間で機能するわけではありません。ライターで、すべての更新が同期ブロックでフラッシュされることを確認する必要があります。リーダーでは、おそらくバッファリングされたストリームを使用したくないでしょう。そうしないと、古いデータになります。

于 2012-05-07T15:10:01.887 に答える
2

一般に、I/O間でロックすることは良い考えではありません。通常、ファイルの特定のセクションが同時に書き込まれ、読み取られないことを設計によって保証し、ファイルの特定の部分の読み取りと書き込みを絶対に仲介する必要がある場合にのみロックするようにプログラムを構築することをお勧めします。

于 2012-05-07T15:09:47.070 に答える
0

読み取り/書き込みオブジェクトを1つのスレッドにキューイングしてから操作を実行することは、何かに対する有効なアプローチですが、何ができるかわかりません。

たとえば、前の質問で指定したように、読み取り/書き込み/読み取り/書き込みの順序を強制することはできません。読み取りスレッドが100個の読み取り要求をキューに入れるのを止めるものは何もありません。

これは、オブジェクトを送信するスレッドを読み取り/書き込みスレッドによって通知されるまで待機させることで防ぐことができますが、これは読み取り/書き込みの順序を強制する非常に複雑な方法のようです(それがまだ必要であると仮定します)。

私は今、あなたが何を必要としているのか、何を望んでいるのかわからない状態になりつつあります。

于 2012-05-07T15:40:30.143 に答える
0

通常はありません。もっと良い方法があります:

このクラスはすでに「読み取り/書き込みのロック」メタファを提供しています。また、多数のスレッドが同時に読み取ることができるが、1 つのスレッドしか書き込むことができない場合も正しく処理します。

他の人が既に述べたように、ロックはすべてのスレッドが同じFileインスタンスを使用する場合にのみ機能します。

各書き込み後に必ず出力バッファーをフラッシュしてください。これによりパフォーマンスが低下しますが、それ以外の場合は、古い読み取りが発生します (読み取りスレッドは、そこにあると期待するデータを見つけられません)。

コードを簡素化したい場合は、他の 2 つのコマンドを受け入れる 3 番目のスレッドを追加します。コマンドはREADWRITEです。コマンドをキューに入れ、3 番目のスレッドがキュー内のエントリを待機するようにします。success()各コマンドには、コマンドが実行されたときに 3 番目のスレッドが呼び出すコールバック メソッド ( など) が必要です。

この方法では、ロックはまったく必要ありません。各スレッドのコードは、はるかに単純になり、テストが容易になります。

[編集]あなたのコードに基づく回答: 誰もが の同じインスタンスを使用するため、あなたのケースでは機能しますが、fileObj1 つのフィールドに複数のものを混在させます。コードを読んでいる人は、ファイル オブジェクトが、読み取るファイルへの単なるパスであることを期待します。したがって、解決策は最小の驚きの原則に違反します。

メモリを節約できると主張する場合は、「時期尚早の最適化」と答えます。

あなたの意図を明確に伝える解決策を見つけてみてください。「賢い」コーディングはあなたの自我にとって良いことですが、それについて人が言える唯一の肯定的なことです (そして、あなたの「賢い」コードを初めて見た後に人々があなたについて何を言うかを知ることは、あなたの自我にとって良くありません...) ;-)

于 2012-05-07T15:17:25.660 に答える