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

Java – 对可变对象的易失性引用 – 对对象的字段的更新对所有线

发布时间:2020-12-14 05:23:42 所属栏目:Java 来源:网络整理
导读:…没有额外的同步?下面的Tree类是为了被多个线程访问(它是一个单例,但不是通过枚举实现) class Tree { private volatile Node root; Tree() { root = new Node(); // the threads are spawned _after_ the tree is constructed } private final class Node
…没有额外的同步?下面的Tree类是为了被多个线程访问(它是一个单例,但不是通过枚举实现)
class Tree {

    private volatile Node root;

    Tree() {
        root = new Node();
        // the threads are spawned _after_ the tree is constructed
    }

    private final class Node {
        short numOfKeys;
    }
}

>读者线程对numOfKeys字段的更新是可见的,而没有任何明确的同步(注意读者和写者必须获取一个ReentrantReadWriteLock的实例 – 每个节点相同的实例 – 但是除此之外)?如果不是会使numOfKeys volatile足够吗?
>将root更改为root = new Node()(只有一个写入线程才能更改根,除了调用Tree构造函数的主线程)

有关:

> multiple fields: volatile or AtomicReference?
> Is volatile enough for changing reference to a list?
> Are mutable fields in a POJO object threadsafe if stored in a concurrentHashMap?
> Using volatile keyword with mutable object

编辑:有兴趣发布Java 5语义

解决方法

这两个问题.我们从第二个开始吧.

将新构造的对象分配给易变量变量工作得很好.读取volatile变量的每个线程都将看到一个完全构造的对象.不需要进一步的同步.这种模式通常与不可变类型结合使用.

class Tree {
    private volatile Node node;
    public void update() {
        node = new Node(...);
    }
    public Node get() {
        return node;
    }
}

关于第一个问题您可以使用volatile变量来同步对非易失性变量的访问.以下列表显示了一个示例.假设两个变量被初始化,如图所示,并且这两个方法是并发执行的.这是有保证的,如果第二个线程看到更新到foo,它也将看到更新bar.

volatile int foo = 0;
int bar = 0;

void thread1() {
    bar = 1;
    foo = 1; // write to volatile variable
}

void thread2() {
    if (foo == 1) { // read from volatile variable
        int r = bar; // r == 1
    }
}

但是,你的例子是不同的.阅读和写作可能如下.与上述示例相反,两个线程都从volatile变量读取.但是,对volatile变量的读操作不会相互同步.

void thread1() {
    Node temp = root; // read from volatile variable
    temp.numOfKeys = 1;
}

void thread2() {
    Node temp = root; // read from volatile variable
    int r = temp.numOfKeys;
}

换句话说:如果线程A写入volatile变量x并且线程B读取写入x的值,则在读操作之后,线程B将看到在写入x之前发生的线程A的所有写操作.但是没有对volatile变量的写入操作,对其他变量的更新没有影响.

这听起来比实际上更复杂.其实,只有一条规则要考虑,你可以在JLS8 §17.4.5找到:

[..] If all sequentially consistent executions are free of data races,[..] then all executions of the program will appear to be sequentially consistent.

简单地说,如果两个线程可以同时访问相同的变量,则存在数据竞争,至少有一个操作是写入操作,并且该变量是非易失性的.可以通过将共享变量声明为volatile来消除数据竞赛.没有数据竞争,更新的可见性没有问题.

(编辑:李大同)

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

    推荐文章
      热点阅读