1.线程的抢占式执行过程
线程的执行顺序不是固定的。哪个线程先抢到CPU就执行,哪怕是其中一个线程正在执行时,其他线程若是抢到了CPU,就会打断前一个的过程,先执行自己的。
2.多个线程修改同一个变量
比如两个线程都想对变量m=0进行加一操作,正常的话,m在两次加一之后应该变成2,但是由于线程的抢占式执行过程,线程二有可能在线程一刚刚读取m之后就开始执行,也从内存中读取m,此时线程一和线程二手中的m的值都为0,两个线程执行完毕之后m都为1,将m又存入内存,此时内存中的m=1,所以就出现了线程安全问题。
3.修改操作不是原子的
线程的修改操作不是原子性的,也就是说不是一个整体,线程的执行过程是可能被穿插的。线程二可能在线程一正在执行时,抢占CPU,打断线程一的执行。
就比如:你想吃苹果,你先拿去清洗,洗完之后,碰到你朋友,他也想吃,就把苹果从你手中抢过去吃了,他吃了几口觉得不想吃了,又把苹果还给你,这个时候你才能继续完成吃苹果这个最终过程。
4.内存可见性
本质:操作内存比操作缓存要慢很多,编译器的优化导致线程一修改的数据没有及时存入内存,线程二就读不到最新的数据。
工作内存:CPU寄存器和缓存
主内存:真实内存
例如线程一对变量m=0循环自增10次,线程二对变量m加一;
正常情况线程一对m每次加一之后都应该把m放回主内存中,但由于编译器的优化,所以每次加一之后新的m的值放在了工作内存中,只有到最后一次加一之后,才会将m的值放入主内存中,。
但是如果线程二在线程一执行过程中就读取m,是从主内存中读取的,所以读到的m=0,并不是新更改后的值,所以就会造成线程安全问题。
5.指令重排序
编译器会调整执行顺序,在逻辑不变的情况下提高效率。
调整顺序,也可能会造成线程安全问题;
比如:我去取快递,顺便帮舍友买饭。但是因为食堂离得近,我就先去买饭,然后去取快递;买完之后,准备去取快递。但是舍友以为我先去取得快递,饭还没有买,她就说不用买了,她吃泡面。但是此时饭已经买了,所以就造成了冲突。



