一直以来,多
线程代码是服务器开发人员的毒药(问问Oracle的Java语言
架构师和并行开发大师Brian Goetz)。西安达内科技java
培训(
http://www.xatarena.cn/java/index.jhtml)讲师表示,Java的核心库不断加入各种复杂的用法来减少访问共享资源时的线程等待时间。其中之一就是经典的读写锁(ReadWriteLock),它让你把代码分成两部分:需要互斥的写操作和不需要互斥的读操作。
表面上看起来很不错。问题是读写锁有可能是极慢的(
最多10倍),这已经和它的初衷相悖了。Java 8引入了一种新的读写锁——叫做时间戳锁。好消息是这个家伙真的非常快。坏消息是它使用起来更复杂,有更多的状态需要处理。并且它是不可重入的,这意味着一个线程有可能跟自己死锁。
java时间戳锁有一种“乐观”模式,在这种模式下每次加锁操作都会返回一个时间戳作为某种权限凭证;每次
解锁操作都需要提供它对应的时间戳。如果一个线程在请求一个写操作锁的时候,这个锁碰巧已经被一个读操作持有,那么这个读操作的解锁将会失效(因为时间戳已经失效)。这个时候应用程序需要从头再来,也许要使用悲观模式的锁(时间戳锁也有实现)。
你需要自己搞定这一切,并且一个时间戳只能解锁它对应的锁——这一点必须非常小心。
下面我们来看一下这种锁的实例——
long stamp = lock.tryOptimisticRead(); // 非阻塞路径——超级快
work(); // 我们希望不要有写操作在这时发生
if (lock.validate(stamp)){
//成功!没有写操作干扰
}
else {
//肯定同时有另外一个线程获得了写操作锁,改变了时间戳
//懒汉说——我们切换到开销更大的锁吧
stamp = lock.readLock(); //这是传统的读操作锁,会阻塞
try {
//现在不可能有写操作发生了
work();
}
finally {
lock.unlock(stamp); // 使用对应的时间戳解锁
}
}