线程内存模型
线程在工作的时候,如果涉及到需要访问对象的某个成员变量,比如下面的这个类里的amount 属性:
class Goods {
private int amount;
// balabala.....
}
线程在运行期间,首先把这个属性从主内存里load进自己的工作内存,然后对这个变量做修改,改完之后save 到主内存里,这个就是线程的线程模型。另一方面,我们所说的线程的原子性,也是这么一个过程,也就是说如果线程在从 load ——> save 到save 这个过程没有受到其他线程的影响,那么就可以认为这个是原子性的,假如在这个过程中有其他线程修改了 amount 的值,那么上一个线程的过程就被打破了,该线程的原子性就被破坏了,举个例子
如果把这个amount 设置为 volatile 的话,当一个线程修改了这个amount 之后,其他线程立即可见,就会有如下的场景:
线程1:load——> 修改 ————————>save
线程2:load——————> 修改————> save
这时候线程2 修改的数据在save到主内存之前,线程1是可见的,也就是说线程1的修改被线程2覆盖掉了,就破坏了线程1的原子性
线程安全性
要理解线程安全性,首先要搞明白几个东东:
1. 对象
2. 线程
3. 共享变量(或者叫类成员变量)
4. 同步或者锁
5. 线程执行方法的过程
线程是可以在任何地方创建的,它就是一个工具,用来执行代码的工具,创建线程和我们的类,对象等没有任何关系,理解的时候可以把线程和我们的代码隔离开来,如下:
线程虽然是由我们的代码创建出来的,但是线程本质上和我们代码没有关系,线程是操作系统层面的东西
多线程问题的根本原因是由于多个线程同时操作了同一个对象的成员变量,而且这个变量没有做同步处理,这就会有多线程问题,所以如果一个对象没有成员变量,那么就不会有多线程问题,因为如果一个对象只有方法的话,那么方法是在线程自己的内存空间执行的(线程内存里有栈帧,就是用来执行方法),所以在方法内所产生的对象都是存储在线程自己的内存空间的,不存在线程安全问题
所以总结下多线程问题的必要条件:
1. 多个线程同时操作一个对象(或者操作同一个静态方法),如果每个线程都操作的是不同的对象,则不存在线程安全问题,因为每个对象都有自己的内存空间,线程操作对象的数据都是存在各自对象的内存空间里,不存在数据共享
2. 多个线程所操作的方法里,必须有对成员变量的修改