一、简单介绍Lock
j.u.c中提供了Lock接口,该接口与synchronized一样,可以保证程序并发访问的互斥性。
这里简单介绍下Lock与synchronized的区别:
- synchronized是隐式获取锁的,经过编译器编译后,会在同步代码块起始处加入monitorenter指令,在结束处加入monitorexit指令。而Lock是显式的有程序员自己进行加锁与解锁操作;
- Lock的加锁方式更丰富,支持可中断的获取锁(即,对于获取到锁的线程可以响应中断),规定获取锁的时间,以及非阻塞的获取锁:
- Lock支持公平锁,即对于等待的多个线程来说,按照FIFO方式后去锁;
- 支持多个条件变量(一个Lock可以产生多个额condition),所谓条件变量可以这样理解:对于synchronized(obj){…},进行等待-唤醒操作,只能通过obj;而对于lock来说,一个Lock可以产生多个Condition,每个Condition能进行等待-唤醒操作。
注意: Lock与synchronized都是可重入的。
二、Lock的可见性是如何保障的:
Lock的可见性是根据Happen-Before规则来实现的,它内部保存了一个volatile变量state,在进行lock()操作后,会读写state的值,在进行unlock()操作前,也会读写state的值。
例:
locl.lock();
// 读写state
try{
//业务逻辑
}finally{
// 读写state
lock.unlock();
}
根据这个简单的例子可以看出,涉及到了 程序次序规则、Volatile变量规则、传递性 三个Happen-Before三个的规则:
程序次序规则:
对于线程T1,业务处理Happen-Before于unlock()操作;
volatile 变量规则:
由于 state = 1 会先读取 state,所以线程 T1 的 unlock() 操作 Happens-Before 线程 T2 的 lock() 操作;
传递性规则:
线程 T1 的 value+=1 Happens-Before 线程 T2 的 lock() 操作。