没有合适的资源?快使用搜索试试~ 我知道了~
首页Java锁机制详解.pdf
Java锁机制详解.pdf
需积分: 50 888 浏览量
更新于2023-03-16
评论 1
收藏 208KB PDF 举报
Java锁机制详解.pdf java线程 java多线程 Java锁机制详解.pdf java线程 java多线程
资源详情
资源评论
资源推荐

第七章 显示锁
第七章 显示锁......................................................................................................1
7.1. Lock和ReentrantLock..................................................................................2
7.2. 对性能的考察 ..............................................................................................4
7.3 Lock与Condition..........................................................................................8
7.4. 在内部锁和重入锁之间进行选择 ............................................................13
7.5. 读-写锁.......................................................................................................14
参考文献..............................................................................................................21

相对于以前的版本,Java 5.0 引入了新的调节共享对象访问的机制,即重入
锁(ReentrantLock)。重入锁可以在内部锁被证明受到局限时,提供可选择的高
级特性。它具有与内在锁相同的内存语义、相同的锁定,但在争用条件下却有更
好的性能。
同时提供了读写锁,与互斥锁相比,读取数据远大于修改数据的频率时能提
升性能。
在第 3 章讲解 JDK 并发 API 时已经介绍过 ReentrantLock,本章做一些提升
和补充。
7.1. Lock 和 ReentrantLock
Lock 接口定义了一组抽象的锁定操作。与内部锁定(intrinsic locking)不同,
Lock 提供了无条件的、可轮询的、定时的、可中断的锁获取操作,所有加锁和
解锁的方法都是显式的。这提供了更加灵活的加锁机制,弥补了内部锁在功能上
的一些局限——不能中断那些正在等待获取锁的线程,并且在请求锁失败的情况
下,必须无限等待。
Lock 接口主要定义了下面的一些方法:
1)void lock():获取锁。如果锁不可用,出于线程调度目的,将禁用当前
线程,并且在获得锁之前,该线程将一直处于休眠状态。
2)void lockInterruptibly() throws InterruptedException:如果当前线程未被中
断,则获取锁。如果锁可用,则获取锁,并立即返回。如果当前线程在
获取锁时被 中断 ,并且支持对锁获取的中断,则将抛出
InterruptedException,并清除当前线程的已中断状态。
3)boolean tryLock():如果锁可用,则获取锁,并立即返回值 true。如果锁
不可用,则此方法将立即返回值 false。
4)boolean tryLock(long time, TimeUnit unit) throws InterruptedException:如
果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁。
5)void unlock():释放锁。
6)Condition newCondition():返回绑定到此 Lock 实例的新 Condition 实

例。调用 Condition.await() 将在等待前以原子方式释放锁,并在等待返
回前重新获取锁。
ReentrantLock实现了 Lock接口。获得 ReentrantLock的锁与进入 synchronized
块具有相同的语义,释放 ReentrantLock 锁与退出 synchronized 块有相同的语义。
相比于 synchronized,ReentrantLock 提供了更多的灵活性来处理不可用的锁。下
面具体来介绍一下 ReentrantLock 的使用。
1. 实现可轮询的锁请求
在内部锁中,死锁是致命的——唯一的恢复方法是重新启动程序,唯一的预
防方法是在构建程序时不要出错。而可轮询的锁获取模式具有更完善的错误恢复
机制,可以规避死锁的发生。
如果你不能获得所有需要的锁,那么使用可轮询的获取方式使你能够重新拿
到控制权,它会释放你已经获得的这些锁,然后再重新尝试。可轮询的锁获取模
式,由 tryLock()方法实现。此方法仅在调用时锁为空闲状态才获取该锁。如果锁
可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false。
此方法的典型使用语句如下:
Lock lock = ...;
if (lock.tryLock()) {
try {
// manipulate protected state
} finally {
lock.unlock();
}
} else {
// perform alternative actions
}
2. 实现可定时的锁请求
当使用内部锁时,一旦开始请求,锁就不能停止了,所以内部锁给实现具有
时限的活动带来了风险。为了解决这一问题,可以使用定时锁。当具有时限的活

动调用了阻塞方法,定时锁能够在时间预算内设定相应的超时。如果活动在期待
的时间内没能获得结果,定时锁能使程序提前返回。可定时的锁获取模式,由
tryLock(long, TimeUnit)方法实现。
3. 实现可中断的锁获取请求
可中断的锁获取操作允许在可取消的活动中使用。lockInterruptibly()方法能
够使你获得锁的时候响应中断。
7.2. 对性能的考察
当 ReentrantLock 被加入到 Java 5.0 中时,它提供的性能要远远优于内部锁。
如果有越多的资源花费在锁的管理和调度上,那用留给应用程序的就会越少。更
好的实现锁的方法会使用更少的系统调用,发生更少的上下文切换,在共享的内
存总线上发起更少的内存同步通信。耗时的操作会占用本应用于程序的资源。
Java 6 中使用了经过改善的管理内部锁的算法,类似于 ReentrantLock 使用的算
法,从而大大弥补了可伸缩性的不足。因此 ReentrantLock 与内部锁之间的性能
差异,会随着 CPU、处理器数量、高速缓存大小、JVM 等因素的发展而改变。
下面具体的构造一个测试程序来具体考察 ReentrantLock 的性能。构造一个
计数器 Counter,启动 N 个线程对计数器进行递增操作。显然,这个递增操作需
要同步以防止数据冲突和线程干扰,为保证原子性,采用 3 种锁来实现同步,然
后查看结果。
测试环境是双核酷睿处理器,内存 3G,JDK6。
第一种是内在锁,第二种是不公平的 ReentrantLock 锁,第三种是公平的
ReentrantLock 锁。
首先定义一个计数器接口。
package locks;
public interface Counter {
public long getValue();
public void increment();
}

下面是使用内在锁的计数器类:
package lockbenchmark;
public class SynchronizedCounter implements Counter {
private long count = 0;
public long getValue() {
return count;
}
public synchronized void increment() {
count++;
}
}
下面是使用不公平 ReentrantLock 锁的计数器。
package lockbenchmark;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantUnfairCounterLockCounter implements Counter {
private volatile long count = 0;
private Lock lock;
public ReentrantUnfairCounterLockCounter() {
// 使用非公平锁,true就是公平锁
lock = new ReentrantLock(false);
}
public long getValue() {
return count;
}
public void increment() {
lock.lock();
try {
count++;
} finally {
lock.unlock();
}
}
}
下面是使用公平的 ReentrantLock 锁的计数器。
package lockbenchmark;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ReentrantFairLockCounter implements Counter {
剩余21页未读,继续阅读








安全验证
文档复制为VIP权益,开通VIP直接复制

评论0