zoukankan      html  css  js  c++  java
  • 读写锁的策略

    概述

    本文简易介绍下读写锁的策略

      1.在公平锁的条件下,所有的锁都不允许插队

      2.在非公平的条件下:

          写锁是可以插队的(写锁插队可以避免饥饿)

          读锁仅在等待队列头结点不是想获取写锁的线程的时候是可以插队的。 

      接下来我会从ReentrantReadWriteLock源码部分进行说明。

    公平锁的条件下读写锁的策略

        我们从ReentrantReadWriteLock 的FairLock中查看策略,如下图所示。

        

      从红圈是可以看到读锁和写锁的阻塞条件都是当队列中有等待的处理任务。即就是读锁和写锁是不可以插队的。

     非公平锁的情况下的读写策略

      下面我们介绍非公平锁的情况下,写锁是可以插队,读锁只有在头结点不是写线程的情况是可以插队,见下图所示。

     读写锁测试实例代码

      下文从实例代码来说明读写的插队策略问题

      代码是实现结果为:非公平锁的条件下,线程1读,线程2读,线程3写,线程4读,执行结果为线程4在线程3之后

      非公平条件下读锁插队代码

      下文代码演示非公平的条件下,读锁进行插队的实现,见下代码。

      非公平条件下,读锁插队的条件是:当头结点不是写锁时,可以插队。

      

    package com.yang.lock;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * 本实例演示非公平的条件下,读锁插队的问题(当头结点不是写线程的时候)
     */
    public class NoFairReadWriteDemo {
        private static ReentrantReadWriteLock reentrantReadWriteLock=new ReentrantReadWriteLock(false);
        private static ReentrantReadWriteLock.ReadLock readLock=reentrantReadWriteLock.readLock();
        private static ReentrantReadWriteLock.WriteLock writeLock=reentrantReadWriteLock.writeLock();
    
        public void read(){
            System.out.println(Thread.currentThread().getName()+"尝试获取读锁");
            readLock.lock();
            try{
                System.out.println(Thread.currentThread().getName()+"获取到了读锁");
            }finally {
                readLock.unlock();
            }
        }
        public void write(){
            System.out.println(Thread.currentThread().getName()+"尝试获取写锁");
            writeLock.lock();
            try{
                Thread.sleep(20);
                System.out.println(Thread.currentThread().getName()+"获取到了写锁");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                writeLock.unlock();
            }
        }
    
        /**
         * 线程1获取写锁,其他线程尝试获取
         * 线程1释放后,队列头为线程2,进行读;线程3也进行读,测试:线程2在读取的时候,子线程能否插队成功
         * @param args
         */
        public static void main(String[] args) {
            NoFairReadWriteDemo noFairReadWriteDemo=new NoFairReadWriteDemo();
            new Thread(()->noFairReadWriteDemo.write(),"线程1").start();
            new Thread(()->noFairReadWriteDemo.read(),"线程2").start();
            new Thread(()->noFairReadWriteDemo.read(),"线程3").start();
            new Thread(()->noFairReadWriteDemo.write(),"线程4").start();
            new Thread(()->noFairReadWriteDemo.read(),"线程6").start();
            new Thread(() -> {
                Thread[] threads=new Thread[1000];
                for (int i = 0; i < 1000; i++) {
                    int finalI = i;
                    threads[i]=new Thread(()->noFairReadWriteDemo.read(),"子线程"+ finalI);
                }
                for (int i = 0; i < 1000; i++) {
                    threads[i].start();
                }
            }, "线程6").start();
        }
    
    }
    

        运行结果主要截图如下所示。

        

    线程1尝试获取写锁
    线程2尝试获取读锁
    线程3尝试获取读锁
    线程4尝试获取写锁
    线程6尝试获取读锁
    线程1获取到了写锁
    子线程0尝试获取读锁
    子线程1尝试获取读锁
    子线程2尝试获取读锁
    子线程3尝试获取读锁
    子线程22尝试获取读锁
    子线程5尝试获取读锁
    子线程6尝试获取读锁
    子线程7尝试获取读锁
    子线程8尝试获取读锁
    子线程9尝试获取读锁
    子线程10尝试获取读锁
    子线程11尝试获取读锁
    子线程12尝试获取读锁
    子线程13尝试获取读锁
    子线程14尝试获取读锁
    子线程15尝试获取读锁
    子线程16尝试获取读锁
    子线程17尝试获取读锁
    子线程18尝试获取读锁
    子线程19尝试获取读锁
    子线程20尝试获取读锁
    子线程21尝试获取读锁
    子线程4尝试获取读锁
    子线程23尝试获取读锁
    线程2获取到了读锁
    子线程25尝试获取读锁
    子线程24尝试获取读锁
    子线程27尝试获取读锁
    线程3获取到了读锁
    子线程28尝试获取读锁
    线程6获取到了读锁
    子线程29尝试获取读锁
    子线程189尝试获取读锁
    子线程30尝试获取读锁
    线程4获取到了写锁
    

      

      

  • 相关阅读:
    在 kylin-v10环境中搭建 electron
    二叉树建树
    python 从txt文件中提取数据保存到 xlxs 文件中
    openpyxl 插件写入数据
    python时间格式转换
    vue-typescript-element-template使用总结
    vue3入门
    typescript入门
    记录下谷歌 浏览器请求数据时遇302,重新连接的问题
    uni使用render.js视图层与逻辑层传数据 的问题
  • 原文地址:https://www.cnblogs.com/cnxieyang/p/12756018.html
Copyright © 2011-2022 走看看