Java Concurrency volatile 读同步写

标签 java concurrency

我需要创建一个具有线程间共享对象的类(让我们调用 SharedObject)。 SharedObject 的特殊之处在于它持有一个在多线程环境下将返回的字符串,有时整个 SharedObject 将通过更改字段引用到新创建的对象来写入。

我不想在同一个监视器上同步读取和写入两者,因为写入场景很少发生,而读取场景却很常见。因此我做了以下事情:

public class ObjectHolder {
    private volatile SharedObject sharedObject;

    public String getSharedObjectString() {
        if (!isObjectStillValid()) {
            obtainNewSharedObject()
        }
        return sharedObject.getCommonString()
    }

    public synchronized void obtainNewSharedObject() {
        /* This is in case multiple threads wait on this lock,
           after first one obtains new object the others can just
           use it and should not obtain a new one */
        if(!isObjectStillValid()) {
            sharedObject = new SharedObject(/*some parameters from somewhere*/)
        }
    }
}

根据我从文档和 stackoverflow 上读到的内容,synchronized 关键字将确保只有一个线程可以访问同一对象实例上的同步块(synchronized block)(因此写入竞争/多次不必要的写入是非-issue) 而字段引用上的 volatile 关键字将确保将引用值直接写入主程序内存(不在本地缓存)。

还有我遗漏的任何其他陷阱吗?

我想确保在写入 sharedObject 时在同步块(synchronized block)内,sharedObject 的新值最迟在锁定 时出现在任何其他线程中>obtainNewSharedObject() 已发布。如果不能保证这一点,我可能会遇到不必要的写入和替换正确值的情况,这对这种情况来说是个大问题。

我知道为了绝对安全,我可以自己制作 getSharedObjectString() synchronized 但是如前所述,如果不需要,我不想阻止读取。 这样读取是非阻塞的,当发生写入场景时它是阻塞的。 我可能应该提到方法 isObjectStillValid() 是线程独立的(完全基于 SharedObject 和系统时钟)因此有效的无线程检查用于写场景。

编辑:请注意我在 stackoverflow 上找不到类似的主题,但它可能存在。抱歉,如果是这样的话。

Edit2:感谢您的所有评论。编辑因为显然我还不能投票(我可以,但它没有显示)。虽然只要 isObjectStillValid 是线程安全的,我的解决方案就可以正常工作,但它可能会因多次访问 volatile 字段而导致性能下降。我最有可能使用升级双重检查锁定解决方案来改进它。我还将深入分析这里提到的所有其他可能性。

最佳答案

你为什么不使用AtomicReference .它使用乐观锁定,这意味着不涉及实际的线程锁定。在内部它使用 Compare and Swap .如果你看一下它在实现中使用 volatile 的实现,我相信 Doug Lea 会正确地实现它:)

除此之外,还有很多方法可以在很多读者和一些作者之间进行同步 - ReadWriteLock

关于Java Concurrency volatile 读同步写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51248760/

相关文章:

c# - System.IO.IOException : 'The process cannot access the file ' @. txt'因为它正被另一个进程使用。'

JAVA - 从启动器调用时外部 exe 锁定

java - 类型 T 不是通用的;它不能用参数 <?> 泛型函数中的错误进行参数化

java - 扩展HashMap以获取具有指定hashcode的所有对象?

multithreading - 在 Clojure 中同步多个读取器/单个写入器的线程

concurrency - Common Lisp 并行编程

Java 执行器调用外部可执行文件的速度仅稍快一些

Java 互斥锁与 smp

java - Java 代码中的结果格式不正确

java - java中 '>>>'运算符的用法是什么?