Java并发编程之美 第二章 并发编程的其他基础知识
并发:同一个时间端内多个任务同时都在执行
并行:单位时间内多个任务同时在执行
线程安全问题指多个线程同时读写一个共享资源并且没有任何同步措施,导致出现脏数据或者其他不可预见的结果
java内存模型规定,所有变量保存在主内存中,当线程使用变量时,会把主内存变量复制到自己的工作空间,线程读写时操作的是自己工作内存中的变量
cpu每个核有自己的一级缓存
所有CPU共享二级缓存
synchronized
synchronized是java的原子性内置锁
java内置的使用者看不到的锁被称为内部锁,也叫监视器锁
java中的线程与操作系统的原生线程是一一对应的,所以阻塞一个线程时,需要从用户态切换到内核态执行阻塞,这是很耗时的操作
synchronized的使用会导致上下文切换
volatile
volatile声明的变量,线程在写入变量时,不会把值缓存在寄存器或其他地方,而是把指刷新回主内存
当其他线程读取该共享变量时,会从主内存重新获取最新值,而不是使用当前线程的工作内存中的值
volatile不保证原子性,只保证可见性
cas
unsafe
JDK的rt.jar包中的unsafe类提供了硬件级别的原子性操作,unsafe类中的方法都是native方法,使用JNI方式访问本地C++实现库
指令重排序
java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依赖性的指令重排序
在单线程下重排序没有问题,但是多线程会存在问题
重排序在多线程下会导致非预期结果,使用volatile可以避免重排序和内存可见性问题
写volatile变量时,可以确保volatile写之前的操作不会被编译器重排序到volatile写之后
读volatile变量时,可以确保volatile读之后的操作不会被编译器重排序到volatile读之前
伪共享
CPU和主内存之间有一级或者多级高速缓冲存储器(Cache),一般被集成到CPU内部
Cache内部是按行存储的,每一行称为Cache行,行大小一般为2的幂次数字节
CPU访问变量时,先判断Cache内是否有,没有才去主内存获取,然后把该变量所在内存区域的一个Cache行大小的内存复制到Cache中
由于存放的是内存块,所以可能多个变量存放在一个cache行中,
当多个线程同时修改一个缓存行里面的多个变量时,由于同时只能有一个线程操作缓存行,所以相比将每个变量放到一个缓存行,性能有所下降,这就是伪共享
单线程下伪共享可以加速程序,但多线程下并发修改,会降低性能
JDK8.0之前通过字节填充避免伪共享
JDK8.0通过sun.misc.contended注解,来解决伪共享。可以修饰类,可以修饰变量
默认情况下,只用于核心类
如果用户类需要使用,需要添加JVM参数
锁的概述
悲观锁:对数据持保守态度,认为数据很容易被其他线程修改。处理前加锁
乐观锁:认为数据不会造成冲突,不加排他锁,在进行数据提交时,才会对数据冲突进行检测
公平锁:先来后到
不公平锁:竞争
独占锁:任何时候只有一个线程能得到锁
共享锁:允许多个线程同时操作
可重入锁:只要该线程获取了锁,那么可以无限次数地进入该锁
自旋锁:如果锁被其他线程占有,不马上阻塞自己,而是多次尝试获取,

浙公网安备 33010602011771号