微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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).

原文地址:https://www.jb51.cc/java/125014.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐