java中同一方法的多线程

时间:2016-12-02 17:20:49

标签: java multithreading

package newpackage;

import java.util.logging.Level;
import java.util.logging.Logger;

class test {

    public int in = 0;

    void helper() {

        Thread t1 = new Thread(
                ()
                -> {

            add();

        }
        );

        Thread t2 = new Thread(
                ()
                -> {

            add();

        }
        );
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException ex) {
            Logger.getLogger(test.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    void add() {
        for (int i = 0; i < 40; i++) {
            in += i;
            try {
                Thread.sleep(50);
            } catch (InterruptedException ex) {
                Logger.getLogger(test.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

}

public class Main {

    public static void main(String[] args) {
        test a = new test();
        a.helper();
        System.out.println(a.in);
    }
}

我想要的是同时从不同的线程运行相同的方法。

但上面给出的代码并没有给出正确的结果。它的输出小于1560(780 + 780)。我怎样才能实现呢?

提前致谢。

1 个答案:

答案 0 :(得分:1)

您遇到了并发程序的一个经典问题。没有适当同步的可变共享状态。您的变量in会被两个线程同时修改,而且i += 1操作不是原子操作。实际上发生的事情是:

int temp = i + 1;
i = temp;

现在的问题是两个线程同时运行,所以会发生这样的事情:

// assuming i == 3
int temp = i + 1; // Thread 1, temp == 4
int temp = i + 1; // Thread 2, temp == 4
i = temp; // Thread 2, i == 4
i = temp; // Thread 1, i == 4

正如你所看到的,我们已经增加了两次,但是我只增加了1.此外,因为你的变量不是volatile,或者任何东西都没有跨线程的可见性保证,这意味着如果线程1修改了变量,那么JVM就不能保证使该变化对读取变量的任何其他线程可见。

要正确执行此操作,您需要使用某种同步辅助,最简单的是synchronized块。然而,在这种情况下,这会破坏并行添加内容的目的,因为同步会使事情按顺序有效运行,但会产生一些开销。

如果您真的想要并行添加内容,请查看Java 7 Streams或Java 7中的Fork-Join Framework。请注意,这样做只需要足够大的数据集,因为并行运行总是随附一些开销。