由于多线程并发执行导致代码出现bug,就叫做线程不安全,具体的比如,新建一个thread1;
新建一个thread2;同时两个线程开始并发执行,针对变量int count=0;各自进行++5000.次;按理说得到的结果应该是100000;可使由于线程不安全导致的bug;实际上a最后的结果并不是100000;
而是小于100000的一个数,
线程安全问题是系统调度线程时候,用抢占执行的方式进行调用,某个线程什么时候上cpu执行完全不确定,如两个线程在两个cpu也可以完全并行执行,因此具体的顺序是不确定的
比如线程的工作分为1.读取,2.传到cpu上进行++,3.保存自增后的值;
如果两个线程按照这种顺序执行那么不会产生线程安全问题,可实际上并不是这么执行的,由于线程之间的抢占执行;线程A读取要++的数为0;刚刚读取完;被b抢占完成了线程b的工作;此时b中保存的数为1;而a此时应该执行第二部工作导致自增的对象还是0;因此自增两次却只得到了一次的结果,这就导致了本来是100000的预期结果,实际上要小很多。
在极端情况下,如果每次自增都发生了线程的安全问题,那么得到的最终结果应该是50000;
如果压根没有发生线程的安全问题,那么最终的结果应该是100000;
线程不安全的原因大概总结以下五点:
1.根本原因:线程之间的抢占执行方式;线程之间里的先后顺序无法确定,这样导致结果的随机性就是根本原因
2.多个线程修改同一个变量,归根结底还是抢占执行方式的结果
(1).如果一个线程修改一个变量那么不会发生抢占,不涉及并发,结果是确定的
(2)多个线程单单读取也不会涉及安全问题
(3)多个线程修改多个变量的话,一个线程对应一个变量,也不会涉及安全问题
3.原子性
是指这个线程执行的操作是可分的,举一个简单的例子;把大象放进轿子;很明显分三个步骤;线程执行如果只有一步不会被拆解也不会涉及线程安全问题;如单单给变量赋值就是一个原子性操作。
4.内存可见性
涉及编译器的优化问题,如线程a只完成了数据的读取,此时被b抢占执行,b中对自增对象执行多次自增,那么系统会优化;提高系统的效率;不采用自增一次保存一次的方式;而是自增多次结束后直接再保存;就会出现a读取数据出现问题。
5.指令重排序
编译器会自动调整指令的顺序达到高效率的效果,可能会产生如内存可见性一样的bug