为什么即使运行了这么长的时间也永远不会抛出AssertionError? [英] Why is this never throwing an AssertionError even after running it for so long?

查看:73
本文介绍了为什么即使运行了这么长的时间也永远不会抛出AssertionError?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是原始代码

//@author Brian Goetz and Tim Peierls
@ThreadSafe
public class SafePoint {
    @GuardedBy("this") private int x, y;

    private SafePoint(int[] a) {
        this(a[0], a[1]);
    }

    public SafePoint(SafePoint p) {
        this(p.get());
    }

    public SafePoint(int x, int y) {
        this.set(x, y);
    }

    public synchronized int[] get() {
        return new int[]{x, y};
    }

    public synchronized void set(int x, int y) {
        this.x = x;
        this.y = y;
    }
}

这里私有int x,y不是最终值是很好的,因为构造函数中的set方法在调用get时会在关系发生之前发生,因为它们使用相同的锁.

Here it is fine that the private int x,y are not final because the set method in the constructor makes for a happens before relationship when calling get because they use the same lock.

现在这里是修改后的版本和主要方法,我希望在运行该方法后再抛出AssertionError,因为我在set方法中删除了synced关键字.如果有人指出它不是线程安全的,我就将构造函数私有化为唯一的调用者,这不是我关注的重点.

Now here is the modified version and a main method that I expected to throw an AssertionError after running it for a little bit because I removed the synchronized keyword in the set method. I made it private for the constructor to be the only one calling it in case someone was going to point out that it's not thread-safe because of it, which isn't the focus of my question.

无论如何,我已经等了很长时间,并且没有抛出AssertionErrors.现在,我厌倦了这种修改过的类在某种程度上是线程安全的,即使从我学到的知识来看,这也不是因为x和y不是最终的.有人可以告诉我为什么仍然从不抛出AssertionError吗?

Anyhow, I've waited quite a bit now, and no AssertionErrors were thrown. Now I am weary that this modified class is somehow thread-safe, even though from what I've learned, this is not because the x and y are not final. Can someone tell me why AssertionError is still never thrown?

public class SafePointProblem {
    static SafePoint sp = new SafePoint(1, 1);

    public static void main(String[] args) {
        new Thread(() -> {
            while (true) {
                final int finalI = new Random().nextInt(50);
                new Thread(() -> {
                    sp = new SafePoint(finalI, finalI);
                }).start();
            }
        }).start();
        while (true) {
            new Thread(() -> {
                sp.assertSanity();
                int[] xy = sp.get();
                if (xy[0] != xy[1]) {
                    throw new AssertionError("This statement is false 1.");
                }
            }).start();
        }
    }
}

class SafePoint {
    private int x, y;

    public SafePoint(int x, int y) {
        this.set(x, y);
    }

    public synchronized int[] get() {
        return new int[]{x, y};
    }

    // I removed the synchronized from here
    private void set(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void assertSanity() {
        if (x != y) {
            throw new AssertionError("This statement is false2.");
        }
    }
}

推荐答案

您已长时间运行 这个事实并不意味着任何事情,它仅表示片刻,您没有重现此内容;可能使用不同的jreCPU,这可能会中断.尤其糟糕的是,由于墨菲法则将保证这种情况将在生产中的某处发生,并且您将面临调试的噩梦.

The fact that you have run this for a lot of time does not mean anything, it just means that at the moment you did not reproduce this; may be with a different jre or CPU this could break. Especially bad since the Murphy law will guarantee that this will happen somewhere in production and you will have a nightmare to debug.

一个小例子并不能证明是好的/正确的代码,特别是对于并发代码来说,这是非常困难的(我什至不敢说我完全理解它).而且您确实知道,这很可能是不好的,因为之前没有发生任何事情.

A small example is not proof of good/correct code, especially true for concurrent code - which is extremely hard (I don't even dare to say to that I fully understand it). And you do understand that this is potentially bad since there is no happens-before.

还将这些变量设置为final意味着您无法通过setters进行设置,而只能在构造函数中进行设置.因此,这意味着您不能有一个setter,因此,一旦设置了字段xy,没有人可以更改它们,因此,get根本不应该被同步(我在这里谈论您的SafePoint)

Also making those variables final will mean that you can not set them via the setters, but only in constructor. So this means you can't have a setter, thus no one can alter the fields x and y once they are set, thus get is not supposed to be synchronized at all (I am talking about your SafePoint here)

这篇关于为什么即使运行了这么长的时间也永远不会抛出AssertionError?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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