Skip to content

StampedLock锁

StampedLock是JDK1.8中新增的一个读写锁,也是对JDK1.5中的读写锁ReentrantReadWrii@Lock的优化。

1. 简介

邮戳锁又称为票据锁,stamp代表了锁的状态。当stamp返回零时,表示线程获取锁失败。并且,当释放锁或者转换锁的时候,都要传入最初获取的stamp值。

2. 特点

  1. 所有获取锁的方法,都返回一个邮戳(Stamp), Stamp为零表示获取失败,其余都表示成功
  2. 所有释放锁的方法,都需要一个邮戳(Stamp), 这个Stamp必须是和成功获取锁时得到的Stamp一致
  3. StampedLock是不可重入的,危险(如果一个线程已经持有了写锁,再去获取写锁的话就会造成死锁)

3. 3种模式

①Reading(读模式悲观):功能和ReentrantReadWriteLock的读锁类似
②Writing(写模式):功能和ReentrantReadWriteLock的写锁类似
③Optimistic reading(乐观读模式):无锁机制,类似于数据库中的乐观锁,支持读写并发,很乐观认为读取时没人修改,假如被修改再实现升级为悲观读模式式

4. 读写模式

java
public class TimestampLockDemo {
    private static int number = 50;
    StampedLock stampedLock = new StampedLock();

    public void write() {
        long timestamp = stampedLock.writeLock();
        try {
            System.out.println("修改数据。。。");
            number = 37;
        } finally {
            stampedLock.unlockWrite(timestamp);
        }
        System.out.println("数据修改结束。。。");

    }

    public void read() throws InterruptedException {
        long timestamp = stampedLock.readLock();
        try{
            TimeUnit.SECONDS.sleep(4);
            System.out.println("读取到数据为:" + number);
        }finally {
            stampedLock.unlockRead(timestamp);
        }
        System.out.println("数据读取结束。。。");
    }

    public static void main(String[] args) {
        TimestampLockDemo lockDemo = new TimestampLockDemo();
        new Thread(() -> {
            try {
                lockDemo.read();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();

        new Thread(() -> {
            lockDemo.write();
        }).start();
    }
}

运行结果:
Alt text

5. 乐观读模式

java
public class StampLockDemo {
    private static int number = 50;
    StampedLock stampedLock = new StampedLock();

    public void write() {
        long timestamp = stampedLock.writeLock();
        try {
            System.out.println("修改数据。。。");
            number = 37;
        } finally {
            stampedLock.unlockWrite(timestamp);
        }
        System.out.println("数据修改结束。。。");

    }

    public void optimisticRead() throws InterruptedException {
        // 乐观读是一种无锁的读模式,不会真正获取锁,不存在解锁的操作
        long timestamp = stampedLock.tryOptimisticRead();

        if (!stampedLock.validate(timestamp)) {
            System.out.println("数据已经被修改....");
            timestamp = stampedLock.readLock();
            System.out.println("从乐观读升级为悲观读");
            try {
                TimeUnit.SECONDS.sleep(4);
                System.out.println("悲观读, 读取到数据为:" + number);
            } finally {
                stampedLock.unlockRead(timestamp);
            }
        }else{
            TimeUnit.SECONDS.sleep(4);
            System.out.println("读取到数据为:" + number);
        }
        System.out.println("数据读取结束。。。");
    }

    public static void main(String[] args) throws InterruptedException {
        StampLockDemo lockDemo = new StampLockDemo();
        new Thread(() -> {
            try {
                lockDemo.optimisticRead();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
        // 暂停1秒
        Thread.sleep(1000);
        new Thread(() -> {
            lockDemo.write();
        }).start();
    }
}

执行结果:
Alt text