java 中多线程的意外答案
unexpected answers in multithreading in java
这是我的代码,使用 4 个线程将变量 'res' 乘以 4*10^7 次:
class MathSin extends Thread {
public double a;
public MathSin(int degree) {
a = degree;
}
@Override
public void run() {
for (int i = 0; i < Math.pow(10., 7); i++)
MathThreads.res++;
}
}
class MathThreads {
public static double res = 0;
public static void main(String args[]) {
MathSin st = new MathSin(8);
MathSin ct = new MathSin(8);
MathSin tt = new MathSin(8);
MathSin qt = new MathSin(8);
st.start();
ct.start();
tt.start();
qt.start();
try { // wait for completion of all thread and then sum
st.join();
ct.join(); // wait for completion of MathCos object
tt.join();
qt.join();
System.out.println(res);
} catch (InterruptedException IntExp) {
}
}
}
这些是一些答案:
1.8499044E7
2.3446789E7
.
.
.
我希望得到 3.0E7 但得到了另一个不同的答案。
如何解决这个问题?
有什么问题?
您在更新 static
变量时观察到竞态条件 res
。
MathThreads.res++
相当于:
double tmp = MathThreads.res;
MathThreads.res = tmp + 1;
如果两个线程同时读取 tmp
的值,并且都用 tmp + 1
更新 res
会发生什么?好吧,只是忘记了一个增量:res
结束为 tmp + 1
而不是 tmp + 1 + 1
!
因此,当 4 个线程同时更新 res
时,您只会以未定义的行为结束:由于这些竞争条件,无法预测 res
的最终值。两次执行相同的代码会得到不同的答案。
如何解决这个问题?
为了让你的代码线程安全,你需要为res
使用线程安全的结构:一个可以并发更新和访问的结构。
在你的情况下,AtomicLong
似乎是完美的选择:
public static AtomicLong res = new AtomicLong(0);
并且在运行方法中:
for (int i = 0; i < Math.pow(10., 7); i++) {
MathThreads.res.incrementAndGet();
}
这是我的代码,使用 4 个线程将变量 'res' 乘以 4*10^7 次:
class MathSin extends Thread {
public double a;
public MathSin(int degree) {
a = degree;
}
@Override
public void run() {
for (int i = 0; i < Math.pow(10., 7); i++)
MathThreads.res++;
}
}
class MathThreads {
public static double res = 0;
public static void main(String args[]) {
MathSin st = new MathSin(8);
MathSin ct = new MathSin(8);
MathSin tt = new MathSin(8);
MathSin qt = new MathSin(8);
st.start();
ct.start();
tt.start();
qt.start();
try { // wait for completion of all thread and then sum
st.join();
ct.join(); // wait for completion of MathCos object
tt.join();
qt.join();
System.out.println(res);
} catch (InterruptedException IntExp) {
}
}
}
这些是一些答案:
1.8499044E7
2.3446789E7
.
.
.
我希望得到 3.0E7 但得到了另一个不同的答案。
如何解决这个问题?
有什么问题?
您在更新 static
变量时观察到竞态条件 res
。
MathThreads.res++
相当于:
double tmp = MathThreads.res;
MathThreads.res = tmp + 1;
如果两个线程同时读取 tmp
的值,并且都用 tmp + 1
更新 res
会发生什么?好吧,只是忘记了一个增量:res
结束为 tmp + 1
而不是 tmp + 1 + 1
!
因此,当 4 个线程同时更新 res
时,您只会以未定义的行为结束:由于这些竞争条件,无法预测 res
的最终值。两次执行相同的代码会得到不同的答案。
如何解决这个问题?
为了让你的代码线程安全,你需要为res
使用线程安全的结构:一个可以并发更新和访问的结构。
在你的情况下,AtomicLong
似乎是完美的选择:
public static AtomicLong res = new AtomicLong(0);
并且在运行方法中:
for (int i = 0; i < Math.pow(10., 7); i++) {
MathThreads.res.incrementAndGet();
}