0

java.io.File在对象上使用同步是否好?当您想使用两个线程交替读取和写入该文件对象时:一个用于读取,一个用于写入。

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

}

在上面的代码中我使用了 Synchronised(this),我可以使用 Synchronise(fileObj) 吗?

我从我的一位教授那里得到的另一个解决方案是将读写封装在对象中,并在每次操作后将它们推送到 fifo 中,如果有人详细说明的话

4

4 回答 4

3

编辑:

现在您已经添加了代码,您可以锁定,fileObj但前提是它没有更改。我会将它移到构造函数中,并final确保有人不会setFileObj不当调用它。要么,要么抛出异常,如果this.fileObj不是null

几个其他评论:

  • notifyAll()除非你真的需要通知多个线程,否则不要使用。
  • 如果你 catch 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
  }

不能做的是锁定两个不同的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

通常不会。有很多更好的方法:使用ReentrantLock

这个类已经提供了“读/写锁”的比喻。它还正确处理了多个线程可以同时读取但只有一个线程可以写入的情况。

File正如其他人已经提到的,只有当所有线程都使用相同的实例时,锁定才会起作用。

确保在每次写入后刷新输出缓冲区;这将消耗一些性能,但否则,您将获得陈旧的读取(读取线程不会找到您期望存在的数据)。

如果要简化代码,请添加第三个线程,该线程接受来自其他两个的命令。命令是READWRITE。将命令放入队列中,让第三个线程等待队列中的条目。每个命令都应该有一个回调方法(如success()),当命令执行时第三个线程将调用该方法。

这样,您根本不需要任何锁定。每个线程的代码将更加简单和易于测试。

[编辑]根据您的代码回答:它适用于您的情况,因为每个人都使用相同的实例,fileObj但它会将几件事混合到一个字段中。阅读您的代码的人会期望文件对象只是要读取的文件的路径。因此,该解决方案将违反最小惊讶原则

如果您争辩说它会节省内存,那么我会回答“过早优化”。

尝试找到一个可以清楚地传达您的意图的解决方案。“聪明”的编码对你的自我有好处,但这是一个人可以说的唯一积极的事情(而且当人们第一次看到你的“聪明”代码后,了解人们会对你说什么对你的自我不利...) ;-)

于 2012-05-07T15:17:25.660 回答
0

Queueing off read/write objects to one thread that then performs the operation is a valid approach to something, but I'm not sure what.

Wha it would not do, for example, is to enforce read/write/read/write order as you specified in your earlier question. There is nothing to stop the read thread queueing up 100 read requests.

That could be prevented by making the thread that submits an object wait on it until it is signaled by the read/write thread, but this seems a very complex way of just enforcing read/write order, (assuming that's what you still want).

I'm getting to the state now where I'm not sure what it is you need/want.

于 2012-05-07T15:40:30.143 回答