我有一个类,它实现在并发环境中文件的读写操作。我知道BufferedInputStream和BufferedWriter是同步的,但在我的例子中,读写操作可以同时使用。现在我使用ReentrantReadWriteLock,但是我对正确的解决方案没有信心。
public class FileSource {
private final File file;
private final ReadWriteLock lock;
public FileWrapper(final File file) {
if (Objects.isNull(file)) {
throw new IllegalArgumentException("File can't be null!");
}
this.file = file;
this.lock = new ReentrantReadWriteLock();
}
public String getContent() {
final Lock readLock = lock.readLock();
readLock.lock();
final StringBuilder sb = new StringBuilder();
try (final BufferedInputStream in =
new BufferedInputStream(
new FileInputStream(file))) {
int data;
while ((data = in.read()) > 0) {
sb.append(data);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
readLock.unlock();
}
return sb.toString();
}
public void saveContent(final String content) {
final Lock writeLock = lock.writeLock();
writeLock.lock();
try (BufferedWriter out =
new BufferedWriter(
new FileWriter(file))) {
out.write(content);
} catch (IOException e) {
e.printStackTrace();
} finally {
writeLock.unlock();
}
}
}在这种情况下,ReentrantReadWriteLock是正确的解决方案,还是我需要使用ReentrantLock或其他什么的?(有理由)
本文讨论的不是像File这样的类设计作为状态,也不是直接在方法中发送File,或者使用nio包或ext。它不应该是一个实用程序类。方法签名和文件作为字段必须保持不变。它是关于文件和InputStream\OutputStream.的潜在并发问题。
发布于 2020-09-29 22:58:29
RRWL这里很好。当然,如果一些代码生成了一个new FileWrapper("/foo/bar.txt"),而另一些代码也制造了一个单独的new FileWrapper("/foo/bar.txt"),那么这两个包装器就会掉在自己身上,导致事情变得珠光宝气;我假设您有一些外部机制来确保这种情况不会发生。如果不这样做,一些人使用ConcurrentHashMap及其并发方法(例如computeIfAbsent;不要为这些方法使用普通的jane /put)可以帮助您解决问题。
注意,您的异常处理是错误的。异常消息不应该以标点符号结尾(想想看:如果没有这条规则,所有异常消息中的80%将以感叹号结尾,并使日志文件成为一项有趣的练习),一般来说,如果您曾经写过catch (Exception e) { e.printStackTrace(); },您就会去那个专门为电影院里说话的人和写这个词的人保留的地方。
我想说,一个名为saveContent的方法在抛出一些检查异常时是合理的;毕竟,很明显这是可以失败的,如果可以的话,调用它的代码可能会采取一些行动。
如果您只是无法到达那里,那么正确的¯_(ツ)_/ just不知道捕获块处理程序是:throw new RuntimeException("uncaught", e);。不是e.printStackTrace();。后者登录到一个无法控制的位置,删除有用的信息,关键的是,继续运行,好像什么都没有错一样,默默地忽略了一个事实,即保存调用只是失败了,而前者保留了所有信息,实际上会中止代码执行。它使它很难恢复,但至少它比e.printStackTrace容易,而且如果您希望它更容易,就比做一个特殊的例外情况更容易。或者直接抛出IOException (您的启动代码要短得多!)。
这段代码中另一个常见的错误是它使用'platform默认字符集编码‘来读取您的文件,这很少是您想要的。
新的Files还可以一次读取整个文件,为您节省大量的代码。当您升级代码时,您将受益于Files对字符集编码的独特体验:与java库中的大多数其他地方不同,如果您没有指定UTF-8编码,java.nio.file.Files将假设您打算使用UTF-8编码(而不是“platform default”,即“无法测试的东西在生产中会爆炸,并会浪费一周时间追逐它”)。
https://stackoverflow.com/questions/64128590
复制相似问题