加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 以同步方法读取值时的安全发布

发布时间:2020-12-14 16:33:07 所属栏目:Java 来源:网络整理
导读:我的问题涉及到 Java中字段值的安全发布(如这里所述) 据我所知,一个字段可以安全地读取(意味着从多个线程访问将看到正确的值)如果: 读写在同一个显示器上同步 字段是最后的 字段是不稳定的 如果我的理解正确,以下类不应该是线程安全的,因为初始值没有这些特
我的问题涉及到 Java中字段值的安全发布(如这里所述)

据我所知,一个字段可以安全地读取(意味着从多个线程访问将看到正确的值)如果:

>读写在同一个显示器上同步
>字段是最后的
>字段是不稳定的

如果我的理解正确,以下类不应该是线程安全的,因为初始值没有这些特征.然而,我发现很难相信,即使只能从同步方法访问,我也需要使第一个易失性.

public class Foo {

    private boolean needsGreeting = true;

    public synchronized void greet() {
        if (needsGreeting) {
            System.out.println("hello");
            needsGreeting = false;
        }
    }
}

我错过了什么吗?以上代码是否正确,如果是,为什么?或者在这种情况下,必须先创建volatile或者使用最终的AtomicBoolean或类似的东西,以及从synchronized方法访问它.

(只是为了澄清,我知道,如果初始值是用一个synchronized方法编写的,即使没有volatile关键字,它也是线程安全的.)

解决方法

在构造函数和方法调用的结尾之间没有发生之前的关系,因此一个线程可能开始构建实例并使引用可用,另一个线程可以获取该引用并开始调用greet( )方法. greet()中的同步并不能解决这个问题.

如果您通过着名的双重检查锁定模式发布实例,将变得更容易看到如何.如果有这样的发生关系,即使使用DCLP也应该是安全的.

public class Foo {
    private boolean needsGreeting = true;

    public synchronized void greet() {
        if (needsGreeting) {
            System.out.println("Hello.");
            needsGreeting = false;
        }
    }
}

class FooUser {
    private static Foo foo;

    public static Foo getFoo() {
        if (foo == null) {
            synchronized (FooUser.class) {
                if (foo == null) {
                    foo = new Foo();
                }
            }
        }
        return foo;
    }
}

如果多个线程同时调用FooUser.getFoo().greet(),一个线程可能正在构造Foo实例,但是另一个线程可能会提前找到一个非空的Foo引用,并调用greet()并发现needGreeting仍然是假.

Java并发实践中提到了一个例子(3.5).

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读