Java内存模型规定所有变量都是存在主存当中(即物理内存),每个线程都有自己的工作内存(类似高速缓存),线程对变量的操作都是在工作内存中进行,而不能直接对主存进行操作,每个线程不能访问其他线程的工作内存。
1.原子性
Java内存模型只保证了对基本数据的读取和赋值是原子性操作,如果要实现更大范围操作的原子性,可以通过synchronized和lock来实现(能够保证任一时刻只有一个线程执行该代码块,所以自然不存在原子性问题)。
2.可见性
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其它线程读取时,它会去内存中读取新值,此外synchronized和lock能够保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中,因此可以保证可见性。
3.有序性
Java内训模型具备一些先天的有序性,即不需要通过任何手段就能够保证的有序性,这个通常也成为happen-before原则
如果两个操作的持续无法从happen-before推导出来,那么就无法保证他们的有序性,Java物理机可以随意地对它们进行重排序。
happen-before原则:
- 程序次序规则:一个线程内按照代码顺序书写在前面的操作先行发生于书写在后面的操作
- 锁定规则:一个unLock操作先行发生于后面对同一锁的Lock操作
- volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
- 传递规则:如果操作A先行发生于操作B,操作B先行发生于操作C,那么操作A先行发生于操作C
- 线程启动规则:Thread对象的start方法先行发生于此线程的每一个动作方法
- 线程中断规则:对线程interrupt方法的调用先行发生于被中断的代码检测到中断事件的发生
- 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束,
Thread.isAlive()的返回值手段检测线程已终止执行 - 对象终结规则:一个对象的初始化先行发生于它的finalize()方法的开始