我正在尝试创建一个简单的程序来计算PI,并教我自己多线程的工作原理。每次我运行程序时,我都会得到不同的PI答案。我假设它与每次以不同顺序运行的Threads有关,但是在我输出我的答案之前我在每个Thread上调用了Thread.join(),所以我不确定为什么计算的顺序是在会影响我的最终答案。我也尝试创建一个我已命名为add的同步方法,以便更新Pi变量线程安全,并将volatile修饰符添加到我的pi变量,但这并没有阻止问题的发生。我所拥有的代码全部保存在一个类中,即
public class Pi implements Runnable{
static volatile double pi = 0;
static long numRects = 100;
static int rectsPerThread = 1 ;
static double width = 1.0 / numRects;
long start, end;
public Pi(long start, long end){
this.start = start;
this.end = end;
}
@Override
public void run(){
double tmp = 0;
for(long i = start; i < end; i++){
tmp += Math.sqrt(1.0 - Math.pow(width * i, 2)) * width;
}
add(tmp);
}
private synchronized void add(double partOfPi){
pi += partOfPi;
}
public static void main(String[] args){
Thread[] threads = new Thread[(int)(numRects / rectsPerThread)];
double start = System.nanoTime();
for(int i = 0; i < threads.length; i++){
threads[i] = new Thread(new Pi(i * rectsPerThread, i * rectsPerThread + rectsPerThread));
threads[i].start();
}
for(Thread t : threads){
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
pi *= 4;
System.out.println(pi);
System.out.printf("Ran in: %.4fms", (System.nanoTime() - start) / Math.pow(10, 6));
}
}
我的问题如下:我的多线程错误导致每次都会返回不同的答案,我该怎么办呢?
答案 0 :(得分:0)
以下,
var += expr;
不是原子操作。旧值被读取,递增和写回,因此它不是线程安全的。你需要用信号量来防范它。
import java.util.concurrent.Semaphore;
public class Pi implements Runnable{
static double pi = 0;
static long numRects = 100;
static int rectsPerThread = 1;
static double width = 1.0 / numRects;
long start, end;
private static final Semaphore s = new Semaphore(1);
public Pi(long start, long end){
this.start = start;
this.end = end;
}
@Override
public void run(){
for(long i = start; i < end; i++){
try{
s.acquire();
}catch (InterruptedException IE){
return;
}
pi += Math.sqrt(1.0 - Math.pow(width * i, 2)) * width;
s.release();
}
}
public static void main(String[] args){
Thread[] threads = new Thread[(int)(numRects / rectsPerThread)];
double start = System.nanoTime();
for(int i = 0; i < threads.length; i++){
threads[i] = new Thread(new Pi(i * rectsPerThread, i * rectsPerThread + rectsPerThread));
threads[i].start();
}
for(Thread t : threads){
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
}
pi *= 4;
System.out.println(pi);
System.out.printf("Ran in: %.4fms", (System.nanoTime() - start) / Math.pow(10, 6));
}
}