Lock接口
提供了与synchronized
关键字类似的同步功能
synchronized
方法或语句的使用提供了对与每个对象相关的隐式监视器锁定的访问,但却强制所有锁定获取和释放均要出现在一个块结构中:当获取了多个锁定时,它们必须以相反的顺序释放,且必须在与所有锁定被获取时相同的词法范围内释放所有锁定。
虽然synchronized
方法和语句的范围机制使得使用监视器锁定编程方便了很多,而且还帮助避免了很多涉及到锁定的常见编程错误,但有时也需要以更为灵活的方式使用锁定。例如,某些遍历并发访问的数据结果的算法要求使用 “hand-over-hand” 或 “chain locking”:获取节点 A 的锁定,然后再获取节点 B 的锁定,然后释放 A 并获取 C,然后释放 B 并获取 D,依此类推。Lock 接口
的实现允许锁定在不同的作用范围内获取和释放,并允许以任何顺序获取和释放多个锁定,从而支持使用这种技术。
ReentrantLock构造方法
-
ReentrantLock()
:构建一个ReentrantLock的实例,这等同于使用ReentrantLock(false)
-
ReentrantLock(boolean fair)
: 创建一个具有给定公平策略的 ReentrantLock
参数:
fair
- 如果此锁定是公平的,则该参数为true
;否则为false
使用方式
Lock lock=new ReentrantLock(); //显式的获取锁
lock.lock();
try
{
// access the resource protected by this lock
//处理逻辑
}
finally
{
lock.unlock(); //显式的释放锁
}
例题:多窗口售票问题
class lockThread implements Runnable
{
private int tickets=100;
//实例化Reentrantlock
Lock lock=new ReentrantLock(); //默认false,非公平锁
public void run()
{
while(true)
{
lock.lock(); //上锁
try {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName() + ":卖票,票号为:" + (100 - tickets + 1));
tickets--;
} else {
break;
}
}
finally {
lock.unlock(); //释放锁
}
}
}
}
synchronized与Lock异同
相同:二者都可以解决线程安全问题
不同:synchronized
机制在执行完相应同步代码后,会自动释放同步监视器;Lock
需要手动获得锁(lock()
),手动释放锁(unlock()
)