volatile
定义
Java中的关键字,用于修饰变量,以实现可见性、有序性,不保证原子性。
可见性:线程A修改了共享变量x后,线程B读取到的x是否是最新值。内部原理是线程将主内存的变量复制到自身工作内存,修改后是否立即同步给主内存有序性:程序运行时的指令顺序,与写程序时的顺序是否一致。内部原理是JVM指令重排以提高程序运行性能原子性:一组指令操作,不存在只执行一部分的情况,要么完全执行,要么完全不执行
保证可见性
由volatile修饰的变量,每次读取它,不论哪个线程,读到的都是最新值。
原理
线程A在工作内存修改后的变量值会立刻同步到主内存,通过读写屏障(Barrier)来实现。读写屏障是一条CPU指令,插入一条屏障时,相当于告诉编译器和CPU,强制更新一次主内存以及工作内存的缓存
保证有序性
对volatile类型的变量进行读写操作时,它前面的指令必须全都执行完成,它后面的指令不可以执行。
原理
以volatile变量的读写代码为分界线,它前面的代码不可以重排序到后面,它后面的代码不可以重排序到前面。
不保证原子性
对于写volatile修饰的变量的操作,如果子线程A在写之前读的值,同时子线程B去修改这个值,那么修改后的值是不会同步给子线程A的。
原理
// 子线程A、B同时执行以下代码
volatile static int a = 0;
// 子线程A、B同时读取a的值,并且++
// 这过程中其实是2步操作:1)读取a的值,2)计算a+1并赋值给a
a++;
// 子线程A读取到a的值为0,子线程B同理,它们同时对0进行+1(=1)后赋值回去给a,最终a=1
sout("a="+a); // a=1输出
synchronized
synchronized关键字用于保证代码的互斥性访问,使用格式为synchronized (锁对象) 函数/代码块。
定义
是管程模型在Java语言中的实现。模型主要由:锁标识、等待队列、条件队列、wait、notify等功能组成,用于实现同步和互斥功能的并发编程工具。
synchronized关键字在使用时,必须要关联一个对象,要么是实例对象,要么是类对象。这个对象就是monitor object。
JVM内部有一套ObjectMonitor模式,实现了wait(), notify()功能,分三块区域:Entry Set, Owner, Wait Set。线程通过enter进入到Entry Set,通过acquire获取锁进入Critical(Owner)区域,通过release释放锁进入Wait区域,在Wait时如果条件满足,则再次进入Entry竞争锁
Java中synchronized的4种状态
Java SE 1.6的实现里,锁共有4种状态,随着竞争情况逐渐升级:
无锁偏向锁轻量级锁重量级锁
锁的分类
悲观锁:线程A持有锁时,线程B无法读、无法写,全部阻塞乐观锁:线程A持有锁时,线程B允许读,无法写。一般有版本号机制、CAS(compare and swap)两种实现自旋锁:线程A持有锁时,线程B一直循环等待该资源是否已经释放锁。它是non-blocking的。适用于时间比较短、锁的竞争不激烈的情况,有助于减少线程阻塞互斥锁:线程A持有锁时,线程B把自己阻塞起来,重新等待调度请求