• 多线程之读写锁


    前言

    java中,锁lock是多线程编程的一个重要组件,可以说凡是涉及到多线程编程,线程安全这一块就无法避开lock,进一步说就是所有的线程安全都是基于锁实现的,只是从形式上分为隐式锁和显式锁,synchronized就属于隐式锁,像我们之前分享的可重入锁就属于显式锁,当然显示锁还有很多,我们今天就来看一个很常用的显式锁——读写锁。

    读写锁

    读写锁是一对互斥锁,分为读锁和写锁。读锁和写锁互斥,让一个线程在进行读操作时,不允许其他线程的写操作,但是不影响其他线程的读操作;当一个线程在进行写操作时,不允许任何线程进行读操作或者写操作。

    简单来说就是,写锁会排斥读和写,但是读锁只排斥写,这样的好处就很明显,在读多写少的应用场景下,比其他互斥锁性能要好很多。下面我们通过一段代码说明:

    public class Example {
        private static final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
        private static AtomicInteger count = new AtomicInteger(0);
    
        public static void main(String[] args) {
            ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
            ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            // 写操作1:写锁
            executorService.execute(() -> {
                writeLock.lock();
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("写count1: " + count.incrementAndGet());
                }
                writeLock.unlock();
            });
            // 读操作1:读锁
            executorService.execute(() -> {
                readLock.lock();
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("读count1: " + count.get());
                }
                readLock.unlock();
            });
            // 读操作2:读锁
            executorService.execute(() -> {
                readLock.lock();
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("读count2: " + count.get());
                }
                readLock.unlock();
            });
            // 写操作2:写锁
            executorService.execute(() -> {
                writeLock.lock();
                for (int i = 0; i < 5; i++) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("写count2: " + count.incrementAndGet());
                }
                writeLock.unlock();
            });
            // 写操作3:写锁
            executorService.execute(() -> {
                writeLock.lock();
                for (int i = 0; i < 5; i++) {
                    System.out.println("写count3: " + count.incrementAndGet());
                }
                writeLock.unlock();
            });
    
            executorService.shutdown();
    
        }
    }
    

    上面的代码中,我们分别有3次写操作,2次读操作,然后运行上面的代码:

    运行结果图片上我们已经标注了线程休眠情况,根据运行结果虽然写count1休眠了1000,读count1休眠了500,但因为写锁的存在,排斥了其他读写操作,读只能等写锁释放,所以是先写后读,也就是写锁排斥读;

    count2休眠了200,读count1休眠了500,虽然加了读锁,但结果还是读count2先运行,而且期间是读count1和读count2交替运行,说明读并不排斥读,而且读后面的写count2只休眠了100,但还是在读count1和读count2之后运行,说明读排斥写;

    count2休眠100,写count3未休眠,但是写count3依然在写count2之后执行,说明写锁排斥写。

    综上,我们在示例中分别证明了我们上面的结论:写锁会排斥读和写,但是读锁只排斥写。

    总结

    读写锁相比于其他互斥锁,优点很明显,也就是前面我们说的:在读多写少的应用场景下,比其他互斥锁性能要好很多。至于原因,我们也通过示例证明了:写锁会排斥读和写,但是读锁只排斥写。

    关于读写锁,我觉得今天分享的内容已经比较详细,不仅展示了它的基本用法,同时还通过示例反证了它的互斥原则,所以如果你看明白了今天的内容,那么互斥锁这一款的知识你就掌握了。好了,今天的内容就到这里吧!

  • 相关阅读:
    crontab定时任务写法记录
    Django与Vue语法冲突问题完美解决方法
    Django下MEDIA_ROOT, MEDIA_URL, STATIC_ROOT, STATIC_URL解惑
    解决python2.x用urllib2证书验证错误, _create_unverified_context
    django 异步任务实现及Celery beat实现定时/轮询任务
    用Python写WebService接口并且调用
    django(权限、认证)系统——第三方组件实现Object级别权限控制
    django(权限、认证)系统—— 基于Authentication backends定制
    django(权限、认证)系统—— Permissions和Group
    [jmeter]linux下自动测试环境+持续集成ant+jmeter+Apache(httpd)环境搭建与使用
  • 原文地址:https://www.cnblogs.com/caoleiCoding/p/15015069.html
Copyright © 2020-2023  润新知