多线程应用程序中的不可变对象 - 它是如何工作的?

发布于 2024-11-26 02:15:34 字数 1255 浏览 1 评论 0原文

我有这段代码可以在多线程应用程序中工作。 我知道不可变对象是线程安全的,因为它的状态无法更改。如果我们有易失性引用,则可以使用例如进行更改 MyImmutableObject 状态 = MyImmutableObject.newInstance(oldState, newArgs);即,如果一个线程想要更​​新状态,它必须创建新的不可变对象,并使用旧状态和一些新状态参数对其进行初始化),并且这对所有其他线程都是可见的。 但问题是,如果线程 2 开始对状态进行长时间操作,其中线程 1 用新实例更新状态,会发生什么? Thread2 将使用对旧对象状态的引用,即它将使用不一致的状态?或者线程2将看到线程1所做的更改,因为对状态的引用是易失性的,在这种情况下,线程1可以在其长操作的第一部分中使用旧状态,在第二部分中使用新状态,这是不正确的?

State state = cache.get(); //t1 
Result result1 = DoSomethingWithState(state); //t1 
        State state = cache.get(); //t2
    ->longOperation1(state); //t1
        Result result2 = DoSomethingWithState(state); //t2
             ->longOperation1(state); //t2
   ->longOperation2(state);//t1
cache.update(result1); //t1 
             ->longOperation2(state);//t2
        cache.update(result2);//t2

Result DoSomethingWithState(State state) {
    longOperation1(state);
    //Imaging Thread1 finish here and update state, when Thread2 is going to execute next method
    longOperation2(state);
return result;
}

class cache {
     private volatile State state = State.newInstance(null, null);

    update(result) {
        this.state = State.newInstance(result.getState, result.getNewFactors);

    get(){
       return state;
    }

 }

I have this code will work in multithreaded application.
I know that immutable object is thread safe because its state cannot be changed. And if we have volatile reference, if is changed with e.g.
MyImmutableObject state = MyImmutableObject.newInstance(oldState, newArgs); i.e. if a thread wants to update the state it must create new immutable object initializing it with the old state and some new state arguments) and this will be visible to all other threads.
But the question is, if a thread2 starts long operation with the state, in the middle of which thread1 updates the state with new instance, what will happen? Thread2 will use reference to the old object state i.e. it will use inconsistent state? Or thread2 will see the change made by thread1 because the reference to state is volatile, and in this case thread1 can use in the first part of its long operation the old state and in the second part the new state, which is incorrect?

State state = cache.get(); //t1 
Result result1 = DoSomethingWithState(state); //t1 
        State state = cache.get(); //t2
    ->longOperation1(state); //t1
        Result result2 = DoSomethingWithState(state); //t2
             ->longOperation1(state); //t2
   ->longOperation2(state);//t1
cache.update(result1); //t1 
             ->longOperation2(state);//t2
        cache.update(result2);//t2

Result DoSomethingWithState(State state) {
    longOperation1(state);
    //Imaging Thread1 finish here and update state, when Thread2 is going to execute next method
    longOperation2(state);
return result;
}

class cache {
     private volatile State state = State.newInstance(null, null);

    update(result) {
        this.state = State.newInstance(result.getState, result.getNewFactors);

    get(){
       return state;
    }

 }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

大海や 2024-12-03 02:15:34

但是引用是易失性,这不是让新对象状态......对其他线程可见吗?

否。当写入易失性字段时发生在每次后续读取该字段之前,另一个线程必须重新读取该字段才能获取新值。

But the reference is volatile, isn't it making visible the new object state … to the other threads?

No. While a write to a volatile field happens-before every subsequent read of that field, the other thread must re-read that field to get the new value.

你的笑 2024-12-03 02:15:34

尽管您使用的是不可变对象,但您所描述的并不是线程安全的。即使thread1同时分配了state的新值,thread2仍继续作用于它最初获得引用的对象。在java中,对象引用是按值传递的。因此,当传递 DoSomethingWithState()longOperation1()state 参数时,该方法仅看到传递的对象引用,而不是稍后更改值。如果您希望此类代码是线程安全的,则需要同步作用于单例 state 对象的所有方法。

What you describe is not thread safe, despite the fact that you are using immutable objects. thread2 continues to act on the object it originally obtained a reference to, even if thread1 assigns a new value of state concurrently. In java, object references are passed by value. So when the state argument to DoSomethingWithState() or longOperation1() gets passed, the method sees only the object reference that was passed, not the changing values later. If you want this kind of code to be thread safe, you need to synchronize all methods that act on the singleton state object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文