StampedLock带戳读写锁

StampedLock带戳读写锁

1.概念

为了提高ReentrantReadWriteLock读写锁的读性能,
该类自 JDK 8 加入,是为了进一步优化读性能,它的特点是在使用读锁、写锁时都必须配合【戳】使用 .

  • 加解读锁
long stamp = lock.readLock();
lock.unlockRead(stamp);
  • 加解写锁
long stamp = lock.writeLock();
lock.unlockWrite(stamp);

乐观读,StampedLock 支持 tryOptimisticRead() 方法(乐观读),读取完毕后需要做一次 戳校验 如果校验通过,表示这期间确实没有写操作,数据可以安全使用,如果校验没通过,需要重新获取读锁,保证数据安全。

long stamp = lock.tryOptimisticRead();
// 验戳
if(!lock.validate(stamp)){
    
    
// 锁升级
}

2.StampedLock基本用法

StampedLock基本使用

package com.concurrent.p10;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.locks.StampedLock;

@Slf4j(topic = "c.Test_StampedLock")
public class Test_StampedLock {
    
    

    /**
     * 测试读-读
     * <p>
     * 12:01:54.621 [Thread-0] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:01:54.621 [Thread-1] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:01:54.629 [Thread-1] DEBUG c.Test_StampedLock - 输出:abc
     * 12:01:54.629 [Thread-0] DEBUG c.Test_StampedLock - 输出:abc
     */
    @Test
    public void test1() {
    
    
        DataContainerStamped dataContainer = new DataContainerStamped("abc");
        Thread t1 = new Thread(() -> {
    
    
            String data = dataContainer.read();
            log.debug("输出:{}", data);
        });
        Thread t2 = new Thread(() -> {
    
    
            String data = dataContainer.read();
            log.debug("输出:{}", data);
        });
        t1.start();
        t2.start();
        try {
    
    
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }

    /**
     * 测试读-写
     *
     * (1)两个读线程先执行
     * 12:08:51.140 [Thread-0] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:08:51.143 [Thread-1] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:08:51.150 [Thread-0] DEBUG c.Test_StampedLock - 输出:abc
     * 12:08:51.150 [Thread-1] DEBUG c.Test_StampedLock - 输出:abc
     * 12:08:51.243 [Thread-2] DEBUG c.DataContainerStamped - 获取写锁,stamped=384
     * 12:08:51.243 [Thread-2] DEBUG c.DataContainerStamped - 开始写...
     * 12:08:53.244 [Thread-2] DEBUG c.DataContainerStamped - 写完成...
     * 12:08:53.244 [Thread-2] DEBUG c.DataContainerStamped - 释放写锁,stamped=384
     *
     * (2)写线程先执行
     * 12:09:45.258 [Thread-0] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:09:45.263 [Thread-2] DEBUG c.DataContainerStamped - 获取写锁,stamped=384
     * 12:09:45.258 [Thread-1] DEBUG c.DataContainerStamped - 乐观读,stamped=256
     * 12:09:45.264 [Thread-2] DEBUG c.DataContainerStamped - 开始写...
     * 12:09:47.265 [Thread-0] DEBUG c.DataContainerStamped - 乐观读升级读锁,stamped=514
     * 12:09:47.265 [Thread-0] DEBUG c.DataContainerStamped - 开始读...,stamped=514
     * 12:09:47.265 [Thread-1] DEBUG c.DataContainerStamped - 乐观读升级读锁,stamped=513
     * 12:09:47.265 [Thread-1] DEBUG c.DataContainerStamped - 开始读...,stamped=513
     * 12:09:47.265 [Thread-2] DEBUG c.DataContainerStamped - 写完成...
     * 12:09:47.265 [Thread-2] DEBUG c.DataContainerStamped - 释放写锁,stamped=384
     * 12:09:48.265 [Thread-1] DEBUG c.DataContainerStamped - 结束读...,stamped=513
     * 12:09:48.265 [Thread-0] DEBUG c.DataContainerStamped - 结束读...,stamped=514
     * 12:09:48.265 [Thread-1] DEBUG c.DataContainerStamped - 释放读锁,stamped=513
     * 12:09:48.265 [Thread-0] DEBUG c.DataContainerStamped - 释放读锁,stamped=514
     * 12:09:48.265 [Thread-0] DEBUG c.Test_StampedLock - 输出:jkl
     * 12:09:48.265 [Thread-1] DEBUG c.Test_StampedLock - 输出:jkl
     */
    @Test
    public void test2() {
    
    
        DataContainerStamped dataContainer = new DataContainerStamped("abc");
        Thread t1 = new Thread(() -> {
    
    
            String data = dataContainer.read();
            log.debug("输出:{}", data);
        });
        Thread t2 = new Thread(() -> {
    
    
            String data = dataContainer.read();
            log.debug("输出:{}", data);
        });
        Thread t3 = new Thread(() -> {
    
    
            dataContainer.write("jkl");
        });

        t1.start();
        t2.start();
        t3.start();
        try {
    
    
            t1.join();
            t2.join();
            t3.join();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
    }
}

@Slf4j(topic = "c.DataContainerStamped")
class DataContainerStamped {
    
    
    //共享数据
    private String data;
    //StampedLock
    private StampedLock lock = new StampedLock();

    public DataContainerStamped(String data) {
    
    
        this.data = data;
    }

    //写
    public void write(String data) {
    
    
        //获取写锁,并返回戳
        long stamped = lock.writeLock();
        log.debug("获取写锁,stamped={}", stamped);
        try {
    
    
            //睡2秒,模拟写入
            log.debug("开始写...");
            try {
    
    
                Thread.sleep(2000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            this.data = data;
        } finally {
    
    
            //释放写锁,并设置戳
            lock.unlockWrite(stamped);
            log.debug("写完成...");
            log.debug("释放写锁,stamped={}", stamped);
        }
    }

    //读
    public String read() {
    
    
        //乐观读(此过程没有锁),返回戳
        long stamped = lock.tryOptimisticRead();
        log.debug("乐观读,stamped={}", stamped);
        //校验戳
        if (lock.validate(stamped)) {
    
      //成功则返回结果
            return this.data;
        } else {
    
     //失败则将乐观读升级成读锁
            stamped = lock.readLock();
            log.debug("乐观读升级读锁,stamped={}", stamped);
            try {
    
    
                log.debug("开始读...,stamped={}", stamped);
                //模拟读取1秒
                try {
    
    
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
    
    
                    e.printStackTrace();
                }
                log.debug("结束读...,stamped={}", stamped);
                return this.data;
            } finally {
    
    
                lock.unlockRead(stamped);
                log.debug("释放读锁,stamped={}", stamped);
            }
        }
    }
}

3.StampedLock缺点

  • 不支持条件变量Condition
  • 不支持锁重入

猜你喜欢

转载自blog.csdn.net/qq_36109528/article/details/120650983