并发编程之读写锁

读写锁是什么

如果没有读写锁,那么使用其他类型的锁,线程无论是做读操作还是写操作,都需要去获取锁,也都需要阻塞等待着锁资源的释放。但是如果仅仅是读操作,其实完全是允许多线程同时进行的,因为读操作不涉及数据的修改,也就不会引起线程安全问题,相反的,多个读操作并行执行,反而提高了效率。而因为写操作涉及数据的修改,会引起线程安全问题,所以写操作就要做到与其他操作的互斥,以此来保证线程的安全。读写锁就提供了这样的机制,它允许多个线程读操作,提高了效率,同时还能保证写操作的线程安全。

读写锁的实现思路

其实就是设计两把锁,第一把叫读锁,获取读锁后,只允许查看数据,而不能修改数据。第二把叫写锁,获取写锁后,既能查看数据也能修改数据。读锁可以被多个线程持有,而写锁则只能被一个线程持有。

读写锁的获取规则

读读共享:一个线程获取了读锁后,另一个线程一样能获取读锁
写写互斥:一个线程获取了写锁后,另一个线程就不能再获取这个写锁了
读写互斥:一个线程获取了读锁后,另一个线程就不能获取写锁了
写读互斥:一个线程获取了写锁后,另一个线程就不能获取读锁了

读写锁代码示例

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * 读写锁示例
 */
public class ReadWriteLockDemo {
    private static final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(false);
    //读锁
    private static final ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
    //写锁
    private static final ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();

    /**
     * 读线程任务
     */
    static class Read implements Runnable {
        @Override
        public void run() {
            readLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取到读锁");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "准备释放读锁");
                readLock.unlock();
            }
        }
    }

    /**
     * 写线程任务
     */
    static class Write implements Runnable {
        @Override
        public void run() {
            writeLock.lock();
            try {
                System.out.println(Thread.currentThread().getName() + "获取到写锁");
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                System.out.println(Thread.currentThread().getName() + "准备释放写锁");
                writeLock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        new Thread(new Read()).start();
        new Thread(new Read()).start();
        new Thread(new Write()).start();
        new Thread(new Write()).start();
        new Thread(new Read()).start();
    }
}

运行结果如下:

在这里插入图片描述

总结

可以从上述的运行结果发现,相同的一把读写锁,读锁和写锁之间做到了读读共享、写写互斥、读写互斥、写读互斥,用最简单的业务做个示例,读多写少的情况下,可以在query方法中使用读锁,在update等方法中使用写锁,这样就实现了读高效率和写安全。

扫描二维码关注公众号,回复: 11144888 查看本文章
原创文章 358 获赞 387 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_38106322/article/details/105593306