多线程安全问题有以下五个原因。
1.操作系统对线程的随机调度和线程的抢占式执行
2.两个线程同时修改同一变量
以上两个原因分别由于涉及操作系统工作原理和实际需求不能改变,所以多线程问题通常从下面三点解决。
3.操作系统的指令不是原子性的
操作系统指令的非原子性导致多线程对代码的执行顺序超出人们的预期,从而引发线程安全问题。
例如count++由load(取变量)、add(修改)、save(返回变量)三个指令完成,线程的调度可能出现如下情况 count=0;
解决方案 : 加锁
synchronized(锁对象){
需要锁的代码
}
通过加锁使操作系统的指令具有原子性,从而解决线程安全问题。
加锁可能出现的问题:死锁
死锁产生的原因及解决方法,只需解决一个便不会产生死锁。
1.锁的互斥特性(无法更改)
2.锁的不可剥夺/不可抢占(无法更改)
3.线程对锁的请求和保持(打破锁的嵌套)
4.线程对锁的循环等待(约定枷锁顺序)
4.内存可见性问题
编译器会对代码进行优化,某些情况可能会使线程不从主内存中获取变量最新值,从而引发线程安全问题。
解决方案:关键词volatile
volatile可以保证变量的修改使每个线程都可看见,volatile修饰的变量每次使用都会从主内存中获取,修改后都会返回到主内存。
5.指令重排序
编译器会对代码进行优化,可能会使代码的执行顺序发生改变,从而引发线程安全问题。
解决方案:关键词volatile
volatile可以保证被修饰变量的相关操作不被重排序