public class Bank {
private int sum=0;
public void add(int n) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
sum+= n;
System.out.println(sum);
}
}
public class Consumer implements Runnable {
Bank bank = new Bank();
@Override
public void run() {
for (int i = 0; i < 10; i++) {
bank.add(100);
}
}
}
public class Tes2 {
public static void main(String[] args) {
Consumer consumer = new Consumer();
Thread thread1 = new Thread(consumer);
Thread thread2 = new Thread(consumer);
thread1.start();
thread2.start();
}
}
这是一个多线程程序,模拟是向银行的多个存款人存款,用于演示多线程安全问题。由于代码不同步,因此其第一和第二结果可能是200 / 200,200 / 300,依此类推。但是我不明白为什么你会得到100/100,谁能解释?
答案 0 :(得分:3)
如果仅基于代码中的行来考虑该程序的并发性,则100/100输出结果将毫无意义。但是,您还必须考虑执行这些行时实际上正在发生什么指令。每行代码可以包含许多汇编指令。在这种情况下,要将n
添加到sum
,实际上发生的是从存储器中读取sum
的值,可能将其加载到寄存器中,然后递增,然后重新写入存储器中。
在以下情况下可能会发生100/100输出。假设线程1和线程2都调用bank.add(100)
,并且库异步处理请求。也就是说,银行有一个处理每个请求的线程。
然后,存储区的线程1加载sum
的值,该值为零。线程2也紧随其后加载sum
的值,该值仍为零。然后,线程1获得它加载的值,将n=100
加起来,然后将其写入内存。线程2执行相同的操作;它采用先前加载的总和的值,0,加100,然后写回内存。然后,它们各自打印出100的值。
答案 1 :(得分:3)
这是比赛条件。
两个线程都可以求和。
sum + = n;不是原子的
线程1读取总和0
线程2换入,因为未同步的代码将sum读取为0
线程1将100加到0,并将其写入总和
线程2将100加0并将其写入以求和覆盖线程1s的值