java.io.File对象上的同步
在java.io.File对象上的同步,java,multithreading,file-io,synchronization,Java,Multithreading,File Io,Synchronization,在java.io.File对象上使用Synchronized是否合适。当您想使用两个线程交替地读写该文件对象时:一个用于读,一个用于写 public class PrintChar { File fileObj; public void read() { while (true) { synchronized (this) { readFile(); notifyAll(); try
java.io.File
对象上使用Synchronized是否合适。当您想使用两个线程交替地读写该文件对象时:一个用于读,一个用于写
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(此),我可以使用Synchronise(fileObj)吗
我从我的一位教授那里得到的另一个解决方案是封装读写对象,并在每次操作后将其推入fifo中,如果有人对此进行详细说明的话一般来说,锁定I/O不是一个好主意。最好构造您的程序,以便通过设计保证文件的给定部分通常不会同时被写入和读取,并且只有在您必须在给定文件的读取和写入之间进行调解时才进行锁定。一般来说,跨I/O锁定不是一个好主意。最好构造您的程序,这样您就可以通过设计保证文件的给定部分通常不会同时被写入和读取,并且只有在您必须在文件的给定部分的读取和写入之间进行调解时才可以锁定。编辑: 现在您已经添加了代码,您可以锁定
fileObj
,但前提是它没有更改。我会将它移动到构造函数中,并将其设置为final
,以确保没有人不适当地调用setFileObj
。如果this.fileObj
不是null
,则抛出异常
其他几点意见:
- 除非确实需要通知多个线程,否则不要使用
notifyAll()
- 如果您捕获了InterruptedException,我会退出线程而不是循环。始终围绕捕获中断异常做出正确的决定,而不仅仅是打印和循环
- 你的
在.close()中代码>应位于
块中finally
只要两个线程都锁定在同一个常量对象上,就可以锁定所需的任何对象。通常使用
私有final
对象,例如:
private final File sharedFile = new File(...);
// reader
synchronized (sharedFile) {
// read from file
}
...
// writer
synchronized (sharedFile) {
// write to 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) {
...
}
您不能锁定两个不同的文件
对象,即使它们都指向同一个文件。例如,以下操作不起作用:
private final File sharedFile = new File(...);
// reader
synchronized (sharedFile) {
// read from file
}
...
// writer
synchronized (sharedFile) {
// write to 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) {
...
}
另外,锁定同一文件
对象并不意味着读写代码可以在线程之间工作。您需要确保在writer中,同步块中的所有更新都已刷新。在读卡器中,您可能不想使用缓冲流,否则您将有过时的数据。编辑:
现在您已经添加了代码,您可以锁定fileObj
,但前提是它没有更改。我会将它移动到构造函数中,并将其设置为final
,以确保没有人不适当地调用setFileObj
。如果this.fileObj
不是null
,则抛出异常
其他几点意见:
- 除非确实需要通知多个线程,否则不要使用
notifyAll()
- 如果您捕获了InterruptedException,我会退出线程而不是循环。始终围绕捕获中断异常做出正确的决定,而不仅仅是打印和循环
- 你的
在.close()中代码>应位于
块中finally
只要两个线程都锁定在同一个常量对象上,就可以锁定所需的任何对象。通常使用
私有final
对象,例如:
private final File sharedFile = new File(...);
// reader
synchronized (sharedFile) {
// read from file
}
...
// writer
synchronized (sharedFile) {
// write to 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) {
...
}
您不能锁定两个不同的文件
对象,即使它们都指向同一个文件。例如,以下操作不起作用:
private final File sharedFile = new File(...);
// reader
synchronized (sharedFile) {
// read from file
}
...
// writer
synchronized (sharedFile) {
// write to 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) {
...
}
另外,锁定同一
文件
对象并不意味着读写代码可以在线程之间工作。您需要确保在writer中,同步块中的所有更新都已刷新。在读卡器中,您可能不希望使用缓冲流,否则您将有过时的数据。通常不希望。有更好的方法:使用
这个类已经提供了“读/写锁”的比喻。它还正确处理了多个线程可以同时读取但只有一个线程可以写入的情况
正如其他人已经提到的,只有当所有线程使用相同的文件
实例时,锁定才会起作用
确保在每次写入后刷新输出缓冲区;这将降低一些性能,但否则,您将得到过时的读取(读取线程将找不到您期望的数据)
如果希望简化代码,请添加第三个线程,该线程接受来自其他两个线程的命令。这些命令是READ
和WRITE
。将命令放入队列中,让第三个线程等待队列中的条目。每个命令都应该有一个回调方法(如success()
),当命令执行时,第三个线程将调用该方法
这样,您根本不需要任何锁定。每个线程的代码将更加简单,易于测试
[EDIT]根据您的代码回答:这在您的情况下是可行的,因为每个人都使用相同的fileObj
实例,但它会将多个内容混合到一个字段中。阅读代码的人会认为file对象只是要读取的文件的路径。因此,解决方案将违反规则
如果你认为这样可以节省内存,那么我会用“”来回答
试着找到一个能清楚传达你意图的解决方案。“聪明”的代码对你的自我是有好处的,但这是唯一可以说的积极的事情(而且,当人们第一次看到你的“聪明”代码后,了解人们会对你说些什么对你的自我是不好的…-) 通常不会。有更好的方法:使用