首先:
单线程也不会出现线程安全问题,多线程并发访问共享变量,没有保证原子、可见、有序会发生线程安全问题
多线程抢占CPU,指令被打断没有,原子段段代码没有被原子执行完。
--------------------------------------------------------------------------------------------------------------
主内存:里的共享变量会有线程安全问题
工作内存:里的变量不会出现线程安全问题线程私有的,如果是关联了主内存,共享资源也会出现问。
主内存(可以理解为堆里面属性和方法区里的static属性)主内存就一份
工作内存(可以理解为虚拟机栈)每个线程都有自己的工作内存
--------------------------------------------------------------------------------------------------------------
如果保证线程安全就要保证
原子性
可见性
有序性
--------------------------------------------------------------------------------------------------------------
在JVM层面:线程操作共享变量的时候不是直接操作主内存,而是先从主内存复制一份到自己的工作内存,在每个线程自己的工作内存中做修改,最后写回主内存。
这三个操作并不是原子的
--------------------------------------------------------------------------------------------------------------
加sychronized或者ReentrantLock锁会解决线程安全问题吗?
可以解决
在加锁的同步区,只有一个线程能进入,原子性、可见性、有序性都满足
--------------------------------------------------------------------------------------------------------------
volataile有什么用 ?
可见性:
有序性:volatile可以防止指令重排序,CPU和JIT都会优化指令顺序
指令重排序
原子性:volatile不能保证原子性
比如
i++;
Solution s = new Solution();
x += 1;
x = y;
都不是原子操作,即使加了volatile 也不能保证线程安全
加锁就可以解决为什么还要用volataile?
加锁是一个重量的开销
如果只需要解决变量对其他线程及时可见,或者防止指令重排序可以用volataile
--------------------------------------------------------------------------------------------------------------
原子操作不只是体现在JVM的内存模型的读写,复合的原子操作也要满足原子性
--------------------------------------------------------------------------------------------------------------