你能帮我弄清楚这个 Snipped of Java-code 应该做什么吗?

Can you help me figuring out, what this Snipped of Java-code is supposed to do?

我在求职面试问题中找到了这段 Java 代码,并试图弄明白。 (我是一个 Smalltalker,可能不像我想的那样熟悉 Java 的语法)。

据我所知,它为数据矩阵中的每一行生成一个线程。该线程似乎成对处理行向量中的每一列。它检查对中的第一项是否大于第二项。如果为真,它会增加一个全局计数器(?)并对数据做一些我不明白的事情(What's "or" defined to do with integers in Java?)。

我相信它也以某种方式损坏了。你能帮我弄清楚吗?我想了解发生了什么。

public static int process(int [][] data) {
    final Object[] c = new Object[]{0};
    Object[] p = new Object[data.length];
    for (int i = 0; i < p.length; i++) {
        final int [] r = data[i];
        p[i] = new Thread() {
            public void run() {
                for (int s0 = 0, s1 = 0; s0 < r.length - 1; s0++, s1 = s0 + 1) {
                    if (r[s0] > r[s1]) {
                        // what is this next line supposed to do?
                        r[s0] ^= r[s1]; r[s1] ^= r[s0]; r[s0] ^= r[s1];
                        // does this next line increase a global counter?
                        c[0] = ((Integer) c[0]) + 1;
                    }
                }
            }
        };
    }
    return (Integer) c[0];
}

这段代码有几个主要问题,这里有几个:

  • 线程已创建,但从未启动。这意味着它们包含的代码将 永远不会 运行。为此,必须在创建的每个线程上调用 start() 方法。
  • 线程不是 "joined" 最后,因此该方法将 return 在线程有机会执行计算之前 c[0] 中的值。为此,必须在创建的每个线程上调用 join() 方法。
  • 线程对 c[0] 的更新不是线程安全的。该数据由多个线程并发访问,需要某种类型的锁定机制进行保护。
  • 在内循环的第一次迭代中,s0s1都是0,在进一步的迭代中,s1比[=21早一个=].不知道算法实际想要什么,这可能正确也可能不正确,但看起来很可疑。

此外,还有一些奇怪的事情:

  • 为什么要声明一个对象的单元素数组c,因为它只有一个元素,而且从不作为数组使用,而是作为简单的变量。我们可能想在这里使用 AtomicInteger。这也将解决并发访问问题,因为 AtomicInteger 提供线程安全。
  • 未输入任何内容。例如数组 p 应该是 Thread 个对象的数组:

    Thread p[] = new Thread[data.length];
    

    同理,c的类型应该是Integer[](或AtomicInteger

我已经注释了下面的代码:

// Method declaration, takes a two-demensional array of integers
public static int process(int [][] data) {
    // Create a one-demensional array of Objects, containing 
    // a single element, `0`.  This will be "auto-boxed" from
    // a primitive int to an Integer object.
    final Object[] c = new Object[]{0};
    // Create a one dimensional array of Objects, of the same
    // size as the first dimension of data
    Object[] p = new Object[data.length];

    // Loop through each index of the array p, declared above
    for (int i = 0; i < p.length; i++) {
        // get a reference, r, to the ith "row" of data
        final int [] r = data[i];
        // create a new Thread, and store a reference to it in p[i]
        p[i] = new Thread() {
            // This is the method that will be invoked on a separate
            // thread of execution by the java virtual machine
            public void run() {
                for (int s0 = 0, s1 = 0; s0 < r.length - 1; s0++, s1 = s0 + 1) {
                    if (r[s0] > r[s1]) {
                        // perform an xor-swap of two elements in the
                        // array (as pointed out by Jongware)
                        r[s0] ^= r[s1]; r[s1] ^= r[s0]; r[s0] ^= r[s1];
                        // this access of c[0] is not thread-safe
                        c[0] = ((Integer) c[0]) + 1;
                    }
                }
            }
        };
    }
    // return the value in c[0]
    return (Integer) c[0];
}

这是我修复了上面提到的所有问题的版本:

public static int process(int [][] data) {
    final AtomicInteger c = new AtomicInteger();
    Thread[] threads = new Thread[data.length];
    for (int i = 0; i < data.length; i++) {
        final int [] row = data[i];
        threads[i] = new Thread() {
            public void run() {
                for (int s0 = 0, s1 = 1; s0 < row.length - 1; s0++, s1 = s0 + 1) {
                    if (row[s0] > row[s1]) {
                        row[s0] ^= row[s1]; row[s1] ^= row[s0]; row[s0] ^= row[s1];
                        c.incrementAndGet();
                    }
                }
            }
        };
        threads[i].start();
    }
    try {
        for (Thread thread : threads)
            thread.join();
    } catch (InterruptedException e) {}
    return c.intValue();
}