并发与并行
并发是一个时间段内多个任务同时进行,并行是一个单位时间内多个任务同时进行,并发中一个时间段包含多个单位时间,并发任务在单位时间内不一定同时进行。并发->单核CPU 并行->多核CPU
处理共享变量时java的内存模型:
synchronized关键字和volatile关键字
synchronized是Java提供的一种原子性内置锁,也是排它锁,使用它需要切换线程上下文,会造成损耗。
进入synchronized块的内存语义是把在synchronized块内使用到的变量从线程的工作内存中清除,这样在synchronized块内使用到该变 时就不会从线程的工作内存中获取,而是 直接从主内存中获取 ;退出 synchronized块的内存语义是把在synchronized块内对共享变量修改刷新到主内存。
当一个变量被声明为volatile时,线程在写入变量时不会把值缓存在寄存器或者其他地方,而是会把值刷新回主内存 ;当其它线程读取该共享变量,会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值。
Java中的CAS操作
boolean compareAndSwapLong(Object obj,long valueOffset,long expect, long update )方法:其中 compareAndSwap 的意思是比较并交换。 CAS 有四个操作数 分别为对象内存位置 、对象中的变量的偏移量、变量预期值和新的值。其操作含义是,如果对象 obj 中内存偏移量为 valueOffset 变量值为 expect ,则使用新 update 替换 旧的 expect。这是处理器提供的一个原子性指令。
JDK的rt.jar包中的Unsafe类提供了硬件级别的原子性操作。
Java指令重排序
Java 内存模型允许编译器和处理器对指令冲排序以提升运行性能 ,并且只会对不存在数据依赖性的指令重排序。 在单线程下重排序可以保证最终执行的结果与程序顺序执行的结果一致,但是在多线程下就存在问题。
使用valatile关键字可以避免重排序和内存可见性的问题。
锁类型
乐观锁和悲观锁
乐观锁只在更新时锁定(通过设置的version等),悲观锁则是排它锁。
公平锁和非公平锁
如其名,非公平不按照先到先得原则
ReentranLock提供公平锁和非公平锁的实现,在构造函数传入布尔参数,true为公平,false为非公平,默认是非公平
公平锁会带来性能开销。
独占锁和共享锁
如其名,独占锁是一种悲观锁;共享锁则是乐观锁,如ReadWriteLock读写锁,允许一个资源被多线程同时进行读操作。
可重入锁
当一个线程获得一个锁,当它再次获得它已经获得的锁不会被阻塞,则称该锁为可重入锁;synchronized是可重入锁,通过计数器实现。
public class Hello{
public synchronized void helloA () {
System.out.println("hello");
public synchronized void helloB () {
System.out.println("helloB");
helloA();
}
}
自旋锁
线程如果获取锁失败会切换内核态而被挂起,开销较大,故失败后不马上阻塞自己,而是多次尝试获取。