同样的计算如何产生不同的结果

时间:2014-11-04 16:24:56

标签: java multithreading swing affinetransform

花两个小时调试一下,我想我知道问题的原因,但我不明白它怎么能产生这样的结果。

我有一个基于Swing的应用程序,我在这里覆盖JPanel.paint(Graphics g)

public void paint(Graphics g) {
    <snipped code>

    Insets is = getInsets();
    Dimension sz = getSize();
    g2.setClip(is.left + 1, is.top + 1, sz.width - is.right - is.left - 2, sz.height - is.top - is.bottom - 2);

    int w = getWidth();
    int h = getHeight();
    double s = Math.min(sz.getWidth(), sz.getHeight());

    AffineTransform mc = g2.getTransform();

    AffineTransform m1 = new AffineTransform(mc);
    m1.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
    m1.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
    m1.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

    AffineTransform m2 = new AffineTransform(mc);
    m2.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
    m2.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
    m2.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

    try {
        m_InverseViewTransform = m1.createInverse();
    } catch (NoninvertibleTransformException e) {

        AffineTransform m3 = new AffineTransform(mc);
        m3.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
        m3.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
        m3.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));

        System.out.println("m1 = " + m1);
        System.out.println("m2 = " + m2);
        System.out.println("m3 = " + m3);

        AffineTransform m4 = new AffineTransform(mc);
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getTranslateInstance(-m_CenterX, -m_CenterY));
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getScaleInstance(m_ScaleX * s, -m_ScaleY * s));
        System.out.println("m4 = " + m4);
        m4.preConcatenate(AffineTransform.getTranslateInstance(w / 2, h / 2));
        System.out.println("m4 = " + m4);

        System.out.println(w); 
        System.out.println(h);
        System.out.println(s);
        System.out.println(m_CenterX);
        System.out.println(m_CenterY);
        System.out.println(m_ScaleX);
        System.out.println(m_ScaleY);

        e.printStackTrace();

现在这个谜团,有时当我启动应用程序时,通常会说四次中的三次,会抛出NoninvertibleTransformException。

正如您可以看到调试我输出有问题的矩阵和其他三个相同计算的矩阵以及用于形成这些矩阵的变量。

这就是它变得有趣的地方,看下面的输出,所有矩阵都没有相同的值!

m1 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m2 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m3 = AffineTransform[[0.0, 0.0, 400.0], [0.0, -0.0, 289.0]]
m4 = AffineTransform[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]
m4 = AffineTransform[[1.0, 0.0, -49.5], [0.0, 1.0, -0.362762953421903]]
m4 = AffineTransform[[5.254545454545455, 0.0, -260.1], [0.0, -587.9922126928986, 213.3017916655554]]
m4 = AffineTransform[[5.254545454545455, 0.0, 139.89999999999998], [0.0, -587.9922126928986, 502.3017916655554]]
800
578
578.0
49.5
0.36276295342190257
0.009090909090909092
1.0172875652126274
java.awt.geom.NoninvertibleTransformException: Determinant is 0
at java.awt.geom.AffineTransform.createInverse(AffineTransform.java:2706)

更有趣的东西,如果我适当地移动调试输出/计算以深入研究这个问题就会消失。

这只发生在jdk1.8.0_25.jdk的JRE上(在Mac OS X 10.8.5上),而不是Java 1.6或1.6。

好吧,我认为真正的罪魁祸首是JPanel不是在Event Dispatched线程中创建的,一旦我这样做,异常永远不会抛出没有不一致。

显然,线程与时序相关的问题非常明显,但我很好奇如何在Java JVM&#39;规则中发生这种情况。所涉及的所有变量都是方法的局部变量,来自AffineTransform的矩阵方法不应该有副作用,所以很难理解线程问题如何导致这样的事情......

对于我的想法,我想了解这里发生了什么。

作为副作用,这个问题可能有助于一些可怜的灵魂在类似问题上挣扎。

另外我不介意,如果有人设法指出代码/调试/扣除中明显的缺陷,因为我现在已经盯着那些线几个小时......

1 个答案:

答案 0 :(得分:1)

如果该方法不依赖于任何共享数据,则它无法展示您描述的行为。但是,您所呈现的内容并不清楚,您的方法可以避免共享数据。我特别怀疑变量m_CenterXm_CenterYm_ScaleXm_ScaleY。这些类似于您的类的实例变量,如果是这样,那么它们肯定在实例化类和EDT的线程之间共享。如果没有正确的同步,EDT可能会在构造函数(或在另一个线程中调用的其他方法)为它们分配值之前看到这些变量的默认值。

更一般地说,通过EDT中运行的方法直接或间接访问的类的任何实例变量在EDT和创建对象的线程之间共享(如果它们不同)。