StampedLock的简单用法

来源:互联网 发布:海知智能 编辑:程序博客网 时间:2024/06/11 00:21

        StampedLock是JDK1.8新引入的锁机制,可以简单的理解为读写锁的改进版本。我们知道读写锁可以让读和读之间完全并发,但是读和写之间是有阻塞的。StampedLock使用了一种乐观锁的读策略,这种机制类似于无锁的概念,使得获取锁的过程中不会阻塞写线程。
简单例子
        下面给出一个JDK官方给的Demo:

public class Point {private double x, y;private final StampedLock sl = new StampedLock();void move(double deltaX, double deltaY) {long stamp = sl.tryWriteLock();try {x += deltaX;y += deltaY;} finally {sl.unlockWrite(stamp);}}double distanceFromOrigin() {long stamp = sl.tryOptimisticRead();double currentX = x, currentY = y;if (!sl.validate(stamp)) {stamp = sl.readLock();try {currentX = x;currentY = y;} finally {sl.unlockRead(stamp);}}return Math.sqrt(currentX * currentX + currentY * currentY);}}
        上面是一个点移动的一个抽象。首先对于move()操作,加锁和解锁的过程和普通的Lock类似。对于distanceFromOrigin(),首先会使用tryOptimisticRead()加一个乐观读锁,此时会返回一个stamp数值。获取到X和Y的值之后,去验证其有效性,如果尚未被修改过,那么读取成功,计算结果返回。如果验证失败,那么会加读锁。
        在这个例子中,使用的锁升级,里面调用了readLock()方法去操作。这个操作会有一个循环的CAS操作,直到获取到锁为止。
StampedLock的缺陷
        在使用StampedLock的过程中,如果API使用的不当,则有可能造成CPU占用率过高。

// 获取读锁(阻塞,不响应中断)long readLock();// 获取读锁(立即)long tryReadLock();// 限时获取读锁(响应中断)long tryReadLock(long time, TimeUnit unit);// 获取读锁(阻塞,响应中断)long readLockInterruptibly();
        StampedLock在使用readLock()的时候,使用的是Unsafe.park()函数。park()在遇到线程中断时,会直接返回。这就导致阻塞在park()上面的线程被中断后,会再次进入循环,从而导致CPU的大量占用。以下是事例代码:

public class StampedLockCPUDemo {static Thread[] holdCpuThreads = new Thread[3];static final StampedLock lock = new StampedLock();public static void main(String[] args) throws InterruptedException {new Thread() {@Overridepublic void run() {long readLong = lock.writeLock();LockSupport.parkNanos(600000000000L);lock.unlockWrite(readLong);}}.start();Thread.sleep(100);for (int i = 0; i < 3; ++i) {holdCpuThreads[i] = new Thread(new HoldCPUReadThread());holdCpuThreads[i].start();}Thread.sleep(10000);// 线程中断后,会占用CPUfor (int i = 0; i < 3; ++i) {holdCpuThreads[i].interrupt();}}private static class HoldCPUReadThread implements Runnable {@Overridepublic void run() {long lockr = lock.readLock();System.out.println(Thread.currentThread().getName() + "获得读锁");lock.unlockRead(lockr);}}}
        笔者在自己的电脑上面测试时,CPU的占用率如下:




参考:《Java高并发程序设计》


链接:http://moguhu.com/article/detail?articleId=44