Lock接口有3个实现它的类:
ReentrantLock
重入锁
ReetrantReadWriteLock.ReadLock
读锁
ReetrantReadWriteLock.WriteLock 写锁
代码示例:
Lock lock =
new
ReentrantLock();
//默认使用非公平锁,如果要使用公平锁,需要传入参数true
........
lock.lock();
try
{
//更新对象的状态
//捕获异常,必要时恢复到原来的不变约束
//如果有return语句,放在这里
}
finally
{
lock.unlock();
//锁必须在finally块中释放
}
两种锁机制的底层的实现策略
synchronized
互斥同步最主要的问题:
进行线程阻塞和唤醒所带来的性能问题,
一种悲观的并发策略,
线程获得的是独占锁。独占锁意味着其他线程只能依靠阻塞来等待线程释放锁
CPU转换线程阻塞时会引起线程上下文切换,当有很多线程竞争锁的时候,会引起CPU频繁的上下文切换导致效率很低
ReetrantLock
冲突检测的乐观并发策略:
如果没有其他线程争用共享数据,那操作就成功了,如果共享数据被争用,产生了冲突,
那就再进行其他的补偿措施(最常见的补偿措施就是不断地重拾,直到试成功为止)
这种乐观的并发策略的许多实现都不需要把线程挂起,因此这种同步被称为非阻塞同步
LOCK用途:
1 等待可中断:当持有锁的线程长期不释放锁时,正在等待的线程可以选择放弃等待,改为处理其他事情
2、可实现公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序排队等待,
而非公平锁则不保证这点,在锁释放时,任何一个等待锁的线程都有机会获得锁
公平锁:
ReentrantLock(ture)
3、锁可以绑定多个条件:ReentrantLock对象可以同时绑定多个Condition对象(名曰:条件变量或条件队列)
只需要多次调用newCondition()方法即可。而且我们还可以通过绑定Condition对象来判断当前线程通知的是哪些线程
可中断锁
ReetrantLock有两种锁:忽略中断锁和响应中断锁。
忽略中断锁与synchronized实现的互斥锁一样,不能响应中断,
而响应中断锁可以响应中断
ReentrantLock lock =
new
ReentrantLock();
...........
lock.lockInterruptibly();
//获取响应中断锁
try
{
//更新对象的状态
//捕获异常,必要时恢复到原来的不变约束
//如果有return语句,放在这里
}
finally
{
lock.unlock();
//锁必须在finally块中释放
}
synchronized获取的互斥锁不仅互斥读写操作、写写操作,还互斥读读操作
ReadWriteLock rwl =
new
ReentrantReadWriteLock();
rwl.writeLock().lock()
//获取写锁
rwl.readLock().lock()
//获取读锁
用读锁来锁定读操作,用写锁来锁定写操作,
这样写操作和写操作之间会互斥,
读操作和写操作之间会互斥,但读操作和读操作就不会互斥
提倡在synchronized能实现需求的情况下,优先考虑使用synchronized来进行同步。
使用 ReentrantLock的最佳时机:
当你需要以下高级特性时,才应该使用:可定时的、可轮询的与可中断的锁获取操作,公平队列,或者非块结构的锁。否则,请使用synchronized。