【问题标题】:one java memoryFlushing volatile: A good programdesign?一个java memoryFlushing volatile:一个好的程序设计?
【发布时间】:2019-12-17 14:32:08
【问题描述】:

这是一个与此相关的问题:java: using volatile at one variable VS each variable

我有一个或多个不同的对象。我想更改其中的某些状态,然后我想让该状态对其他线程可见。

出于性能原因,我不想使该对象中的每个成员变量都可变。 有时我想在单线程应用程序中使用这些对象。所以在那种情况下,volatile 也会很糟糕。

所以我有以下内容:

//these following mehtods change some internal variable state. These variables are not volatile or synchronized

boolean volatile memoryFlusher=false;

Thread1:

obj1->changeSomeState();
obj1->changeMoreState();
obj2->alsoSomeStateChange();

//and now i want to make that state visible to others

memoryFlusher=false; //volatile write


Thread2:

boolean tmp=memoryFlusher; // volatile read but variable is not used again

obj1->getState();
obj2->getState();

所以到目前为止,它与我在开头链接的相关问题或多或少相同。

所以现在我想问以下问题:

我的 memoryFlusher 没有被优化掉? (在我的另一个问题中没有回答) 每次 volatile 写入/读取都会刷新 ALL 的所有 memoryState?其他(也是非易失性)变量?

现在是真正的新问题:

这是一个好的设计吗? 因为我没有在任何地方看到任何这样的代码,所以我在这里发布。

我应该以其他方式对我的 Progamm 进行编程吗? 是否有其他最佳实践来提高性能并获得可见性? 在程序设计视图中是否有其他最佳实践,没有做这样的事情?

编辑:

我改变的状态是无关的。 所以我想要那个内存变量一个memoryflusher,并且没有锁定机制。它应该将许多单个 volatile 变量替换为一个。在某处我不需要显式的易失性内存刷新,因为我使用同步,例如

synchronized(x)
{
    ...
    obj1->stateChange() //if internally is used a volatile, then i have a volatile memory flush and later the synchronized-end memory-flush, i guess (is that right?)
    ...
}

这只是一个例子,它在哪里有用?!

总结: 但这是正确的吗,我认为以这种方式使用 memoryFlushing?

【问题讨论】:

    标签: java multithreading design-patterns concurrency volatile


    【解决方案1】:

    您的 volatile 读取和写入并未被优化掉,但我认为这段代码没有任何用处。这可能就是你在其他地方看不到它的原因。不过,您并没有说出您对它的期望,所以谁知道呢?

    您似乎想确保 Thread2 可靠地读取 Thread1 所做的状态更改。好吧,只有当您确定 Thread2 中的代码实际上在 Thread1 中的代码之后运行时,这才有效。

    你怎么知道是这样的?

    我建议如果确实有任何方法可以确保 Thread2 代码发生在 Thread1 代码之后,那么已经存在内存屏障确立了这一事实,并使您的 volatile 变量变得不必要。

    【讨论】:

    • 所以你的意思是,我不应该只将memoryFlusher用作memoryFlusher,更像是信号变量? if(memoryFlusher==true){...} 在第二个线程中?
    • 首先解释一下你想用这段代码完成什么
    【解决方案2】:

    我的 memoryFlusher 没有被优化掉?

    不,memoryFlusher 的写入和读取不会被优化掉。

    每次 volatile 写入/读取都会刷新 ALL 的所有 memoryState

    是的,它会将内存同步到两个线程。但是,它仅在您可以检测到从一个线程到另一个线程的更改时才有效。

    在您的示例中,您阅读了memoryFlusher,但memoryFlusher 在初始化时是false。你怎么知道Thread-1 真的写信给它?如果 Thread-1 位于 obj1 -> changeMoreState 这一行,而 Thread-2 读取 memoryFlusher 会怎样。这两个值都将是false,因此您不知道 Thread-1 是否实际完成。您不同步,因为您尚未建立先发生顺序。

    要更正您的代码,您应该将true 写入memoryFlusher 字段,并且只有在memoryFlusher 为真时,Thread-2 才应该继续。这有效地确定了您的顺序,但也使您的代码更加混乱。

    我建议使用StampedLock 而不是尝试这个。当写入不频繁时,StampedLock 可为您提供非常快速的读取。

    【讨论】:

    • 好的,但如果 Thread1 再次改变状态,那么我的信号变量已经为真;在那种情况下,我必须在 Thread2 中再次使信号变量无效,对吗?但是我应该在 Thread2 中再次将 memoryFlusher 设置为 false 吗?或者我应该在这里使用布尔值以外的东西?为什么这样更令人困惑?
    • And why its in that way more confusing? 你刚才所说的确切原因。也许混淆不是正确的术语,我可以更新它。它只会使代码在您的用例中更难以推理和出错。就您的观点而言(这是一个很好的观点),如果 Thread-1 确实再次更改了值怎么办?好吧,你运气不好,无法建立订单。您的代码只能执行一次。在这种情况下,StampedLock 更有意义。您可以多次使用StampedLock 来安全地更新这些字段。
    • 好吧,我想了几分钟:如果对象中的状态不相关,那么当 thread1 更改该值时,我不需要在 thread2 中知道。 Thread2 可以看到该值本身的变化。您提到的 StampedLock 与内部 CAS 操作的 java-synchronized 相同,对吧?因此,在这种情况下,我使用 StampedLocks 获得与锁定视图中的 java-synchronized 相同的行为。但我想存在我不想锁定状态的场景(如果状态不相关)。还是我现在有思考问题?^^
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-01
    • 2012-02-10
    • 1970-01-01
    • 2013-02-19
    • 1970-01-01
    • 2011-02-09
    相关资源
    最近更新 更多