内存,cache,和寄存器之间的关系
寄存器是用于计算数据,而cpu所能访问的数据都是主存中的.寄存器速度随时代行长越来越快,但是读取数据却是没有太大发展.所以有了cache这样的东西
高并发三大特性
- 原子性
- 多个原子性操作在一起就不再是原子性操作了
- 简单的读取和赋值操作是原子性的,将一个变量赋给另外一个变量的操作不是原子性的.
- Java内存模型(JMM)只保证了基本读取和赋值的原子性操作,其他均不保证,如果需要某些代码块能够拥有原子性,需要使用关键字synchronized,或者JUC中的lock.如果想要使用int等类型自增操作具备原子性,可以使用JUC包下的原子封装类型java.util.concurrent.atomic.*
- 总结:volatile关键字不具备原子性的语义,需要synchronized或者lock
- 可见性
- 使用volatile,当一个变量被volatile关键字修饰时,对于共享资源的读操作会直接在主内存中进行,对于共享资源的写操作当然是先修改工作内存,但是修改结束后,会立刻刷新到主内存中.
- 通过synchronized关键字能够保证可见性,synchronized关键字能够保证同一时刻只有一个线程获得锁,然后指向同步方法,并且还会确保在锁释放之前,会将对变量的修改刷新到主内存中.
- 通过JUC提供的显示锁Lock也能够保证可见性,Lock的lock方法能够保证在同一个时刻只有一个线程获取锁然后执行同步方法,并确保在锁释放之前将对变量的修改刷新到主内存中.
- 有序性
- 使用volatile关键字来保证有序性
- 使用synchronized关键字来保证有序性
- 使用Lock来保证有序性
总结:volatile可以实现可见性,有序性,但是不可实现原子性
volatile和synchronized
-
使用上的区别
- volatile关键字只能用于修饰实例变量或者类变量,不能修饰方法以及方法参数和局部变量,常量等
- synchronized关键字不能用于对变量的修饰,只能用于修饰方法或者语句块
- volatile修饰的变量可以为null,synchronized关键字同步语句框的monitor对象不能为null
-
对原子性的保证
- volatile无法保证原子性
- 由于synchronized是一种排他的机制,因此被synchronized关键字修饰的同步代码无法被中断打断,因此能够保证代码的原子性
-
可见性的保证
- 两者均可以保证共享资源在多线程间的可见性,但是实现机制完全不同.
- synchronized借助于JVM指令monitor enter和monitor exit对通过排他的方式使得同步代码串行化,在monitor exit时所有共享数据都会被刷新到主内存中.
- 相较与synchronized关键字volatile使用机器指令(偏硬件)"lock;"的方式迫使其他线程工作内存中的数据失效,不得到主内存中进行再次加载.
-
有序性的保证
- volatile关键字禁止JVM编译器以及处理器对其进行重排序,所以它能够保证有序性
- 虽然synchronized关键字所修饰的同步方法也可以保证顺序性,但是这种顺序性是以程序的串行化换来的,在synchronized关键字所修饰的代码块中代码块代码指令也发生指令重排序的情况
-
其他
- volatile不会使线程陷入阻塞
- synchronized关键字会使线程进入阻塞状态.