美文网首页
31.java 多线程(读写锁)

31.java 多线程(读写锁)

作者: 呦丶耍脾气 | 来源:发表于2025-07-07 14:01 被阅读0次

ReadWriteLock

一般情况,我们更希望允许多个线程同时读,但只要有一个线程在写,其他线程就必须等待,就需要使用ReadWriteLock来实现。

  • 只允许一个线程写入(其他线程既不能写入也不能读取);
  • 没有写入时,多个线程允许同时读(提高性能)。
public class Counter {
    private final ReadWriteLock rwlock = new ReentrantReadWriteLock();
    private final Lock rlock = rwlock.readLock();
    private final Lock wlock = rwlock.writeLock();
    private int[] counts = new int[10];
    public void inc(int index) {
        wlock.lock(); // 加写锁
        try {
            counts[index] += 1;
        } finally {
            wlock.unlock(); // 释放写锁
        }
    }
    public int[] get() {
        rlock.lock(); // 加读锁
        try {
            return Arrays.copyOf(counts, counts.length);
        } finally {
            rlock.unlock(); // 释放读锁
        }
    }
}

把读写操作分别用读锁和写锁来加锁,在读取时,多个线程可以同时获得读锁,这样就大大提高了并发读的执行效率。

StampedLock

StampedLockReadWriteLock相比:读的过程中也允许获取写锁后写入,是一种乐观锁。

public class Point {
    private final StampedLock stampedLock = new StampedLock();
    private double x;
    private double y;
    public void move(double deltaX, double deltaY) {
        long stamp = stampedLock.writeLock(); // 获取写锁
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            stampedLock.unlockWrite(stamp); // 释放写锁
        }
    }
    public double distanceFromOrigin() {
        long stamp = stampedLock.tryOptimisticRead(); // 获得一个乐观读锁
        // 注意下面两行代码不是原子操作
        // 假设x,y = (100,200)
        double currentX = x;
        // 此处已读取到x=100,但x,y可能被写线程修改为(300,400)
        double currentY = y;
        // 此处已读取到y,如果没有写入,读取是正确的(100,200)
        // 如果有写入,读取是错误的(100,400)
        if (!stampedLock.validate(stamp)) { // 检查乐观读锁后是否有其他写锁发生
            stamp = stampedLock.readLock(); // 获取一个悲观读锁
            try {
                currentX = x;
                currentY = y;
            } finally {
                stampedLock.unlockRead(stamp); // 释放悲观读锁
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }
}

首先我们通过tryOptimisticRead()获取一个乐观读锁,并返回版本号。接着进行读取,读取完成后,我们通过validate()去验证版本号,如果在读取过程中没有写入,版本号不变,验证成功,我们就可以放心地继续后续操作。如果在读取过程中有写入,版本号会发生变化,验证将失败。在失败的时候,我们再通过获取悲观读锁再次读取。由于写入的概率不高,程序在绝大部分情况下可以通过乐观读锁获取数据,极少数情况下使用悲观读锁获取数据。

相关文章

  • go sync包的读写锁RWMutex的使用

    sync包的读写锁RWMutex的使用(sync.RWMutex) 我们使用“读写”锁的场景主要是在多线程的安全操...

  • iOS中的锁

    锁 - 主要作用是保证多线程访问资源安全 锁的种类:基本的锁就包括了三类 自旋锁 互斥锁 读写锁其他的比如条件锁,...

  • 锁的优化

    在前几天的文章:浅谈Java中的锁:Synchronized、重入锁、读写锁 中我们学习了多线程环境下为了保证线程...

  • iOS底层探索-多线程锁

    多线程的锁大致可分为两大类:互斥锁、自旋锁;也可以分为三类:互斥锁、自旋锁、读写锁。 一、互斥锁:互斥+同步(强调...

  • AbstractQueuedSynchronizer

    理解多线程的并发锁,可结合多进程的分布式锁(如Zookeeper的互斥锁、读写锁的实现原理),本质是相通的 介绍 ...

  • 备忘录之-iOS保证线程安全的锁和方法

    只要系统中存在多线程,存在共享资源,那么锁就是一个绕不过去的概念,像后台数据库读写数据就要用到读写锁,来保证数据的...

  • 5、使用atomic一定是线程安全的吗?

    atomic在set方法里加了锁,防止了多线程一直去写这个property,造成难以预计的数值。但这也只是读写的锁...

  • 并发控制方法

    解决问题:为多线程、多任务间的协作和数据共享提供并发控制。常用方法:内部锁、重入锁、读写锁、信号量等。一、vola...

  • 读写锁和互斥锁 读写互斥锁,简称读写锁 mux sync.RWMutex Lock和Unlock分别对写锁进行锁定...

  • java多线程之读写锁

    Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个...

网友评论

      本文标题:31.java 多线程(读写锁)

      本文链接:https://www.haomeiwen.com/subject/hwzwgjtx.html