关于 volatile 关键字的一些说明 [英] A little clarification on the volatile keyword

查看:40
本文介绍了关于 volatile 关键字的一些说明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑 Java 并发实践中的片段-

//不安全的发布公众持有人;公共无效初始化(){持有人 = 新持有人(42);}

<小时>

公共类持有人{私人国际n;公共持有人(int n){this.n = n;}public void assertSanity(){如果 (n != n)throw new AssertionError("这句话是假的.");}}

本书作者建议的解决方案之一是 -

public static Holder holder = new Holder(42);

如果唯一的要求是防止 AssertionError,那么这也能正常工作-

private final int n;

我的问题是对这个 stackoverflow 线程的评论的跟进 作者:John Vint-

<块引用>

实际上,声明成员字段 volatile 仍然不能保证在持有人可见之前发布.你可以看看ConcurrentHashMap 的私有方法 readUnderLock 其中需要考虑到这种细微差别.虽然将持有者声明为 volatile 确实如此.

简单来说,他在此建议两件事-

public volatile Holder;公共无效初始化(){持有人 = 新持有人(42);}

上述解决方案会完美运行吗?如果对对象的引用被声明为 volatile,它是否能确保安全的对象发布?数组也是对象.声明一个数组引用并不能使它的元素线程安全.

为什么这不会像作者建议的那样工作-

公共类持有人{私有 volatile int n;

<块引用>

声明成员字段 volatile 仍然不能保证在持有人可见之前发布

即使成员字段已声明为 volatile,它也保证条件 n != n 将始终为 false,因此不会出现 AssertionError.请提出建议.

解决方案

虽然按照您的建议使用 volatile 会有所帮助,但在您可能碰巧尝试使用的许多其他情况下却无济于事.即很容易错误地使用 volatile,因此很难鼓励,除非您可以确定您知道将使用哪些操作.

<块引用>

如果一个对象的引用被声明为 volatile,它是否能确保安全的对象发布?

这在很大程度上取决于操作的顺序和类型.在这种情况下,写入

this.n = n;//进而持有人 = ...

写入 holder 确保写入 this.n 必须可见,前提是你也这样做

Holder h = holder;//读屏障//必须设置 n.int n = this.n;

<块引用>

声明成员字段 volatile 仍然不能保证在持有者可见之前发布

我不同意这种情况.一旦您在另一个线程中获得了 holder,在读取 n 时就不可能在读取 volatile 变量时看到初始化的值.这是因为 holder 仅在 n 初始化后设置.

Consider the snippet from Java Concurrency in Practice-

// Unsafe publication
public Holder holder;

public void initialize(){
    holder = new holder(42);
}


public class Holder{
    private int n;

    public Holder(int n) {
        this.n = n;
    }

    public void assertSanity(){
        if (n != n)
            throw new AssertionError("This statement is false.");
    }
}

One of the solutions suggested by the author of the book is -

public static Holder holder = new Holder(42);

And if the only requirement was to prevent the AssertionError, then this would also work fine-

private final int n;

My question is a follow-up to the comment on this stackoverflow thread by John Vint-

Actually, declaring the member field volatile still doesnt guarantee publication prior to holder being visible. You can look at ConcurrentHashMap's private method readUnderLock in which that takes this nuance into account. Though declaring holder as volatile does.

To put it in simple words, he is suggesting hereby 2 things-

public volatile Holder holder;

public void initialize(){
    holder = new holder(42);
}

Is the above solution going to work perfectly? If a reference to an object is declared as volatile, does it ensures safe object publication? Arrays are objects too. Declaring an array reference doesn't makes its elements thread safe.

And Why this will not work as suggested by author-

public class Holder {
private volatile int n;

declaring the member field volatile still doesnt guarantee publication prior to holder being visible

Even though as the member field has been declared as volatile, its gauranteed that the condition n != n will be always false, and hence no AssertionError. Please suggest.

解决方案

While using volatile would help as you suggest, it would not help in many other situations you might happen to try to use. i.e. it's very easy to use volatile incorrectly so it would be difficult to encourage unless you can be sure you know which operations will be used.

If a reference to an object is declared as volatile, does it ensures safe object publication?

This is very dependant on the order and type of operations. In this case, the write

this.n = n;
// and then
holder = ...

The write to holder ensure the write to this.n must be visible assuming you also do

Holder h = holder; // read barrier
// n must be set.
int n = this.n;

declaring the member field volatile still doesnt guarantee publication prior to holder being visible

I don't agree in this case. Once you have obtained the holder in another thread, there is no chance that reading n will fail to see the value initialised as you are reading a volatile variable. This is because the holder is set only after n is initialised.

这篇关于关于 volatile 关键字的一些说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆