在这种情况下,是否会抛出此AssertionError?

编程入门 行业动态 更新时间:2024-10-11 19:21:21
本文介绍了在这种情况下,是否会抛出此AssertionError?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

首先关闭代码,从JCIP列出 jcip/listings/StuffIntoPublic.java 和 jcip/listings/Holder.java

public class SafePublication { public static void main(String [] args)throws InterruptedException { // System.out.println(Thread.currentThread()。getName()); StuffIntoPublic t = new StuffIntoPublic(); t.initialize(); while(true){ new Thread(() - > {t.holder.assertSanity();})。start(); } } } // @作者Brian Goetz和Tim Peierls class StuffIntoPublic {公众持有人; public void initialize(){ // System.out.println(Thread.currentThread()。getName()); 持有人=新持有人(42); } } // @作者Brian Goetz和Tim Peierls 类持有人{ private int n; public Holder(int n){ this.n = n; } public void assertSanity(){ if(n!= n){ throw new AssertionError(This statement is false。); } } }

我说的是AssertionError因为Thread.start()在保证之前发生,所以在这种情况下永远不会抛出。注释的两个System.out.printlns都打印main,这意味着主线程通过在while(true)循环中的线程上创建和调用start来生成所有后来的线程。

由于那是创建和初始化Holder的线程,所有后续线程都可以安全地成为一个完全可见的持有者,因为之前发生了保证。我是对的吗?

我甚至尝试运行此代码很长时间没有断言错误。

但是,如果main看起来如下,那么我相信AssertionError可能是

public static void main(String [ ] args)抛出InterruptedException { System.out.println(Thread.currentThread()。getName()); StuffIntoPublic t = new StuffIntoPublic(); new Thread(() - > t.initialize())。start(); while(true){ new Thread(() - > {t.holder.assertSanity();})。start(); } }

解决方案

是,这是安全的,因为线程#start 保证发生在之前。更加罗嗦:对 Thread #start 之前发生的任何变量的任何读/写(如果你想要,我倾向于按程序顺序认为 ),也将发生之前该线程内的任何操作(它的运行方法)。

<事实上,如果之前没有发生(允许重新排序)并且程序执行允许那些潜在的重新排序,那么可能会发生破坏并抛出该错误。我甚至倾向于说和一个适用于弱内存模型的CPU(假设你是英特尔,这是一个强大的内存模型)可以增加这个机会,但我不确定。

因此,据我所知,这些操作将按以下顺序进行:首先,使用变量 n重新排序发布引用(之前没有发生过,所以这是允许的)。 Thread1创建 Holder 的实例。 Thread2看到发布的引用并调用该方法。它读取变量 n 为零(请记住重新排序发生并且 n 尚未编写,因此默认值为零),因此它会执行!= 检查,但是创建 Holder 的Thread1,将 n 写为 12 例如之前 Thread2再次读取它(在!= n 部分中)。所以这可能会失败。

使值 final 可以解决这个问题,因为它会引入正确的内存障碍,或者发生在之前规则。

First off the code, from JCIP listing jcip/listings/StuffIntoPublic.java and jcip/listings/Holder.java

public class SafePublication { public static void main(String[] args) throws InterruptedException { // System.out.println(Thread.currentThread().getName()); StuffIntoPublic t = new StuffIntoPublic(); t.initialize(); while (true) { new Thread(() -> { t.holder.assertSanity(); }).start(); } } } //@author Brian Goetz and Tim Peierls class StuffIntoPublic { public Holder holder; public void initialize() { // System.out.println(Thread.currentThread().getName()); holder = new Holder(42); } } //@author Brian Goetz and Tim Peierls 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."); } } }

I am saying that the AssertionError will never be thrown in this case because of the Thread.start() happens before guarantee. Both of the System.out.printlns that are commented prints main, meaning that the main thread is which spawns all the later threads by making and calling start on the threads in the while(true) loop.

And since that is the thread that created and initialized Holder, all subsequent threads are safe to be a perfectly visible holder due to the happens-before guarantee. Am I right?

I even tried running this code for a really long time and no assertion errors.

However, if the main looked like below, then I believe it will be possible for an AssertionError

public static void main(String[] args) throws InterruptedException { System.out.println(Thread.currentThread().getName()); StuffIntoPublic t = new StuffIntoPublic(); new Thread(() -> t.initialize() ).start(); while (true) { new Thread(() -> { t.holder.assertSanity(); }).start(); } }

解决方案

Yes, this is safe, because Thread#start guarantees happens-before. To be more wordy: any read/write to any variable that happens before Thread#start (I tend to think above in program order if you want), will also happen before any action within that Thread (it's run method).

Indeed, that could happen to break and throw that error, if there were no happens before (to allow re-orderings) and if program execution would allow those potential re-orderings. I am even inclined to say and a proper CPU used with weak memory model (assuming you are on Intel, which is a strong memory model) could increase that chance, but I am not sure.

So, as far as I can tell, the actions would take place in the following order: first the the publishing the reference is re-ordered with variable n (there is no happens-before, so this is allowed). Thread1 creates an instance of Holder. Thread2 sees that published reference and calls that method. It reads the variable n to be zero (remember that re-ordering happened and n is not yet written, thus has a default value of zero), so it then does the != check, but Thread1 that created Holder, writes n to be 12 for example before Thread2 reads it again (in the !=n part). So this can fail.

Making the value final would solve this as it introduces the right memory barriers, or happens-before rules.

更多推荐

在这种情况下,是否会抛出此AssertionError?

本文发布于:2023-11-12 13:13:29,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1581602.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:在这种情况下   是否会   抛出   AssertionError

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!