首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于并发访问文件的ReadWriteLock

用于并发访问文件的ReadWriteLock
EN

Stack Overflow用户
提问于 2020-09-29 22:37:01
回答 1查看 43关注 0票数 1

我有一个类,它实现在并发环境中文件的读写操作。我知道BufferedInputStreamBufferedWriter是同步的,但在我的例子中,读写操作可以同时使用。现在我使用ReentrantReadWriteLock,但是我对正确的解决方案没有信心。

代码语言:javascript
复制
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.的潜在并发问题。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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”,即“无法测试的东西在生产中会爆炸,并会浪费一周时间追逐它”)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64128590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档