zoukankan      html  css  js  c++  java
  • StampedLock

    该类自 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)){
     // 锁升级
    }
    

    测试代码:

    import lombok.extern.slf4j.Slf4j;
    
    import java.util.concurrent.locks.StampedLock;
    import static  com.dalianpai.Sleeper.sleep;
    /**
     * @author WGR
     * @create 2020/12/31 -- 13:55
     */
    @Slf4j(topic = "c.TestStampedLock")
    public class TestStampedLock {
        public static void main(String[] args) {
            DataContainerStamped dataContainer = new DataContainerStamped(1);
            new Thread(() -> {
                dataContainer.read(1);
            }, "t1").start();
            sleep(0.5);
            new Thread(() -> {
                dataContainer.read(0);
            }, "t2").start();
        }
    }
    
    @Slf4j(topic = "c.DataContainerStamped")
    class DataContainerStamped {
        private int data;
        private final StampedLock lock = new StampedLock();
    
        public DataContainerStamped(int data) {
            this.data = data;
        }
    
        public int read(int readTime) {
            long stamp = lock.tryOptimisticRead();
            log.debug("optimistic read locking...{}", stamp);
            sleep(readTime);
            if (lock.validate(stamp)) {
                log.debug("read finish...{}, data:{}", stamp, data);
                return data;
            }
            // 锁升级 - 读锁
            log.debug("updating to read lock... {}", stamp);
            try {
                stamp = lock.readLock();
                log.debug("read lock {}", stamp);
                sleep(readTime);
                log.debug("read finish...{}, data:{}", stamp, data);
                return data;
            } finally {
                log.debug("read unlock {}", stamp);
                lock.unlockRead(stamp);
            }
        }
    
        public void write(int newData) {
            long stamp = lock.writeLock();
            log.debug("write lock {}", stamp);
            try {
                sleep(2);
                this.data = newData;
            } finally {
                log.debug("write unlock {}", stamp);
                lock.unlockWrite(stamp);
            }
        }
    }
    
    
    

    测试 读-读 可以优化

        public static void main(String[] args) {
            DataContainerStamped dataContainer = new DataContainerStamped(1);
            new Thread(() -> {
                dataContainer.read(10);
            }, "t1").start();
            sleep(0.5);
            new Thread(() -> {
                dataContainer.read(0);
            }, "t2").start();
        }
    }
    

    image-20201231140233219

    测试描述:当t1线程先抢到乐观读锁,然后睡眠10秒,t2晚t1 0.5秒抢到锁,然后直接结束,并没有堵塞住。

    测试读-写 时优化读补加读锁

        public static void main(String[] args) {
            DataContainerStamped dataContainer = new DataContainerStamped(1);
            new Thread(() -> {
                dataContainer.read(1);
            }, "t1").start();
            sleep(0.5);
            new Thread(() -> {
                dataContainer.write(100);
            }, "t2").start();
        }
    

    image-20201231141057253

    测试描述:当t1线程先抢到乐观读锁,然后休眠1秒钟,t2线程晚t1线程0.5秒抢到读锁,然后休眠2秒,这个时候t1线程醒来,验签失败,这个时候就会锁进升级成读锁,但是锁还在写锁那边,只能等写锁释放,读锁才能拿到。

    注意:
    StampedLock不支持条件变量
    StampedLock不支持可重入

  • 相关阅读:
    Android项目几种常见的应用架构
    PreferenceCategory背景颜色设置
    xml中怎样换行?
    Windows 7启动Telnet
    android图片处理方法(转)
    android SDK下载失败和更新方法
    JBoss 5.1.0 GA:Error installing to Instantiated:name=AttachmentStore state=Described
    window常用的『运行』命令
    在linux中eclipse连接android手机开发程序
    [leetcode]Binary Tree Level Order Traversal
  • 原文地址:https://www.cnblogs.com/dalianpai/p/14216416.html
Copyright © 2011-2022 走看看