public class ThreadExample implements Runnable {
private static int count;
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
count++;
}
}
public static void main(String[] args) {
ThreadExample threadExample=new ThreadExample();
Thread thread1=new Thread(threadExample);
Thread thread2=new Thread(threadExample);
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(count);
}
}
打印结果: 11084
分析原因:
首先理解下线程和进程的区别:
进程是代码在数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位;
线程是进程的一个执行路径,一个进程至少有一个线程,多个线程则会共享进程中的资源;
线程像病毒一样,不能够独立的存活于世间,需要寄生在宿主细胞中。线程也是不能够独立的生存在系统中,线程需要依附于进程存在。
程序执行count++这个操作时,JVM将会分为三个步骤完成(非原子性):
- 某线程从内存中读取
count。 - 某线程修改
count值。 - 某线程将
count重新写入内存。count++的3个步骤,由于线程会共享进程中的资源,所以在这三步中,任何一步都可能被其他线程打断,导致count值还没来得及写入,就被其他线程读取或写入。
假如count值为1,线程1读取到count值后,将count修改为2,此时还没来得及将结果写入内存,内存中的count值还是1。
另一个线程2,读取到count值为1后,也将其修改为2,并成功写入内存中,此时内存中的count值变为了2。
随后线程1也将count的结果2写入到内存中,count在内存中的结果依然是2(理应为3)。
上述场景中,两个线程各自执行了一次count++,但count值却只增加了1,这就是问题所在。