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)。我怎样才能实现呢?
提前致谢。
答案 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。请注意,这样做只需要足够大的数据集,因为并行运行总是随附一些开销。