问题描述
- java多线程操作同一个变量的问题,难道是多核cpu所致?
-
大家请看代码和输出结果,我百思不得其解,为什么 amount只加了一次,开始我以为是static所致,就算去掉也还是有几率出现这样的结果,难道是多核cpu真的把两个线程同时执行了?package study; public class MyRunnable implements Runnable { public static int amount=0; @Override public void run() { // TODO 自动生成的方法存根 amount++; String s=Thread.currentThread().getName(); System.out.println(s+" "+amount); } } package study; public class MyFirstThread { public static void main(String[] args) { // TODO 自动生成的方法存根 MyRunnable r1=new MyRunnable(); Thread AThread=new Thread(r1); Thread BThread=new Thread(r1); AThread.start(); BThread.start(); for(;;) { if((!AThread.isAlive())&&(!BThread.isAlive())) { System.out.println("amount ="+r1.amount); break; } } } }
解决方案
没有加同步锁的问题,两个线程是同时执行的,amount什么值都有可能,可能都是1,可能打印都是2,也可能打印2,1。所以需要对amount加同步锁
public static Integer amount=0;
@Override
public void run() {
// TODO 自动生成的方法存根
synchronized(amount){
amount++;
String s=Thread.currentThread().getName();
System.out.println(s+" "+amount);
}
}
解决方案二:
如果只有一个处理器,仍然可能出现线程同步的问题,和什么多cpu同时执行没有关系。
我再说清楚一些
这是因为amount++;不是原子化的操作,它是这样的
int x = amount;
x = x + 1;
amount = x;
(这里x代表寄存器,amount代表内存)
我们假设你只有1个cpu,也就是执行本身不是并发的,但是有两个线程
假设amount = 0
线程1
int x = amount;
此时x = 0, amount=0
切换到线程2
注意,x是寄存器,每个线程独立,而amount是共享的,只有一个,所以为了避免混淆,这里x写成x1表示另一个变量
int x1 = amount;
此时x1=0 amount=0
x1 = x1 + 1;
此时x1=1
再切换到线程1
x = x + 1;
amount = x;
此时x = 1
amount=1
再切换到线程2
amount = x1;
记住,x1=1
所以amount=1
结果是1而不是2
为什么这样?因为x存的数据是脏数据,amount被另一个线程更新了,但是x没有更新。
注意,以上代码不是并行执行的,同样有同步问题。
解决方案三:
晕,线程没有同步,无论单核多核都需要线程同步。这是起码的常识。
解决方案四:
无论单核多核都不是同步执行的,CPU在各个线程随机执行(优先级高的线程得到CPU执行的机会更多),你所看到的同步,其实是CPU在线程之间切换执行,只是速度太快,我们无法跟上。
解决方案五:
可以看看龙书的线程同步,讲的十分仔细。 《operating system concepts》
解决方案六:
对,单核时代,同一时刻,只有一个执行,现在多核时代了